From 797311eebaea8171367cbf91ca28627fb49fff7d Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 24 Dec 2025 19:54:00 -0800 Subject: [PATCH] Improve VideoPlayer event handling and streamline viewer count sync - Add a `callReady` function to ensure `onReady` is called only once - Attach `canplay` event listener for native HLS support to trigger `onReady` - Call `onReady` immediately after manifest parsing for HLS streams - Simplify `useStreamViewers` hook to skip viewer count sync for user "nikiv" - Silently handle errors during viewer count synchronization to avoid unnecessary logs --- packages/web/src/components/VideoPlayer.tsx | 27 ++++++++++--------- packages/web/src/lib/jazz/useStreamViewers.ts | 7 ++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/web/src/components/VideoPlayer.tsx b/packages/web/src/components/VideoPlayer.tsx index ee82780f..6d6279d0 100644 --- a/packages/web/src/components/VideoPlayer.tsx +++ b/packages/web/src/components/VideoPlayer.tsx @@ -38,19 +38,23 @@ export function VideoPlayer({ const video = videoRef.current if (!video || !src) return + let hasCalledReady = false + const callReady = () => { + if (!hasCalledReady) { + hasCalledReady = true + onReady?.() + } + } + // Check if native HLS is supported (Safari) if (video.canPlayType("application/vnd.apple.mpegurl")) { video.src = src + // Call ready when video can play + video.addEventListener("canplay", callReady, { once: true }) if (autoPlay) { video.play() - .then(() => { - setIsPlaying(true) - onReady?.() - }) + .then(() => setIsPlaying(true)) .catch(() => setIsPlaying(false)) - } else { - // Even if not autoplay, notify ready when we can play - video.addEventListener("canplay", () => onReady?.(), { once: true }) } return } @@ -68,15 +72,12 @@ export function VideoPlayer({ hls.attachMedia(video) hls.on(Hls.Events.MANIFEST_PARSED, () => { + // Call ready as soon as manifest is parsed + callReady() if (autoPlay) { video.play() - .then(() => { - setIsPlaying(true) - onReady?.() - }) + .then(() => setIsPlaying(true)) .catch(() => setIsPlaying(false)) - } else { - onReady?.() } }) diff --git a/packages/web/src/lib/jazz/useStreamViewers.ts b/packages/web/src/lib/jazz/useStreamViewers.ts index 439ddec8..864078ac 100644 --- a/packages/web/src/lib/jazz/useStreamViewers.ts +++ b/packages/web/src/lib/jazz/useStreamViewers.ts @@ -140,8 +140,9 @@ export function useStreamViewers(username: string): UseStreamViewersResult { }, [presenceFeed?.$isLoaded, presenceFeed]) // Sync viewer count to database for external access + // Skip for nikiv since it's a hardcoded user without a database entry useEffect(() => { - if (viewerCount === 0) return + if (viewerCount === 0 || username === "nikiv") return // Debounce the API call const timeout = setTimeout(() => { @@ -149,8 +150,8 @@ export function useStreamViewers(username: string): UseStreamViewersResult { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ viewerCount }), - }).catch((err) => { - console.error("Failed to sync viewer count:", err) + }).catch(() => { + // Silently ignore sync errors - not critical }) }, 1000)