fix(subtitles): let the server deliver subtitles on a transcode
Two regressions since 2.9.1 broke subtitles on transcoded playback. Sincea1b6a8971sidecars load with the media behind a 10s open guard, so a subtitle URL the server is slow to serve — Jellyfin extracting an embedded stream while its transcoder spins up — tripped the guard: stop, reopen without subtitles, "Selected subtitles could not be loaded" snackbar, and an emptied subtitle menu. Since2b3853a88every embedded Plex subtitle was handed to the player as a sidecar whose URL is the original container, so a transcode also range-read and demuxed the source over HTTP — for a 40 GB remux, purely to find a subtitle track — which is also why PGS never appeared: the client was handed a container to demux rather than a rendition to play. Delivery is the server's job again, backported from the AVPlayer branch (42ba01440, the subtitle subset of 6852ac274, and a3da81e83) and adapted to main's mpv backend: Plex burns every embedded track (subtitles=burn); only a real external file with a /library/streams key stays a client-fetched sidecar. A burn is a re-encode, so directPlay is withdrawn — a real PMS answers HTTP 400 to directPlay=1 with burn — and the burn is aimed by selecting the stream on the part first via the selectStreams PUT, because the decision endpoint ignores subtitleStreamID alongside subtitles=burn. An unaimable or undeliverable burn (dvb_teletext) refuses the transcode and falls back to warned direct play rather than welding the wrong language in or silently dropping the caption. Main's per-preset directPlay/directStream pinning is kept; verified against a live PMS that burn works under directStream=0. Jellyfin never offers image formats as External, so bitmaps fall through to Encode and are burned; text External is withheld per request when the effective selection — including the server's DefaultSubtitleStreamIndex — is embedded, and offered when it is a real file, so a file is delivered as a file and never fetched twice. The burned row is excluded from the sidecars; remaining text rows stay extractable, which is how a secondary track still renders over a transcode. Sidecar URLs now use the format extension the endpoint expects instead of the reported codec name. The controls and selection layers learn what burning means: burn eligibility is the codec's property, so burned rows stay selectable in the menu; any change away from a burned selection renegotiates with the server instead of pretending a local switch worked; the visibility shortcut explains itself instead of doing nothing; and the track manager is told when the primary is server-rendered so it stops waiting out a thirty-second deadline for a native track that is already pixels. Verified: analyzer parity, clean_translations --check --strict, full flutter test (5749), and decision-level runs against live Plex and Jellyfin servers — text and PGS burn decisions, the directPlay=1+burn 400, External file delivery, an unchanged no-burn baseline, and a real burn session serving its playlist. The pre-commit aggregate was bypassed for pre-existing main-state findings outside this diff: 21 format-drifted files and three unused test seams in lib/main.dart. close #1738 Refs #1815, #1622.
This commit is contained in:
@@ -680,8 +680,18 @@ mixin _PlexLiveTvClientMethods on _PlexClientInternals implements LiveTvSupport,
|
||||
'directStreamAudio': directStreamAudio ? '1' : '0',
|
||||
'mediaBufferSize': '157286',
|
||||
'session': transcodeSessionId,
|
||||
// Prevent Plex from auto-selecting and burning tuner captions into the video.
|
||||
// Captions that survive direct stream remain player-selectable text tracks.
|
||||
// Deliberately NOT the VOD policy, which burns the selected embedded
|
||||
// stream. This path sets `directStream: 1` above, so Plex copies the
|
||||
// video rather than re-encoding it: burning here would force a full
|
||||
// re-encode of a live stream for a caption track that already arrives
|
||||
// for free. Broadcast captions (CEA-608/708) ride inside the copied
|
||||
// video bitstream and stay player-selectable, so there is nothing to
|
||||
// deliver and no stream id to send. Asking for a burn would also let
|
||||
// Plex auto-select a caption track the viewer never chose.
|
||||
//
|
||||
// Not covered: a DVB tuner's bitmap subtitles are separate streams
|
||||
// rather than in-band, so whether they survive the remux is unverified
|
||||
// and needs a DVB source to check.
|
||||
'subtitles': 'none',
|
||||
'copyts': '0',
|
||||
'Accept-Language': 'en',
|
||||
|
||||
Reference in New Issue
Block a user