'use client' import { useState, useRef, useEffect } from 'react' import Image from 'next/image' import { Play, Pause, SkipBack, SkipForward, Volume2, VolumeX, Shuffle } from 'lucide-react' interface Song { id: string youtubeId: string title: string channelName: string thumbnail: string duration: number } interface PlayerBarProps { currentSong: Song | null onNext?: () => void onPrevious?: () => void isPlaylist?: boolean isShuffled?: boolean onToggleShuffle?: () => void nextSong?: Song | null } export default function PlayerBar({ currentSong, onNext, onPrevious, isPlaylist = false, isShuffled = false, onToggleShuffle, nextSong }: PlayerBarProps) { const [isPlaying, setIsPlaying] = useState(false) const [currentTime, setCurrentTime] = useState(0) const [duration, setDuration] = useState(0) const [volume, setVolume] = useState(1) const [isMuted, setIsMuted] = useState(false) const audioRef = useRef(null) useEffect(() => { if (currentSong && audioRef.current) { const audio = audioRef.current // Reset state when changing songs setCurrentTime(0) setDuration(0) setIsPlaying(false) audio.src = `/api/stream/${currentSong.id}` audio.load() // Force reload to ensure metadata is loaded // Try to get duration after a short delay to ensure metadata is loaded const checkDuration = () => { if (audio.duration && !isNaN(audio.duration) && isFinite(audio.duration)) { setDuration(audio.duration) } } // Check duration immediately and after load const loadedHandler = () => { checkDuration() audio.play().then(() => { setIsPlaying(true) }).catch(err => console.error('Error playing:', err)) } audio.addEventListener('loadedmetadata', loadedHandler) // Fallback if loadedmetadata doesn't fire const timeoutId = setTimeout(() => { checkDuration() if (audio.paused) { audio.play().then(() => { setIsPlaying(true) }).catch(err => console.error('Error playing:', err)) } }, 100) return () => { audio.removeEventListener('loadedmetadata', loadedHandler) clearTimeout(timeoutId) } } }, [currentSong]) // Pre-load next song useEffect(() => { if (nextSong) { // Pre-fetch the stream URL to populate cache fetch(`/api/stream/${nextSong.id}`, { method: 'HEAD' }).catch(() => {}) } }, [nextSong]) useEffect(() => { const audio = audioRef.current if (!audio) return const updateTime = () => setCurrentTime(audio.currentTime) const updateDuration = () => { if (audio.duration && !isNaN(audio.duration) && isFinite(audio.duration)) { setDuration(audio.duration) } } const handleEnded = () => { setIsPlaying(false) if (onNext) onNext() } const handleCanPlay = () => { // Also update duration when audio can play updateDuration() } audio.addEventListener('timeupdate', updateTime) audio.addEventListener('loadedmetadata', updateDuration) audio.addEventListener('durationchange', updateDuration) audio.addEventListener('canplay', handleCanPlay) audio.addEventListener('ended', handleEnded) return () => { audio.removeEventListener('timeupdate', updateTime) audio.removeEventListener('loadedmetadata', updateDuration) audio.removeEventListener('durationchange', updateDuration) audio.removeEventListener('canplay', handleCanPlay) audio.removeEventListener('ended', handleEnded) } }, [onNext, currentSong]) const togglePlay = () => { if (audioRef.current) { if (isPlaying) { audioRef.current.pause() } else { audioRef.current.play() } setIsPlaying(!isPlaying) } } const handleSeek = (e: React.ChangeEvent) => { const time = parseFloat(e.target.value) setCurrentTime(time) if (audioRef.current) { audioRef.current.currentTime = time } } const handleVolumeChange = (e: React.ChangeEvent) => { const vol = parseFloat(e.target.value) setVolume(vol) if (audioRef.current) { audioRef.current.volume = vol } if (vol === 0) { setIsMuted(true) } else { setIsMuted(false) } } const toggleMute = () => { if (audioRef.current) { if (isMuted) { audioRef.current.volume = volume setIsMuted(false) } else { audioRef.current.volume = 0 setIsMuted(true) } } } const formatTime = (time: number): string => { if (isNaN(time)) return '0:00' const mins = Math.floor(time / 60) const secs = Math.floor(time % 60) return `${mins}:${secs.toString().padStart(2, '0')}` } if (!currentSong) { return (
Select a song to start playing
) } return ( <>