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:
@@ -672,8 +672,11 @@ export const plexApi = {
|
||||
code: string | null;
|
||||
gen: number;
|
||||
}> =>
|
||||
// `quiet`: the player reports a failed poll inline, so no global error dialog on top of it.
|
||||
req(
|
||||
`/api/plex/subtitle/${encodeURIComponent(id)}/${ord}/status?at=${Math.max(0, Math.floor(at))}`,
|
||||
undefined,
|
||||
{ quiet: true },
|
||||
),
|
||||
// `final` marks a settled checkpoint (pause / page-hide / leaving the player) as opposed to the
|
||||
// periodic 10s tick — the backend mirrors the resume position to a linked Plex account only on a
|
||||
|
||||
Reference in New Issue
Block a user