fix(plex): the subtitle poll backs off on errors, a failed <track> is replaced, and a resume asks for the right window
Deep-review R2, plus one defect found while verifying it on localdev. - The status poll re-armed every second after a FAILED request: `data` stays empty on an error, so it read as "still preparing" for as long as the player was open — and the request was not quiet, so a persistent 500 re-opened the global error dialog every second. It now backs off to 10 s (a blip still heals on its own) and is quiet; the player already shows the failure inline. - A <track> whose own VTT fetch failed never fetched again: with the server's answer unchanged its key was unchanged, so React kept the dead element — silently blank subtitles. The key (now built in the hook, where it is tested) carries a failed-load count; after two remounts the track is reported as unavailable instead. - Found in UAT: until the first timeupdate `abs` is 0, so after a resume every poll said at=0 and the first window was cut around the head of the film (a resume at 20:00 polled at=0 for as long as it stayed paused). The poll reports the session's start until playback ticks. And the window's dedup identity is the track plus a window-length bucket of its start — keyed on the track alone (R1), the right window queued behind that wrong one. The poll's start/stop rules finally have tests (every earlier one resolved a single fixed answer). Verified on localdev against Westworld S1E6 resumed at 20:00: the polls carried at=1197, one subtitle line on screen at 21:02, the poll stopped at `ready`; the real file's window (56 cues) + full pass (608) merged to 608 — the old merge would have served 664. 11 mutations, all red.
This commit is contained in:
@@ -380,6 +380,7 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
||||
subShowable,
|
||||
subFail,
|
||||
subGen,
|
||||
subTrackKey,
|
||||
onSubTrackError,
|
||||
} = usePlexTracks({
|
||||
id,
|
||||
@@ -873,10 +874,10 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
||||
above flips modes; the browser fetches a track's VTT the first time it's shown. */}
|
||||
{selectedSub && subShowable && (
|
||||
<track
|
||||
// One track = the selected sub only (no multi-track overlap). Key by the shifted-offset so
|
||||
// a seek-restart or a (debounced) sub-offset change remounts → fresh VTT fetch, and by the
|
||||
// extraction generation so a widened track replaces the first short window.
|
||||
key={`${id}-${selectedSub.ord}-${subTrackOffset.toFixed(2)}-${subGen}`}
|
||||
// One track = the selected sub only (no multi-track overlap). The key (see usePlexTracks)
|
||||
// is what remounts it for a fresh VTT fetch: a seek-restart, an offset change, a widened
|
||||
// track, or a failed load.
|
||||
key={subTrackKey}
|
||||
kind="subtitles"
|
||||
src={api.plexSubtitleUrl(id, selectedSub.ord, subTrackOffset, subGen)}
|
||||
srcLang={selectedSub.language ?? undefined}
|
||||
|
||||
Reference in New Issue
Block a user