mirror of
https://github.com/linsa-io/linsa.git
synced 2026-01-12 12:20:23 +01:00
Update production setup docs with new Spotify secret; enhance video components for fullscreen handling; add Spotify now-playing API module.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useEffect, useRef } from "react"
|
||||
import { Stream } from "@cloudflare/stream-react"
|
||||
|
||||
type CloudflareStreamPlayerProps = {
|
||||
@@ -15,23 +16,68 @@ export function CloudflareStreamPlayer({
|
||||
muted = false,
|
||||
onReady,
|
||||
}: CloudflareStreamPlayerProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const handleReady = () => {
|
||||
onReady?.()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current
|
||||
if (!container) return
|
||||
|
||||
const ensureFullscreenAllow = () => {
|
||||
const iframe = container.querySelector("iframe")
|
||||
if (!iframe) return false
|
||||
|
||||
const allow = iframe.getAttribute("allow") ?? ""
|
||||
const parts = allow
|
||||
.split(";")
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean)
|
||||
if (!parts.includes("fullscreen")) {
|
||||
parts.push("fullscreen")
|
||||
iframe.setAttribute("allow", parts.join("; "))
|
||||
}
|
||||
if (!iframe.hasAttribute("allowfullscreen")) {
|
||||
iframe.setAttribute("allowfullscreen", "")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (ensureFullscreenAllow()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof MutationObserver === "undefined") {
|
||||
return
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
if (ensureFullscreenAllow()) {
|
||||
observer.disconnect()
|
||||
}
|
||||
})
|
||||
observer.observe(container, { childList: true, subtree: true })
|
||||
|
||||
return () => observer.disconnect()
|
||||
}, [uid, customerCode])
|
||||
|
||||
return (
|
||||
<Stream
|
||||
className="h-full w-full"
|
||||
src={uid}
|
||||
customerCode={customerCode}
|
||||
controls
|
||||
autoplay={autoPlay}
|
||||
muted={muted}
|
||||
responsive={false}
|
||||
height="100%"
|
||||
width="100%"
|
||||
onCanPlay={handleReady}
|
||||
onPlaying={handleReady}
|
||||
/>
|
||||
<div ref={containerRef} className="h-full w-full">
|
||||
<Stream
|
||||
className="h-full w-full"
|
||||
src={uid}
|
||||
customerCode={customerCode}
|
||||
controls
|
||||
autoplay={autoPlay}
|
||||
muted={muted}
|
||||
responsive={false}
|
||||
height="100%"
|
||||
width="100%"
|
||||
onCanPlay={handleReady}
|
||||
onPlaying={handleReady}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export function VideoPlayer({
|
||||
autoPlay = true,
|
||||
muted = false,
|
||||
}: VideoPlayerProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
const hlsRef = useRef<Hls | null>(null)
|
||||
const [isPlaying, setIsPlaying] = useState(autoPlay)
|
||||
@@ -150,7 +151,8 @@ export function VideoPlayer({
|
||||
|
||||
const handleFullscreen = async () => {
|
||||
const video = videoRef.current
|
||||
if (!video) return
|
||||
const container = containerRef.current
|
||||
if (!video || !container) return
|
||||
|
||||
const doc = document as Document & {
|
||||
webkitFullscreenElement?: Element | null
|
||||
@@ -162,6 +164,9 @@ export function VideoPlayer({
|
||||
webkitRequestFullscreen?: () => Promise<void> | void
|
||||
webkitDisplayingFullscreen?: boolean
|
||||
}
|
||||
const containerEl = container as HTMLElement & {
|
||||
webkitRequestFullscreen?: () => Promise<void> | void
|
||||
}
|
||||
|
||||
const isDocFullscreen = !!doc.fullscreenElement || !!doc.webkitFullscreenElement
|
||||
const isVideoFullscreen = !!videoEl.webkitDisplayingFullscreen
|
||||
@@ -184,15 +189,40 @@ export function VideoPlayer({
|
||||
return
|
||||
}
|
||||
|
||||
if (video.requestFullscreen) {
|
||||
await video.requestFullscreen()
|
||||
setIsFullscreen(true)
|
||||
} else if (videoEl.webkitRequestFullscreen) {
|
||||
await videoEl.webkitRequestFullscreen()
|
||||
setIsFullscreen(true)
|
||||
} else if (videoEl.webkitEnterFullscreen) {
|
||||
videoEl.webkitEnterFullscreen()
|
||||
setIsFullscreen(true)
|
||||
const requestContainerFullscreen = async () => {
|
||||
if (containerEl.requestFullscreen) {
|
||||
await containerEl.requestFullscreen()
|
||||
return true
|
||||
}
|
||||
if (containerEl.webkitRequestFullscreen) {
|
||||
await containerEl.webkitRequestFullscreen()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
if (await requestContainerFullscreen()) {
|
||||
setIsFullscreen(true)
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
// Fall through to video fullscreen methods.
|
||||
}
|
||||
|
||||
try {
|
||||
if (video.requestFullscreen) {
|
||||
await video.requestFullscreen()
|
||||
setIsFullscreen(true)
|
||||
} else if (videoEl.webkitRequestFullscreen) {
|
||||
await videoEl.webkitRequestFullscreen()
|
||||
setIsFullscreen(true)
|
||||
} else if (videoEl.webkitEnterFullscreen) {
|
||||
videoEl.webkitEnterFullscreen()
|
||||
setIsFullscreen(true)
|
||||
}
|
||||
} catch {
|
||||
// Ignore fullscreen errors to avoid breaking playback.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +246,7 @@ export function VideoPlayer({
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="group relative h-full w-full bg-black"
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={() => isPlaying && setShowControls(false)}
|
||||
|
||||
Reference in New Issue
Block a user