fix(subtitles): normalize local subtitle sentinel to -1 in stream re-negotiation URLs

This commit is contained in:
Gauvain
2026-07-08 18:14:07 +02:00
parent 8219e44b5b
commit b59759638c
3 changed files with 26 additions and 4 deletions

View File

@@ -25,7 +25,10 @@ import { Controls } from "@/components/video-player/controls/Controls";
import { Controls as TVControls } from "@/components/video-player/controls/Controls.tv";
import { PlayerProvider } from "@/components/video-player/controls/contexts/PlayerContext";
import { VideoProvider } from "@/components/video-player/controls/contexts/VideoContext";
import { LOCAL_SUBTITLE_INDEX_START } from "@/components/video-player/controls/types";
import {
LOCAL_SUBTITLE_INDEX_START,
toServerSubtitleIndex,
} from "@/components/video-player/controls/types";
import {
PlaybackSpeedScope,
updatePlaybackSpeedSettings,
@@ -888,7 +891,9 @@ export default function DirectPlayerPage() {
const queryParams = new URLSearchParams({
itemId: item?.Id ?? "",
audioIndex: String(index),
subtitleIndex: String(currentSubtitleIndex),
// A local (client-downloaded) sub only exists in the dying mpv
// instance — the server must be asked for "none" (-1) instead.
subtitleIndex: String(toServerSubtitleIndex(currentSubtitleIndex)),
mediaSourceId: stream?.mediaSource?.Id ?? "",
bitrateValue: bitrateValue?.toString() ?? "",
playbackPosition: msToTicks(progress.get()).toString(),
@@ -954,7 +959,9 @@ export default function DirectPlayerPage() {
const queryParams = new URLSearchParams({
itemId: item?.Id ?? "",
audioIndex: params.audioIndex ?? String(currentAudioIndex ?? ""),
subtitleIndex: params.subtitleIndex ?? String(currentSubtitleIndex),
subtitleIndex:
params.subtitleIndex ??
String(toServerSubtitleIndex(currentSubtitleIndex)),
mediaSourceId: stream?.mediaSource?.Id ?? "",
bitrateValue: bitrateValue?.toString() ?? "",
playbackPosition: msToTicks(progress.get()).toString(),

View File

@@ -126,10 +126,17 @@ export const VideoProvider: React.FC<{ children: ReactNode }> = ({
audioIndex?: string;
subtitleIndex?: string;
}) => {
// The URL param can hold a local-sub sentinel (selected via setParams) that
// only exists in the dying player — the server must get "none" (-1) instead.
// NaN (missing/blank param) fails the comparison and passes through as-is.
const fallbackSubtitleIndex =
Number.parseInt(subtitleIndex, 10) <= LOCAL_SUBTITLE_INDEX_START
? "-1"
: subtitleIndex;
const queryParams = new URLSearchParams({
itemId: itemId ?? "",
audioIndex: params.audioIndex ?? audioIndex,
subtitleIndex: params.subtitleIndex ?? subtitleIndex,
subtitleIndex: params.subtitleIndex ?? fallbackSubtitleIndex,
mediaSourceId: mediaSource?.Id ?? "",
bitrateValue: bitrateValue,
playbackPosition: playbackPosition,

View File

@@ -36,4 +36,12 @@ type Track = {
*/
export const LOCAL_SUBTITLE_INDEX_START = -100;
/**
* Map a client-side subtitle index to what the Jellyfin stream API understands.
* Local sentinel indexes have no matching MediaStream on the server, which
* expects -1 ("no subtitles") when re-negotiating a stream.
*/
export const toServerSubtitleIndex = (index: number): number =>
index <= LOCAL_SUBTITLE_INDEX_START ? -1 : index;
export type { EmbeddedSubtitle, ExternalSubtitle, Track, TranscodedSubtitle };