feat(playlists): keep the player queue live across tabs
Track the playing item by id instead of a frozen index, deriving the index from the live queue so the N / M counter and prev/next neighbours stay correct when the playlist changes underneath (e.g. an item removed in another tab) without disrupting playback of the current video. Refetch the playlist list/detail on window focus so such changes flow in, updating the player's queue length in near-real-time.
This commit is contained in:
parent
bd085fc88f
commit
639d761bef
2 changed files with 20 additions and 6 deletions
|
|
@ -203,8 +203,15 @@ export default function PlayerModal({
|
|||
}) {
|
||||
const { t } = useTranslation();
|
||||
const qc = useQueryClient();
|
||||
// The active item is queue[index] (falls back to the single opened video).
|
||||
const [index, setIndex] = useState(startIndex ?? 0);
|
||||
// Track the playing item by id (not a frozen index) so it survives the queue changing
|
||||
// under us — e.g. an item removed in another tab. The index is derived from the *live*
|
||||
// queue, so the N / M counter and prev/next neighbours stay correct without disrupting
|
||||
// playback of the current video.
|
||||
const [playingId, setPlayingId] = useState<string>(
|
||||
queue?.[startIndex ?? 0]?.id ?? video.id
|
||||
);
|
||||
let index = queue ? queue.findIndex((v) => v.id === playingId) : 0;
|
||||
if (index < 0) index = 0;
|
||||
const active = queue && queue[index] ? queue[index] : video;
|
||||
const hasQueue = !!queue && queue.length > 1;
|
||||
// startAt only applies to the item we opened with; advanced items resume their own pos.
|
||||
|
|
@ -369,7 +376,7 @@ export default function PlayerModal({
|
|||
autoMarkedRef.current = true;
|
||||
setWatched(true);
|
||||
}
|
||||
if (queue && index < queue.length - 1) setIndex(index + 1);
|
||||
if (queue && index < queue.length - 1) setPlayingId(queue[index + 1].id);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -418,7 +425,7 @@ export default function PlayerModal({
|
|||
{hasQueue && (
|
||||
<div className="flex items-center justify-center gap-5 px-4 py-2 border-b border-border text-sm">
|
||||
<button
|
||||
onClick={() => setIndex((i) => Math.max(0, i - 1))}
|
||||
onClick={() => index > 0 && setPlayingId(queue![index - 1].id)}
|
||||
disabled={index === 0}
|
||||
className="inline-flex items-center gap-1.5 text-muted enabled:hover:text-fg disabled:opacity-40 transition"
|
||||
>
|
||||
|
|
@ -428,7 +435,7 @@ export default function PlayerModal({
|
|||
{index + 1} / {queue!.length}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setIndex((i) => Math.min(queue!.length - 1, i + 1))}
|
||||
onClick={() => index < queue!.length - 1 && setPlayingId(queue![index + 1].id)}
|
||||
disabled={index === queue!.length - 1}
|
||||
className="inline-flex items-center gap-1.5 text-muted enabled:hover:text-fg disabled:opacity-40 transition"
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue