mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-09 14:02:51 +01:00
fix(subtitles): normalize local subtitle sentinel to -1 in stream re-negotiation URLs
This commit is contained in:
@@ -25,7 +25,10 @@ import { Controls } from "@/components/video-player/controls/Controls";
|
|||||||
import { Controls as TVControls } from "@/components/video-player/controls/Controls.tv";
|
import { Controls as TVControls } from "@/components/video-player/controls/Controls.tv";
|
||||||
import { PlayerProvider } from "@/components/video-player/controls/contexts/PlayerContext";
|
import { PlayerProvider } from "@/components/video-player/controls/contexts/PlayerContext";
|
||||||
import { VideoProvider } from "@/components/video-player/controls/contexts/VideoContext";
|
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 {
|
import {
|
||||||
PlaybackSpeedScope,
|
PlaybackSpeedScope,
|
||||||
updatePlaybackSpeedSettings,
|
updatePlaybackSpeedSettings,
|
||||||
@@ -888,7 +891,9 @@ export default function DirectPlayerPage() {
|
|||||||
const queryParams = new URLSearchParams({
|
const queryParams = new URLSearchParams({
|
||||||
itemId: item?.Id ?? "",
|
itemId: item?.Id ?? "",
|
||||||
audioIndex: String(index),
|
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 ?? "",
|
mediaSourceId: stream?.mediaSource?.Id ?? "",
|
||||||
bitrateValue: bitrateValue?.toString() ?? "",
|
bitrateValue: bitrateValue?.toString() ?? "",
|
||||||
playbackPosition: msToTicks(progress.get()).toString(),
|
playbackPosition: msToTicks(progress.get()).toString(),
|
||||||
@@ -954,7 +959,9 @@ export default function DirectPlayerPage() {
|
|||||||
const queryParams = new URLSearchParams({
|
const queryParams = new URLSearchParams({
|
||||||
itemId: item?.Id ?? "",
|
itemId: item?.Id ?? "",
|
||||||
audioIndex: params.audioIndex ?? String(currentAudioIndex ?? ""),
|
audioIndex: params.audioIndex ?? String(currentAudioIndex ?? ""),
|
||||||
subtitleIndex: params.subtitleIndex ?? String(currentSubtitleIndex),
|
subtitleIndex:
|
||||||
|
params.subtitleIndex ??
|
||||||
|
String(toServerSubtitleIndex(currentSubtitleIndex)),
|
||||||
mediaSourceId: stream?.mediaSource?.Id ?? "",
|
mediaSourceId: stream?.mediaSource?.Id ?? "",
|
||||||
bitrateValue: bitrateValue?.toString() ?? "",
|
bitrateValue: bitrateValue?.toString() ?? "",
|
||||||
playbackPosition: msToTicks(progress.get()).toString(),
|
playbackPosition: msToTicks(progress.get()).toString(),
|
||||||
|
|||||||
@@ -126,10 +126,17 @@ export const VideoProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
audioIndex?: string;
|
audioIndex?: string;
|
||||||
subtitleIndex?: 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({
|
const queryParams = new URLSearchParams({
|
||||||
itemId: itemId ?? "",
|
itemId: itemId ?? "",
|
||||||
audioIndex: params.audioIndex ?? audioIndex,
|
audioIndex: params.audioIndex ?? audioIndex,
|
||||||
subtitleIndex: params.subtitleIndex ?? subtitleIndex,
|
subtitleIndex: params.subtitleIndex ?? fallbackSubtitleIndex,
|
||||||
mediaSourceId: mediaSource?.Id ?? "",
|
mediaSourceId: mediaSource?.Id ?? "",
|
||||||
bitrateValue: bitrateValue,
|
bitrateValue: bitrateValue,
|
||||||
playbackPosition: playbackPosition,
|
playbackPosition: playbackPosition,
|
||||||
|
|||||||
@@ -36,4 +36,12 @@ type Track = {
|
|||||||
*/
|
*/
|
||||||
export const LOCAL_SUBTITLE_INDEX_START = -100;
|
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 };
|
export type { EmbeddedSubtitle, ExternalSubtitle, Track, TranscodedSubtitle };
|
||||||
|
|||||||
Reference in New Issue
Block a user