fix(player): only the credits that end an item move on to the next one

An item can carry several credits blocks with mid- and post-credit scenes between
them, and Plex flags the one that really ends it. The player left at the first
block. Now the Plex-final block moves on (by the auto-skip or the Skip button), an
earlier block is only skipped to its end by the button, and with no final flag the
last block ends the item by the button alone.
This commit is contained in:
2026-10-07 01:48:10 +02:00
parent f3c94641a7
commit 0cda5b6dd4
9 changed files with 189 additions and 10 deletions
+33
View File
@@ -0,0 +1,33 @@
// What skipping an intro/credits marker does. An item can carry several credits blocks — mid- and
// post-credit scenes play between them — so only the block that ends the item moves on to the next
// one: the block Plex flags `final`, else the last one. Every other credits block is skipped like an
// intro, to its own end. And only an end Plex itself vouches for is left on its own (the credits
// auto-skip); an end inferred from the list waits for the viewer's Skip — the stretch after it may
// still be the show.
import type { PlexMarker } from "./api";
/** `leaves`: skipping it moves on to the next item (else: jumps to its end). `auto`: the auto-skip
* setting may act on it without the viewer. */
export interface MarkerSkip {
leaves: boolean;
auto: boolean;
}
function endCredits(markers: readonly PlexMarker[]): PlexMarker | undefined {
const credits = markers.filter((m) => m.type === "credits");
return (
credits.find((m) => m.final) ??
credits.reduce<PlexMarker | undefined>(
(last, m) => (last && last.start_s > m.start_s ? last : m),
undefined,
)
);
}
export function markerSkip(marker: PlexMarker, markers: readonly PlexMarker[]): MarkerSkip {
if (marker.type === "intro") return { leaves: false, auto: true };
// By offset, not identity: a refetched list hands back equal-but-new objects.
const end = endCredits(markers);
const leaves = end != null && end.start_s === marker.start_s && end.end_s === marker.end_s;
return { leaves, auto: leaves && marker.final };
}