fix: fixed audio player erros

This commit is contained in:
2026-01-16 17:11:40 +00:00
parent 5725623e5f
commit 851f186b79
4 changed files with 46 additions and 45 deletions
+46 -45
View File
@@ -1,12 +1,22 @@
'use client';
import { useState, useRef, useEffect } from 'react';
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" }) {
function PlayIcon({ className = "w-6 h-6" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<polygon points="5 3 19 12 5 21 5 3" />
@@ -14,7 +24,7 @@ function PlayIcon({ className = "w-6 h-6" }) {
);
}
function PauseIcon({ className = "w-6 h-6" }) {
function PauseIcon({ className = "w-6 h-6" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<rect x="6" y="4" width="4" height="16" />
@@ -23,7 +33,7 @@ function PauseIcon({ className = "w-6 h-6" }) {
);
}
function SkipNextIcon({ className = "w-6 h-6" }) {
function SkipNextIcon({ className = "w-6 h-6" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<polygon points="5 4 15 12 5 20 5 4" fill="currentColor" />
@@ -32,7 +42,7 @@ function SkipNextIcon({ className = "w-6 h-6" }) {
);
}
function SkipPrevIcon({ className = "w-6 h-6" }) {
function SkipPrevIcon({ className = "w-6 h-6" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<polygon points="19 20 9 12 19 4 19 20" fill="currentColor" />
@@ -41,7 +51,7 @@ function SkipPrevIcon({ className = "w-6 h-6" }) {
);
}
function VideoIcon({ className = "w-5 h-5" }) {
function VideoIcon({ className = "w-5 h-5" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
<rect x="2" y="7" width="20" height="15" strokeLinecap="square" />
@@ -50,7 +60,7 @@ function VideoIcon({ className = "w-5 h-5" }) {
);
}
function MusicIcon({ className = "w-5 h-5" }) {
function MusicIcon({ className = "w-5 h-5" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
<path d="M9 18V5l12-2v13" strokeLinecap="square" />
@@ -60,7 +70,7 @@ function MusicIcon({ className = "w-5 h-5" }) {
);
}
function RefreshIcon({ className = "w-5 h-5" }) {
function RefreshIcon({ className = "w-5 h-5" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<polyline points="23 4 23 10 17 10" strokeLinecap="square" />
@@ -71,15 +81,15 @@ function RefreshIcon({ className = "w-5 h-5" }) {
}
export default function MusicPage() {
const [tracks, setTracks] = useState([]);
const [tracks, setTracks] = useState<Track[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [error, setError] = useState<string | null>(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);
const mediaRef = useRef<HTMLMediaElement | null>(null);
// Fetch available tracks from the server
const fetchTracks = async () => {
@@ -92,15 +102,10 @@ export default function MusicPage() {
}
const data = await response.json();
setTracks(data.tracks || []);
} catch (err) {
} catch (err: unknown) {
console.error('Error fetching tracks:', err);
setError(err.message);
// Fallback to hardcoded tracks if API fails
setTracks([
{ title: "Alone Again", fileName: "AloneAgain.mp4", artist: "Unknown Artist", theme: "general" },
{ title: "House Music VOL1", fileName: "deephousetherapy.mp4", artist: "Deep House Therapy", theme: "house" },
{ title: "House Music VOL2", fileName: "videoplayback.mp4", artist: "Various Artists", theme: "house" },
]);
setError(err instanceof Error ? err.message : 'Unknown error');
setTracks([]);
} finally {
setLoading(false);
}
@@ -111,8 +116,8 @@ export default function MusicPage() {
}, []);
// Group tracks by theme
const tracksByTheme = tracks.reduce((acc, track) => {
const theme = track.theme || 'general';
const tracksByTheme = tracks.reduce<Record<string, Track[]>>((acc, track) => {
const theme = track?.theme || 'general';
if (!acc[theme]) {
acc[theme] = [];
}
@@ -121,10 +126,10 @@ export default function MusicPage() {
}, {});
const themes = Object.keys(tracksByTheme).sort();
// Get filtered tracks based on selected theme
const filteredTracks = selectedTheme === 'all'
? tracks
const filteredTracks = selectedTheme === 'all'
? tracks
: tracksByTheme[selectedTheme] || [];
const currentTrack = filteredTracks[currentTrackIndex];
@@ -140,7 +145,7 @@ export default function MusicPage() {
});
}
}
}, [currentTrackIndex, currentTrack]);
}, [currentTrackIndex, currentTrack]); // Removed isPlaying from deps to prevent loop
const togglePlayPause = () => {
if (mediaRef.current) {
@@ -176,7 +181,7 @@ export default function MusicPage() {
}
};
const handleSeek = (e) => {
const handleSeek = (e: MouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left;
const percentage = x / rect.width;
@@ -185,14 +190,14 @@ export default function MusicPage() {
}
};
const formatTime = (time) => {
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) => {
const handleThemeChange = (theme: string) => {
setSelectedTheme(theme);
setCurrentTrackIndex(0);
setIsPlaying(false);
@@ -293,11 +298,10 @@ export default function MusicPage() {
<span className="text-xs text-white/40 tracking-wider">FILTER:</span>
<button
onClick={() => handleThemeChange('all')}
className={`px-4 py-2 border text-xs tracking-wider transition-all ${
selectedTheme === '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})
</button>
@@ -305,11 +309,10 @@ export default function MusicPage() {
<button
key={theme}
onClick={() => handleThemeChange(theme)}
className={`px-4 py-2 border text-xs tracking-wider transition-all ${
selectedTheme === 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})
</button>
@@ -334,7 +337,7 @@ export default function MusicPage() {
<div className="border border-white/10 bg-black overflow-hidden">
{isVideo ? (
<video
ref={mediaRef}
ref={mediaRef as any}
onTimeUpdate={handleTimeUpdate}
onEnded={nextTrack}
onPlay={() => setIsPlaying(true)}
@@ -375,7 +378,7 @@ export default function MusicPage() {
{/* Audio element (hidden) */}
<audio
ref={mediaRef}
ref={mediaRef as any}
onTimeUpdate={handleTimeUpdate}
onEnded={nextTrack}
onPlay={() => setIsPlaying(true)}
@@ -484,9 +487,8 @@ export default function MusicPage() {
setCurrentTrackIndex(index);
setIsPlaying(true);
}}
className={`w-full p-4 text-left transition-all hover:bg-white/5 ${
currentTrackIndex === index ? 'bg-white/10' : ''
}`}
className={`w-full p-4 text-left transition-all hover:bg-white/5 ${currentTrackIndex === index ? 'bg-white/10' : ''
}`}
>
<div className="flex items-start justify-between mb-2">
<div className="flex-1 min-w-0">
@@ -496,9 +498,8 @@ export default function MusicPage() {
) : (
<MusicIcon className="w-4 h-4 text-white/40 flex-shrink-0" />
)}
<span className={`text-sm font-semibold truncate ${
currentTrackIndex === index ? 'text-white' : 'text-white/80'
}`}>
<span className={`text-sm font-semibold truncate ${currentTrackIndex === index ? 'text-white' : 'text-white/80'
}`}>
{track.title}
</span>
</div>
@@ -561,16 +562,16 @@ export default function MusicPage() {
{/* Animations */}
<style jsx global>{`
@keyframes pulse {
0%, 100% {
0%, 100% {
transform: translate(-50%, -50%) scale(0.95);
opacity: 0.3;
}
50% {
50% {
transform: translate(-50%, -50%) scale(1.05);
opacity: 0.6;
}
}
@keyframes wave {
0%, 100% { height: 4px; }
50% { height: 16px; }