fix(plex): mark the finished episode on the correct id when auto-advancing
The player's watched-mark on completion keyed off the reactive `id`, which can run ahead of the media actually playing: when the next episode fails to load (e.g. no local file), loadSession returns without replacing the <video> source, so the old episode keeps playing and later fires 'ended' — but by then an auto-skip-credits jump has already advanced `id` to the next episode. The result was the WRONG episode marked watched (and scrobbled to Plex), while the finished one got nothing. This was latent before, made visible/harmful by the Phase B Plex push. - go(): pause the outgoing media before switching, so a failed next-episode load can't leave the old media running into a stray 'ended' against the new id. - auto-skip-credits (doSkip): mark the CURRENT id watched (captured now) before advancing — binge advance is a finish, and previously marked nothing. - onEnded: ignore a spurious 'ended' from media that never played (absRef 0), so a failed next episode can't be marked or cascade another advance. Manual Next/Prev still never mark watched (not a finish). Verified live: E06→E07 with a missing E07 marks E06 watched (+ Plex), E07 nothing.
This commit is contained in:
parent
3a3ba17fb8
commit
363b4d17fc
1 changed files with 19 additions and 3 deletions
|
|
@ -566,6 +566,15 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
|||
const go = useCallback(
|
||||
(otherId: string | null | undefined) => {
|
||||
if (otherId) {
|
||||
// Stop the outgoing media BEFORE switching. If the next item fails to load (e.g. no local
|
||||
// file), loadSession returns without replacing the <video> source, leaving the old episode
|
||||
// still playing — it would then fire 'ended' against the NEW id and mark the wrong item
|
||||
// watched (and scrobble it to Plex). Pausing here severs that stale-tail race.
|
||||
try {
|
||||
videoRef.current?.pause();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
setAbs(0);
|
||||
setId(otherId);
|
||||
}
|
||||
|
|
@ -710,6 +719,9 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
|||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
const onEnded = () => {
|
||||
// Only a genuine play-to-the-end counts. A next episode that failed to load never played
|
||||
// (absRef 0) — its stray 'ended' must not mark anything watched or cascade another advance.
|
||||
if (absRef.current <= 0) return;
|
||||
api.plexSetState(id, "watched").catch(() => {});
|
||||
if (nextId) go(nextId);
|
||||
};
|
||||
|
|
@ -845,10 +857,14 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
|||
const doSkip = useCallback(
|
||||
(m: PlexMarker) => {
|
||||
setSkipProgress(null);
|
||||
if (m.type === "credits" && nextId) go(nextId);
|
||||
else seekTo(m.end_s);
|
||||
if (m.type === "credits" && nextId) {
|
||||
// Binge auto-advance: the episode we're leaving was watched through the credits, so mark IT
|
||||
// (the current id, captured here — not the reactive id, which go() is about to change).
|
||||
api.plexSetState(id, "watched").catch(() => {});
|
||||
go(nextId);
|
||||
} else seekTo(m.end_s);
|
||||
},
|
||||
[go, nextId, seekTo],
|
||||
[id, go, nextId, seekTo],
|
||||
);
|
||||
const cancelAutoSkip = useCallback(() => {
|
||||
const m = activeMarkerRef.current;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue