From a1acbd9395e4e06de7b4678e089fa16a85ea91b0 Mon Sep 17 00:00:00 2001 From: dwindown Date: Thu, 1 Jan 2026 01:51:47 +0700 Subject: [PATCH] Fix video player bugs and improve overlay behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed issues: 1. Duration now displays correctly using Plyr's time tracking instead of YouTube API 2. Chapter jump functionality now works using Plyr's currentTime property 3. Overlays now properly avoid Plyr controls - only show when paused/ended 4. Hidden YouTube's native play button with CSS Key changes: - Use Plyr's native time tracking (player.currentTime) instead of YouTube API - Jump to time uses Plyr's seek (player.currentTime = time, then play) - Top overlay only appears when paused/ended (not when playing) - Paused/ended overlays start at bottom: 80px to avoid Plyr controls - Added CSS to hide .ytp-large-play-button and .html5-video-player background - Moved time tracking to onReady callback to ensure player is initialized - Removed dependencies on chapters from useEffect to prevent re-initialization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/components/VideoPlayerWithChapters.tsx | 129 +++++++++++---------- 1 file changed, 67 insertions(+), 62 deletions(-) diff --git a/src/components/VideoPlayerWithChapters.tsx b/src/components/VideoPlayerWithChapters.tsx index 0a85ccc..a2034d5 100644 --- a/src/components/VideoPlayerWithChapters.tsx +++ b/src/components/VideoPlayerWithChapters.tsx @@ -113,6 +113,7 @@ export const VideoPlayerWithChapters = forwardRef { + // Set up time tracking for chapters using Plyr's time + intervalRef.current = setInterval(() => { + if (playerRef.current) { + const currentTime = playerRef.current.currentTime; + if (onTimeUpdate && currentTime > 0) { + onTimeUpdate(currentTime); + } + + // Find current chapter + if (chapters.length > 0) { + let index = chapters.findIndex((chapter, i) => { + const nextChapter = chapters[i + 1]; + return currentTime >= chapter.time && (!nextChapter || currentTime < nextChapter.time); + }); + + // If before first chapter, no active chapter + if (index === -1 && currentTime < chapters[0].time) { + index = -1; + } + + if (index !== currentChapterIndex) { + setCurrentChapterIndex(index); + if (index >= 0 && onChapterChange) { + onChapterChange(chapters[index]); + } + } + } + } + }, 500); + }, onStateChange: (event: any) => { const state = event.data; setYtPlayerState(state); @@ -160,36 +192,6 @@ export const VideoPlayerWithChapters = forwardRef { - if (ytPlayer && ytPlayer.getCurrentTime) { - const currentTime = ytPlayer.getCurrentTime(); - if (onTimeUpdate) { - onTimeUpdate(currentTime); - } - - // Find current chapter - if (chapters.length > 0) { - let index = chapters.findIndex((chapter, i) => { - const nextChapter = chapters[i + 1]; - return currentTime >= chapter.time && (!nextChapter || currentTime < nextChapter.time); - }); - - // If before first chapter, no active chapter - if (index === -1 && currentTime < chapters[0].time) { - index = -1; - } - - if (index !== currentChapterIndex) { - setCurrentChapterIndex(index); - if (index >= 0 && onChapterChange) { - onChapterChange(chapters[index]); - } - } - } - } - }, 500); }; // Initialize YouTube player when API is ready @@ -213,6 +215,13 @@ export const VideoPlayerWithChapters = forwardRef { @@ -240,19 +249,13 @@ export const VideoPlayerWithChapters = forwardRef { - if (ytPlayerRef.current) { - ytPlayerRef.current.seekTo(time, true); - ytPlayerRef.current.playVideo(); - } else if (playerRef.current) { + if (playerRef.current) { playerRef.current.currentTime = time; playerRef.current.play(); } }; const getCurrentTime = () => { - if (ytPlayerRef.current) { - return ytPlayerRef.current.getCurrentTime() || 0; - } return playerRef.current ? playerRef.current.currentTime : 0; }; @@ -288,22 +291,24 @@ export const VideoPlayerWithChapters = forwardRef + {/* 1. Block "Copy Link" and Title on top (only when paused or not started) */} + {(ytPlayerState === -1 || ytPlayerState === 5 || ytPlayerState === 2 || ytPlayerState === 0) && ( +
+ )} {/* 2. Block "YouTube" logo - Bottom right (always on) */}
- {/* 3. Block "Watch on YouTube" - Bottom left (before video starts) */} - {(ytPlayerState === -1 || ytPlayerState === 5) && ( + {/* 3. Block "Watch on YouTube" - Bottom left (before video starts or paused) */} + {(ytPlayerState === -1 || ytPlayerState === 5 || ytPlayerState === 2) && (
)} - {/* 4. Block "More Videos" overlay - When paused */} + {/* 4. Block "More Videos" overlay - When paused (below the controls area) */} {ytPlayerState === 2 && (
)} - {/* 5. Block related videos overlay - When video ends */} + {/* 5. Block related videos overlay - When video ends (below the controls area) */} {ytPlayerState === 0 && (