This commit is contained in:
Mistral Vibe
2026-04-08 20:07:20 +02:00
parent 9c4c3cda34
commit 1629272adb
3 changed files with 334 additions and 66 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react";
import { audioService } from "../services/audioService";
import { audioService, InitializationState } from "../services/audioService";
import { usePlayerStore } from "../stores/playerStore";
export interface UseWaveformOptions {
@@ -27,6 +27,7 @@ export function useWaveform(
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const [error, setError] = useState<string | null>(null);
const [initializationState, setInitializationState] = useState<InitializationState>(InitializationState.NotStarted);
const markersRef = useRef<CommentMarker[]>([]);
// Global player state - use shallow comparison to reduce re-renders
@@ -103,26 +104,30 @@ export function useWaveform(
// Wait for the waveform to be ready and audio context to be available
const checkReady = setInterval(() => {
if (audioService.getDuration() > 0) {
clearInterval(checkReady);
// Only attempt to play if we have a valid audio context
// This prevents autoplay policy violations
try {
audioService.play(options.songId, options.bandId);
if (globalCurrentTime > 0) {
audioService.seekTo(globalCurrentTime);
}
} catch (error) {
console.warn('Auto-play prevented by browser policy, waiting for user gesture:', error);
// Don't retry - wait for user to click play
// Wait for initialization to complete using the new promise-based approach
try {
await audioService.waitForInitialization();
// Use the unified readiness check
if (audioService.isReadyForPlayback()) {
audioService.play(options.songId, options.bandId);
if (globalCurrentTime > 0) {
audioService.seekTo(globalCurrentTime);
}
} else {
console.warn('Not ready for playback after initialization', {
state: audioService.getInitializationState(),
error: audioService.getInitializationError()
});
}
}, 50);
} catch (error) {
console.warn('Auto-play prevented during initialization:', error);
// Don't retry - wait for user to click play
}
}
setIsReady(true);
setInitializationState(audioService.getInitializationState());
options.onReady?.(audioService.getDuration());
return () => {
@@ -145,16 +150,17 @@ export function useWaveform(
}, [options.url, options.songId, options.bandId, containerRef, currentSongId, globalBandId, globalCurrentTime, globalIsPlaying, setCurrentSong]);
const play = () => {
// Only attempt to play if waveform is ready
if (audioService.isWaveformReady()) {
// Use the unified readiness check
if (audioService.isReadyForPlayback()) {
try {
audioService.play(options.songId || null, options.bandId || null);
} catch (error) {
console.error('useWaveform.play failed:', error);
}
} else {
console.warn('Cannot play: waveform not ready', {
hasWavesurfer: !!audioService.isPlaying(),
console.warn('Cannot play: not ready for playback', {
initializationState: audioService.getInitializationState(),
error: audioService.getInitializationError(),
duration: audioService.getDuration(),
url: options.url
});
@@ -235,7 +241,19 @@ export function useWaveform(
markersRef.current = [];
};
return { isPlaying, isReady, currentTime, duration, play, pause, seekTo, addMarker, clearMarkers, error };
return {
isPlaying,
isReady,
currentTime,
duration,
play,
pause,
seekTo,
addMarker,
clearMarkers,
error,
initializationState
};
}
function formatTime(seconds: number): string {