144 lines
3.4 KiB
JavaScript
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;
|
|
|