merge: player queue fixes (Loop One + freeze launch list for Loop All/Next-Prev) — v0.23.2

This commit is contained in:
npeter83 2026-07-05 21:10:30 +02:00
commit 4993298838
3 changed files with 21 additions and 2 deletions

View file

@ -1 +1 @@
0.23.1 0.23.2

View file

@ -50,7 +50,7 @@ function loadYouTubeApi(): Promise<any> {
export default function PlayerModal({ export default function PlayerModal({
video, video,
startAt, startAt,
queue, queue: queueProp,
startIndex, startIndex,
onClose, onClose,
onState, onState,
@ -75,6 +75,14 @@ export default function PlayerModal({
const qc = useQueryClient(); const qc = useQueryClient();
// Browser/mouse Back closes the player instead of leaving the page. // Browser/mouse Back closes the player instead of leaving the page.
useBackToClose(onClose); useBackToClose(onClose);
// Freeze the launch queue: the player steps through the SAME filtered + sorted list it was
// opened with, for its whole session. The live feed refetches and reorders/drops items under
// us — e.g. auto-marking each video watched near its end removes it from a filtered feed — which
// would otherwise shrink the queue mid-playback and break prev/next + Loop "All" (it could never
// wrap back to the first item once earlier items dropped out). Snapshot once at mount via
// useState's lazy initializer and ignore later prop changes. Items that turn out gone/
// non-embeddable still surface the existing playback-error overlay when reached.
const [queue] = useState(() => queueProp);
// Precise upload date shown inline after the relative time (e.g. "9 yr ago · 12 Jan 2017"). // Precise upload date shown inline after the relative time (e.g. "9 yr ago · 12 Jan 2017").
const fullDate = (d: string | null | undefined) => const fullDate = (d: string | null | undefined) =>
d d
@ -93,6 +101,9 @@ export default function PlayerModal({
// `video` in the queue (the feed passes its whole list + the clicked video, no index). // `video` in the queue (the feed passes its whole list + the clicked video, no index).
startIndex != null ? queue?.[startIndex]?.id ?? video.id : video.id startIndex != null ? queue?.[startIndex]?.id ?? video.id : video.id
); );
// Locate the playing item in the frozen launch queue → drives prev/next + the N/M counter.
// Because the queue is frozen, the playing id always stays in it (unlike the old live queue,
// where a just-watched item could drop out and snap playback to queue[0]).
let index = queue ? queue.findIndex((v) => v.id === playingId) : 0; let index = queue ? queue.findIndex((v) => v.id === playingId) : 0;
if (index < 0) index = 0; if (index < 0) index = 0;
const active = queue && queue[index] ? queue[index] : video; const active = queue && queue[index] ? queue[index] : video;

View file

@ -14,6 +14,14 @@ export interface ReleaseEntry {
} }
export const RELEASE_NOTES: ReleaseEntry[] = [ export const RELEASE_NOTES: ReleaseEntry[] = [
{
version: "0.23.2",
date: "2026-07-05",
summary: "The player now steps through the exact list it was opened with, so watching along no longer breaks Loop and Next/Previous.",
fixes: [
"Player: it now plays through a frozen snapshot of the filtered, sorted list it was launched with. Previously, as each video was auto-marked watched it dropped out of a filtered feed, silently shrinking the queue mid-playback — which jumped playback to an unrelated video, and stopped Loop “All” from ever wrapping back to the first video once earlier ones were watched. Next/Previous and both Loop modes now work against the original list for the whole session.",
],
},
{ {
version: "0.23.1", version: "0.23.1",
date: "2026-07-05", date: "2026-07-05",