fix(plex): subtitles — a retried full pass resumes, a stalled track is polled slowly

A full pass that ran out of time kept what it reached, but its retry an hour
later started again at 0, so a file too big to read inside the extraction
timeout never completed. The pass now starts where every embedded track's
coverage from the head ends (less the window pre-roll, so a cue across the
join is read whole). The seek needs -avoid_negative_ts on this read as on a
window, measured on a real file: without it the cue running at the start
shifts the whole output.

A partial track whose full pass had failed never reached a settled state, so
the player polled it every 2 s for the rest of the film. The status now says
whether the track is still growing, and a stalled one is polled every 15 s —
still inside the 60 s lookahead that reads the next window before an edge.
This commit is contained in:
2026-09-19 07:07:53 +02:00
parent e6b76e156a
commit c60359bfed
5 changed files with 126 additions and 5 deletions
+7 -1
View File
@@ -484,6 +484,11 @@ const SUB_POLL_ERROR_MS = 10_000;
// server keeps for a minute), so no need for the 1 s cadence — but the poll carries the position, and
// moving into a stretch that IS cached should stop saying "couldn't be loaded" within a few seconds.
const SUB_POLL_UNAVAILABLE_MS = 5_000;
// …and on a `partial` track that is no longer `growing` (its full pass failed and is backed off for
// an hour): it will not fill in on its own, so the 2 s cadence ran for the rest of the film. The poll
// still carries the position — it is what reads the next window ahead of an edge, which the server
// starts within LOOKAHEAD_S (60 s) of it — so it slows down rather than stops.
const SUB_POLL_STALLED_MS = 15_000;
const SUB_TRACK_RETRIES = 2;
const SUB_TRACK_RETRY_MS = 2_000;
@@ -684,7 +689,8 @@ export function usePlexTracks(opts: {
const st = q.state.data?.state;
if (st === "ready" || st === "failed") return false;
if (st === "unavailable") return SUB_POLL_UNAVAILABLE_MS;
return st === "partial" ? 2000 : 1000;
if (st === "partial") return q.state.data?.growing === false ? SUB_POLL_STALLED_MS : 2000;
return 1000;
},
staleTime: 0,
retry: false,