import { useCallback, useMemo } from "react"; import usePlayer from "./usePlayer"; const useTrackController = (descriptor) => { const { currentTrack, play, pause, resume, isPlaying, positionMs, durationMs, seekTo, seekBy, } = usePlayer(); const normalizedDescriptor = useMemo(() => { if (!descriptor || !descriptor.id) return null; return descriptor; }, [descriptor]); const trackId = normalizedDescriptor?.id || null; const isCurrent = trackId ? currentTrack?.id === trackId : false; const effectivePositionMs = isCurrent ? positionMs : 0; const effectiveDurationMs = isCurrent ? durationMs : 0; const effectiveIsPlaying = isCurrent && isPlaying; const ensureLoaded = useCallback( async ({ startPositionMs = 0, autoPlay = true } = {}) => { if (!normalizedDescriptor) return; await play(normalizedDescriptor, { startPositionMs, autoPlay, context: normalizedDescriptor.context, }); }, [normalizedDescriptor, play] ); const playNow = useCallback( async ({ startPositionMs = 0 } = {}) => { await ensureLoaded({ startPositionMs, autoPlay: true }); }, [ensureLoaded] ); const pauseNow = useCallback(async () => { if (isCurrent) { await pause(); } }, [isCurrent, pause]); const resumeNow = useCallback( async ({ startPositionMs } = {}) => { if (!normalizedDescriptor) return; if (!isCurrent) { await ensureLoaded({ startPositionMs: startPositionMs ?? effectivePositionMs, autoPlay: true, }); return; } if (typeof startPositionMs === "number") { await seekTo(Math.max(0, startPositionMs)); } await resume(); }, [ normalizedDescriptor, isCurrent, ensureLoaded, effectivePositionMs, seekTo, resume, ] ); const seekToPosition = useCallback( async (targetMs, { autoPlay = false } = {}) => { const bounded = Math.max(0, Number(targetMs) || 0); if (!normalizedDescriptor) return; if (!isCurrent) { await ensureLoaded({ startPositionMs: bounded, autoPlay }); return; } await seekTo(bounded); if (autoPlay && !effectiveIsPlaying) { await resume(); } }, [ normalizedDescriptor, isCurrent, ensureLoaded, seekTo, effectiveIsPlaying, resume, ] ); const seekByDelta = useCallback( async (deltaMs, { autoPlay = false } = {}) => { const delta = Number(deltaMs || 0); if (!normalizedDescriptor) return; if (!isCurrent) { const next = Math.max(0, effectivePositionMs + delta); await ensureLoaded({ startPositionMs: next, autoPlay }); return; } await seekBy(delta); if (autoPlay && !effectiveIsPlaying) { await resume(); } }, [ normalizedDescriptor, isCurrent, ensureLoaded, effectivePositionMs, seekBy, effectiveIsPlaying, resume, ] ); return { trackId, descriptor: normalizedDescriptor, isCurrent, isPlaying: effectiveIsPlaying, positionMs: effectivePositionMs, durationMs: effectiveDurationMs, ensureLoaded, play: playNow, pause: pauseNow, resume: resumeNow, seekTo: seekToPosition, seekBy: seekByDelta, }; }; export default useTrackController;