feat(special-curation): complete implementation with all components

- Database: SpecialSong model with startTime
- Backend: API endpoints for curation
- Admin: Waveform editor and curation page
- Game: startTime support in AudioPlayer
- UI: Curate button in admin dashboard
This commit is contained in:
Hördle Bot
2025-11-23 00:50:35 +01:00
parent 4f088305df
commit 587fa59b79
8 changed files with 564 additions and 23 deletions

View File

@@ -5,11 +5,12 @@ import { useState, useRef, useEffect } from 'react';
interface AudioPlayerProps {
src: string;
unlockedSeconds: number; // 2, 4, 7, 11, 16, 30 (or full length)
startTime?: number; // Start offset in seconds (for curated specials)
onPlay?: () => void;
autoPlay?: boolean;
}
export default function AudioPlayer({ src, unlockedSeconds, onPlay, autoPlay = false }: AudioPlayerProps) {
export default function AudioPlayer({ src, unlockedSeconds, startTime = 0, onPlay, autoPlay = false }: AudioPlayerProps) {
const audioRef = useRef<HTMLAudioElement>(null);
const [isPlaying, setIsPlaying] = useState(false);
const [progress, setProgress] = useState(0);
@@ -17,7 +18,7 @@ export default function AudioPlayer({ src, unlockedSeconds, onPlay, autoPlay = f
useEffect(() => {
if (audioRef.current) {
audioRef.current.pause();
audioRef.current.currentTime = 0;
audioRef.current.currentTime = startTime;
setIsPlaying(false);
setProgress(0);
@@ -36,7 +37,7 @@ export default function AudioPlayer({ src, unlockedSeconds, onPlay, autoPlay = f
}
}
}
}, [src, unlockedSeconds, autoPlay]);
}, [src, unlockedSeconds, startTime, autoPlay]);
const togglePlay = () => {
if (!audioRef.current) return;
@@ -54,12 +55,13 @@ export default function AudioPlayer({ src, unlockedSeconds, onPlay, autoPlay = f
if (!audioRef.current) return;
const current = audioRef.current.currentTime;
const percent = (current / unlockedSeconds) * 100;
const elapsed = current - startTime;
const percent = (elapsed / unlockedSeconds) * 100;
setProgress(Math.min(percent, 100));
if (current >= unlockedSeconds) {
if (elapsed >= unlockedSeconds) {
audioRef.current.pause();
audioRef.current.currentTime = 0;
audioRef.current.currentTime = startTime;
setIsPlaying(false);
setProgress(0);
}