Files
musicland/src/hooks/useTrackController.js
T
2025-10-07 09:51:38 +02:00

144 lines
3.4 KiB
JavaScript

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;