fix(plex): a subtitle failure about one position no longer ends the track, and windows are read ahead and never wait behind a full pass
Deep-review round 3 of bug hunt 2026-09. - `failed` is now final only for a track that can never be text (bitmap, no item/track/file). A Plex hiccup or a stretch ffmpeg could not read answers `unavailable`: said, polled again every 5 s, and the <track> stays mounted when cues exist elsewhere (gen > 0). Re-picking the selected track asks the server again at once. - Within LOOKAHEAD_S of a covered stretch's end the next window is read ahead, instead of only once the playhead has fallen off it (subtitles dropped out at every edge while the full pass was backed off or slower than a window lasts). - Windows and full passes run on separate pools with separate in-flight caps, so a window never queues behind (or is refused by) minute-long full passes — the pool comment promised that and nothing enforced it. - A pass that times out is TERMinated and keeps what it reached (published as partial) instead of being killed and discarded. - Lapsed failure memos are swept on every write (they were only pruned when the same key was read again, so polling fresh keys grew the process without bound). - `publish` no longer merges into a sidecar with no VTT behind it, or claims a region whose VTT write failed, or overwrites an unreadable track with one window. - A NUL in a rating_key names no row (it was a DataError, a 500, on every Plex route) and no longer 500s the status poll. Tests: 16 new, each mutation-checked (18 mutations, all red on the test that names them).
This commit is contained in:
@@ -662,13 +662,15 @@ export const plexApi = {
|
||||
// Whether a subtitle track can be shown yet. Extracting one out of a big MKV costs a full read of
|
||||
// the container (measured: 154 s for a 17 GB film), so the server does it in the background — around
|
||||
// `at`, the viewer's position, first — and the player polls this instead of mounting a <track> that
|
||||
// would sit empty for minutes. `partial` = a window around `at` is ready and still growing.
|
||||
// would sit empty for minutes. `partial` = a window around `at` is ready and still growing;
|
||||
// `unavailable` = nothing for `at` right now (`code` says why) but ask again — cues elsewhere, when
|
||||
// `gen` > 0, are still there; `failed` = the track can never be shown (the only final answer).
|
||||
plexSubtitleStatus: (
|
||||
id: string,
|
||||
ord: number,
|
||||
at = 0,
|
||||
): Promise<{
|
||||
state: "ready" | "partial" | "preparing" | "failed";
|
||||
state: "ready" | "partial" | "preparing" | "unavailable" | "failed";
|
||||
code: string | null;
|
||||
gen: number;
|
||||
}> =>
|
||||
|
||||
Reference in New Issue
Block a user