import React, { useState, useRef, useEffect } from 'react'; import { Box, VStack, HStack, Text, IconButton, Slider, SliderTrack, SliderFilledTrack, SliderThumb, Icon, useToast, } from '@chakra-ui/react'; import { FiPlay, FiPause, FiSkipBack, FiSkipForward, FiVolume2, FiVolumeX, } from 'react-icons/fi'; interface MusicFile { _id: string; title?: string; artist?: string; album?: string; duration?: number; originalName: string; } interface MusicPlayerProps { musicFile?: MusicFile; onPlay?: () => void; onPause?: () => void; onEnded?: () => void; } export const MusicPlayer: React.FC = ({ musicFile, onPlay, onPause, onEnded, }) => { 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 [streamingUrl, setStreamingUrl] = useState(null); const [isLoading, setIsLoading] = useState(false); const audioRef = useRef(null); const toast = useToast(); // Format time in MM:SS const formatTime = (seconds: number): string => { if (!seconds || isNaN(seconds)) return '00:00'; const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; // Load streaming URL when music file changes useEffect(() => { if (musicFile) { loadStreamingUrl(); } else { setStreamingUrl(null); setIsPlaying(false); } }, [musicFile]); const loadStreamingUrl = async () => { if (!musicFile) return; setIsLoading(true); try { const response = await fetch(`/api/music/${musicFile._id}/stream`); if (response.ok) { const data = await response.json(); setStreamingUrl(data.streamingUrl); } else { throw new Error('Failed to get streaming URL'); } } catch (error) { console.error('Error loading streaming URL:', error); toast({ title: 'Error', description: 'Failed to load music file', status: 'error', duration: 3000, isClosable: true, }); } finally { setIsLoading(false); } }; // Audio event handlers const handlePlay = () => { if (audioRef.current) { audioRef.current.play(); setIsPlaying(true); onPlay?.(); } }; const handlePause = () => { if (audioRef.current) { audioRef.current.pause(); setIsPlaying(false); onPause?.(); } }; const handleTimeUpdate = () => { if (audioRef.current) { setCurrentTime(audioRef.current.currentTime); } }; const handleLoadedMetadata = () => { if (audioRef.current) { setDuration(audioRef.current.duration); } }; const handleEnded = () => { setIsPlaying(false); setCurrentTime(0); onEnded?.(); }; const handleSeek = (value: number) => { if (audioRef.current) { audioRef.current.currentTime = value; setCurrentTime(value); } }; const handleVolumeChange = (value: number) => { setVolume(value); if (audioRef.current) { audioRef.current.volume = value; } if (value === 0) { setIsMuted(true); } else if (isMuted) { setIsMuted(false); } }; const toggleMute = () => { if (audioRef.current) { if (isMuted) { audioRef.current.volume = volume; setIsMuted(false); } else { audioRef.current.volume = 0; setIsMuted(true); } } }; const skipBackward = () => { if (audioRef.current) { audioRef.current.currentTime = Math.max(0, currentTime - 10); } }; const skipForward = () => { if (audioRef.current) { audioRef.current.currentTime = Math.min(duration, currentTime + 10); } }; if (!musicFile) { return ( No music file selected ); } return ( {/* Audio element */} ); };