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:
@@ -395,6 +395,17 @@ def test_polls_that_follow_the_playhead_join_one_window(monkeypatch):
|
||||
assert len(pool.jobs) == 2, "one window + the one full pass"
|
||||
|
||||
|
||||
def test_a_window_for_a_different_stretch_does_not_wait_behind_the_first(monkeypatch):
|
||||
"""Measured on localdev: after a resume the first poll can still report 0 (the position is only
|
||||
known once playback ticks), so the first window is cut around the wrong spot. The poll that
|
||||
follows, at the real position, must get its own window at once — not queue behind that one."""
|
||||
pool = _ManualPool()
|
||||
monkeypatch.setattr(subtitles, "_POOL", pool)
|
||||
subtitles.ensure("98614", 1, at=0.0)
|
||||
subtitles.ensure("98614", 1, at=1198.0)
|
||||
assert sorted(a[3] for _, a in pool.jobs if a[3] is not None) == [0.0, 1168.0]
|
||||
|
||||
|
||||
def test_a_queued_window_that_was_covered_meanwhile_reads_nothing(monkeypatch):
|
||||
"""Every embedded track rides each pass over its file, so by the time a queued window for one
|
||||
language runs, another language's window may already have published it."""
|
||||
|
||||
Reference in New Issue
Block a user