From f68989c228994c64131022c4c313c5ebec9dcd78 Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Thu, 16 Apr 2026 16:11:39 +0200 Subject: [PATCH] feat: implement AudioPlayer component with playback controls, progress tracking, and persistence --- frontend/src/components/AudioPlayer.tsx | 41 +++++++++++++++++++------ 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/AudioPlayer.tsx b/frontend/src/components/AudioPlayer.tsx index 5852cc6..947eb39 100644 --- a/frontend/src/components/AudioPlayer.tsx +++ b/frontend/src/components/AudioPlayer.tsx @@ -35,6 +35,21 @@ export default function AudioPlayer({ episode, onClose, userId }: AudioPlayerPro const [isExpanded, setIsExpanded] = useState(false); const [isResuming, setIsResuming] = useState(false); const [error, setError] = useState(null); + + // Refs for stable tracking without re-renders + const currentTimeRef = useRef(0); + const episodeIdRef = useRef(null); + const userIdRef = useRef(null); + + // Sync refs with state + useEffect(() => { + currentTimeRef.current = currentTime; + }, [currentTime]); + + useEffect(() => { + episodeIdRef.current = episode?._id || null; + userIdRef.current = userId || null; + }, [episode, userId]); const podcast = typeof episode?.podcastId === 'object' ? episode.podcastId : null; @@ -52,18 +67,26 @@ export default function AudioPlayer({ episode, onClose, userId }: AudioPlayerPro localStorage.setItem('podcastic-speed', playbackSpeed.toString()); }, [volume, playbackSpeed]); - // Save progress periodically + // Save progress periodically and on unmount useEffect(() => { if (!episode || !userId) return; - const interval = setInterval(async () => { - if (isPlaying) { - try { - await episodeService.saveProgress(episode._id, Math.floor(currentTime), false); - } catch {} + + // Save every 20 seconds only if playing + const interval = setInterval(() => { + if (isPlaying && episodeIdRef.current) { + episodeService.saveProgress(episodeIdRef.current, Math.floor(currentTimeRef.current), false).catch(() => {}); } - }, 30000); - return () => clearInterval(interval); - }, [episode, userId, currentTime, isPlaying]); + }, 20000); + + // Cleanup: SAVE FINAL PROGRESS ON UNMOUNT OR EPISODE CHANGE + return () => { + clearInterval(interval); + if (episodeIdRef.current && userIdRef.current) { + console.log(`[AudioPlayer] Final save for ${episodeIdRef.current} at ${Math.floor(currentTimeRef.current)}s`); + episodeService.saveProgress(episodeIdRef.current, Math.floor(currentTimeRef.current), false).catch(() => {}); + } + }; + }, [episode?._id, userId, isPlaying]); // Restart if episode or isPlaying changes to maintain correct interval behavior // Load previous progress useEffect(() => {