'use client'; import { useState, useRef, useEffect, MouseEvent } from 'react'; // Configuration const BASE_URL = "https://openwheels.racing/files/music/"; // Types interface Track { title: string; artist: string; fileName: string; theme?: string; } type IconProps = { className?: string }; // Icons function PlayIcon({ className = "w-6 h-6" }: IconProps) { return ( ); } function PauseIcon({ className = "w-6 h-6" }: IconProps) { return ( ); } function SkipNextIcon({ className = "w-6 h-6" }: IconProps) { return ( ); } function SkipPrevIcon({ className = "w-6 h-6" }: IconProps) { return ( ); } function VideoIcon({ className = "w-5 h-5" }: IconProps) { return ( ); } function MusicIcon({ className = "w-5 h-5" }: IconProps) { return ( ); } function RefreshIcon({ className = "w-5 h-5" }: IconProps) { return ( ); } export default function MusicPage() { const [tracks, setTracks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [currentTrackIndex, setCurrentTrackIndex] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [selectedTheme, setSelectedTheme] = useState('all'); const mediaRef = useRef(null); // Fetch available tracks from the server const fetchTracks = async () => { setLoading(true); setError(null); try { const response = await fetch('/api/music/tracks'); if (!response.ok) { throw new Error('Failed to fetch tracks'); } const data = await response.json(); setTracks(data.tracks || []); } catch (err: unknown) { console.error('Error fetching tracks:', err); setError(err instanceof Error ? err.message : 'Unknown error'); setTracks([]); } finally { setLoading(false); } }; useEffect(() => { fetchTracks(); }, []); // Group tracks by theme const tracksByTheme = tracks.reduce>((acc, track) => { const theme = track?.theme || 'general'; if (!acc[theme]) { acc[theme] = []; } acc[theme].push(track); return acc; }, {}); const themes = Object.keys(tracksByTheme).sort(); // Get filtered tracks based on selected theme const filteredTracks = selectedTheme === 'all' ? tracks : tracksByTheme[selectedTheme] || []; const currentTrack = filteredTracks[currentTrackIndex]; const isVideo = currentTrack?.fileName.toLowerCase().endsWith('.mp4'); useEffect(() => { if (mediaRef.current && currentTrack) { mediaRef.current.load(); if (isPlaying) { mediaRef.current.play().catch(err => { console.error('Playback error:', err); setIsPlaying(false); }); } } }, [currentTrackIndex, currentTrack]); // Removed isPlaying from deps to prevent loop const togglePlayPause = () => { if (mediaRef.current) { if (isPlaying) { mediaRef.current.pause(); } else { mediaRef.current.play().catch(err => { console.error('Playback error:', err); }); } setIsPlaying(!isPlaying); } }; const nextTrack = () => { if (filteredTracks.length > 0) { setCurrentTrackIndex((prev) => (prev + 1) % filteredTracks.length); setIsPlaying(true); } }; const prevTrack = () => { if (filteredTracks.length > 0) { setCurrentTrackIndex((prev) => (prev - 1 + filteredTracks.length) % filteredTracks.length); setIsPlaying(true); } }; const handleTimeUpdate = () => { if (mediaRef.current) { setCurrentTime(mediaRef.current.currentTime); setDuration(mediaRef.current.duration || 0); } }; const handleSeek = (e: MouseEvent) => { const rect = e.currentTarget.getBoundingClientRect(); const x = e.clientX - rect.left; const percentage = x / rect.width; if (mediaRef.current) { mediaRef.current.currentTime = percentage * duration; } }; const formatTime = (time: number) => { if (isNaN(time)) return "0:00"; const minutes = Math.floor(time / 60); const seconds = Math.floor(time % 60); return `${minutes}:${seconds.toString().padStart(2, '0')}`; }; const handleThemeChange = (theme: string) => { setSelectedTheme(theme); setCurrentTrackIndex(0); setIsPlaying(false); }; if (loading) { return ( MUSIC STREAM AUDIO SYSTEM High-fidelity streaming for the racing community LOADING TRACKS... ); } if (!currentTrack) { return ( MUSIC STREAM AUDIO SYSTEM High-fidelity streaming for the racing community NO TRACKS AVAILABLE {error && Error: {error}} RETRY ); } return ( {/* Animated Background */} MUSIC STREAM AUDIO SYSTEM High-fidelity streaming for the racing community {/* Theme Filter */} FILTER: handleThemeChange('all')} className={`px-4 py-2 border text-xs tracking-wider transition-all ${selectedTheme === 'all' ? 'border-white bg-white text-black' : 'border-white/20 hover:border-white/40' }`} > ALL ({tracks.length}) {themes.map(theme => ( handleThemeChange(theme)} className={`px-4 py-2 border text-xs tracking-wider transition-all ${selectedTheme === theme ? 'border-white bg-white text-black' : 'border-white/20 hover:border-white/40' }`} > {theme.toUpperCase()} ({tracksByTheme[theme].length}) ))} REFRESH {/* Main Player Container */} {/* Left Column - Now Playing */} {/* Video/Audio Display */} {isVideo ? ( setIsPlaying(true)} onPause={() => setIsPlaying(false)} className="w-full aspect-video" preload="metadata" > ) : ( {/* Audio Visualizer */} {/* Pulsing circles */} {[...Array(3)].map((_, i) => ( ))} {/* Center icon */} {/* Audio element (hidden) */} setIsPlaying(true)} onPause={() => setIsPlaying(false)} preload="metadata" > )} {/* Track Info & Controls */} {/* Track Info */} {currentTrack.title} {currentTrack.artist} {isVideo ? : } {isVideo ? 'VIDEO' : 'AUDIO'} {currentTrack.theme?.toUpperCase() || 'GENERAL'} {/* Progress Bar */} {formatTime(currentTime)} {formatTime(duration)} {/* Controls */} {isPlaying ? : } {/* Right Column - Playlist */} PLAYLIST {selectedTheme !== 'all' && ` - ${selectedTheme.toUpperCase()}`} {filteredTracks.length === 0 ? ( No tracks in this category ) : ( filteredTracks.map((track, index) => ( { setCurrentTrackIndex(index); setIsPlaying(true); }} className={`w-full p-4 text-left transition-all hover:bg-white/5 ${currentTrackIndex === index ? 'bg-white/10' : '' }`} > {track.fileName.endsWith('.mp4') ? ( ) : ( )} {track.title} {track.artist} {currentTrackIndex === index && isPlaying && ( {[...Array(3)].map((_, i) => ( ))} )} TRACK {String(index + 1).padStart(2, '0')} )) )} {/* Info Box */} SYSTEM INFO FORMAT MP4 / AUDIO QUALITY HIGH FIDELITY TRACKS {tracks.length} AVAILABLE STREAMING PROGRESSIVE LOAD {/* Animations */} ); }
High-fidelity streaming for the racing community
LOADING TRACKS...
NO TRACKS AVAILABLE
Error: {error}
{currentTrack.artist}
{track.artist}
FORMAT
MP4 / AUDIO
QUALITY
HIGH FIDELITY
TRACKS
{tracks.length} AVAILABLE
STREAMING
PROGRESSIVE LOAD