@@ -36,7 +36,6 @@ export const YouTubePlayer = () => {
3636 }
3737 } , [ currentSongIndex , songs ] ) ;
3838
39- // Poll for YouTube audio signed URL
4039 useEffect ( ( ) => {
4140 if ( ! currentSong || ! currentSong . youtube_id ) {
4241 setMediaUrl ( null ) ;
@@ -51,7 +50,6 @@ export const YouTubePlayer = () => {
5150 const poll = async ( ) => {
5251 try {
5352 const result = await getYouTubeAudioSignedUrl ( currentSong . youtube_id ! ) ;
54- // If cancelled or song changed, abort
5553 if ( cancelled || lastPolledIdRef . current !== currentSong . youtube_id )
5654 return ;
5755 if ( result && result . url ) {
@@ -60,14 +58,12 @@ export const YouTubePlayer = () => {
6058 } else {
6159 setIsLoading ( true ) ;
6260 setMediaUrl ( null ) ;
63- // Re-poll after yet
6461 pollTimeoutRef . current = setTimeout ( poll , 2000 ) ;
6562 }
6663 } catch ( e : unknown ) {
6764 console . error ( "Failed to get YouTube audio signed URL:" , e ) ;
6865 setIsLoading ( true ) ;
6966 setMediaUrl ( null ) ;
70- // Re-poll after current = setTimeout(poll, 2000);
7167 }
7268 } ;
7369 poll ( ) ;
@@ -94,12 +90,10 @@ export const YouTubePlayer = () => {
9490 setIsPlaying ( false ) ;
9591 setIsLoading ( true ) ;
9692 } else if ( ! mediaUrl ) {
97- // No media URL yet, waiting for polling
9893 setIsLoading ( true ) ;
9994 }
10095 } , [ mediaUrl , currentSong ] ) ;
10196
102- // Audio event listeners effect
10397 useEffect ( ( ) => {
10498 const audio = audioRef . current ;
10599 if ( ! audio ) return ;
@@ -119,7 +113,6 @@ export const YouTubePlayer = () => {
119113 setIsPlaying ( true ) ;
120114 setIsLoading ( false ) ;
121115
122- // Update status to "playing" when song starts
123116 if ( currentSong ?. id ) {
124117 try {
125118 await updateBoxSong ( currentSong . id , {
@@ -139,7 +132,6 @@ export const YouTubePlayer = () => {
139132 const handleEnded = async ( ) => {
140133 setIsPlaying ( false ) ;
141134
142- // Mark current song as "played" when it ends
143135 if ( currentSong ?. id ) {
144136 try {
145137 await updateBoxSong ( currentSong . id , {
@@ -151,7 +143,6 @@ export const YouTubePlayer = () => {
151143 }
152144 }
153145
154- // Auto-advance to next song if available
155146 if ( currentSongIndex < songs . length - 1 ) {
156147 goToNext ( ) ;
157148 setCurrentTime ( 0 ) ;
@@ -178,7 +169,6 @@ export const YouTubePlayer = () => {
178169 console . error ( "Audio playback error" ) ;
179170 } ;
180171
181- // Add event listeners
182172 audio . addEventListener ( "timeupdate" , handleTimeUpdate ) ;
183173 audio . addEventListener ( "loadedmetadata" , handleLoadedMetadata ) ;
184174 audio . addEventListener ( "play" , handlePlay ) ;
@@ -188,7 +178,6 @@ export const YouTubePlayer = () => {
188178 audio . addEventListener ( "canplay" , handleCanPlay ) ;
189179 audio . addEventListener ( "error" , handleError ) ;
190180
191- // Cleanup function
192181 return ( ) => {
193182 audio . removeEventListener ( "timeupdate" , handleTimeUpdate ) ;
194183 audio . removeEventListener ( "loadedmetadata" , handleLoadedMetadata ) ;
@@ -215,40 +204,28 @@ export const YouTubePlayer = () => {
215204 setIsPlaying ( true ) ;
216205 } catch ( error ) {
217206 console . error ( "Playback failed:" , error ) ;
218- // The error will be handled by the audio error event listener
219207 }
220208 }
221209 } , [ isPlaying ] ) ;
222210
223- const handlePrevious = async ( ) => {
224- goToPrevious ( ) ;
225- } ;
226-
227- const handleNext = async ( ) => {
228- goToNext ( ) ;
229- } ;
230-
231211 const handleSeek = ( e : React . MouseEvent < HTMLDivElement > ) => {
232212 const audio = audioRef . current ;
233213 if ( ! audio || duration === 0 || isLoading ) return ;
234214
235- // Prevent seeking if audio is not ready
236- if ( audio . readyState < 2 ) return ; // HAVE_CURRENT_DATA or higher
215+ if ( audio . readyState < 2 ) return ;
237216
238217 const rect = e . currentTarget . getBoundingClientRect ( ) ;
239218 const clickX = e . clientX - rect . left ;
240- const percentage = Math . max ( 0 , Math . min ( 1 , clickX / rect . width ) ) ; // Clamp between 0 and 1
219+ const percentage = Math . max ( 0 , Math . min ( 1 , clickX / rect . width ) ) ;
241220 const newTime = percentage * duration ;
242221
243- // Ensure the new time is within valid bounds
244222 const clampedTime = Math . max ( 0 , Math . min ( duration , newTime ) ) ;
245223
246- // Clear any existing seek timeout
247224 if ( seekTimeoutRef . current ) {
248225 clearTimeout ( seekTimeoutRef . current ) ;
249226 }
250227
251- setCurrentTime ( clampedTime ) ; // Update UI immediately
228+ setCurrentTime ( clampedTime ) ;
252229
253230 try {
254231 audio . currentTime = clampedTime ;
@@ -283,27 +260,55 @@ export const YouTubePlayer = () => {
283260 return `${ mins } :${ secs . toString ( ) . padStart ( 2 , "0" ) } ` ;
284261 } ;
285262
286- // Space bar play/pause control
287263 useEffect ( ( ) => {
288264 const handleKeyDown = ( e : KeyboardEvent ) => {
289- // Only trigger if space bar is pressed and not inside an input/textarea
290265 if (
291- e . code === "Space" &&
292- ! ( e . target instanceof HTMLInputElement ) &&
293- ! ( e . target instanceof HTMLTextAreaElement ) &&
294- ! e . repeat &&
295- currentSong &&
296- ! isLoading
266+ e . target instanceof HTMLInputElement ||
267+ e . target instanceof HTMLTextAreaElement
297268 ) {
269+ return ;
270+ }
271+
272+ if ( e . code === "Space" && ! e . repeat && currentSong && ! isLoading ) {
298273 e . preventDefault ( ) ;
299274 handlePlayPause ( ) ;
275+ return ;
276+ }
277+
278+ if (
279+ ( e . metaKey || e . ctrlKey ) &&
280+ e . code === "ArrowLeft" &&
281+ ! e . repeat &&
282+ currentSong
283+ ) {
284+ e . preventDefault ( ) ;
285+ goToPrevious ( ) ;
286+ return ;
287+ }
288+
289+ if (
290+ ( e . metaKey || e . ctrlKey ) &&
291+ e . code === "ArrowRight" &&
292+ ! e . repeat &&
293+ currentSong
294+ ) {
295+ e . preventDefault ( ) ;
296+ goToNext ( ) ;
297+ return ;
300298 }
301299 } ;
302300 window . addEventListener ( "keydown" , handleKeyDown ) ;
303301 return ( ) => {
304302 window . removeEventListener ( "keydown" , handleKeyDown ) ;
305303 } ;
306- } , [ currentSong , isLoading , isPlaying , handlePlayPause ] ) ;
304+ } , [
305+ currentSong ,
306+ isLoading ,
307+ isPlaying ,
308+ handlePlayPause ,
309+ goToPrevious ,
310+ goToNext ,
311+ ] ) ;
307312
308313 return (
309314 < motion . div
@@ -404,7 +409,7 @@ export const YouTubePlayer = () => {
404409 < Button
405410 variant = "neutral"
406411 size = "sm"
407- onClick = { handlePrevious }
412+ onClick = { goToPrevious }
408413 disabled = { currentSongIndex === 0 }
409414 >
410415 < SkipBack className = "h-4 w-4" />
@@ -425,7 +430,7 @@ export const YouTubePlayer = () => {
425430 < Button
426431 variant = "neutral"
427432 size = "sm"
428- onClick = { handleNext }
433+ onClick = { goToNext }
429434 disabled = { currentSongIndex === songs . length - 1 }
430435 >
431436 < SkipForward className = "h-4 w-4" />
0 commit comments