fix: restore StreamRanker for cross-episode track matching

Removing StreamRanker reduced track matching to direct index reuse. When a
next episode has a different audio/subtitle track layout (common with anime
multi-sub releases or mixed sources), the stored index points at the wrong
track. StreamRanker scores by codec/language/title/relative index and only
applies a match above threshold, otherwise falls back to media defaults.

Restores utils/streamRanker.ts and its use in getDefaultPlaySettings so the
cleanup PR stays behavior-preserving for playback.
This commit is contained in:
Uruk
2026-05-22 01:43:40 +02:00
parent 381dc351e2
commit da3654ec4a
2 changed files with 184 additions and 5 deletions

View File

@@ -15,6 +15,11 @@ import type {
} from "@jellyfin/sdk/lib/generated-client";
import { BITRATES } from "@/components/BitrateSelector";
import { type Settings } from "../atoms/settings";
import {
AudioStreamRanker,
StreamRanker,
SubtitleStreamRanker,
} from "../streamRanker";
export interface PlaySettings {
item: BaseItemDto;
@@ -49,27 +54,42 @@ export function getDefaultPlaySettings(
}
const mediaSource = item.MediaSources?.[0];
const _streams = mediaSource?.MediaStreams ?? [];
const streams = mediaSource?.MediaStreams ?? [];
// Start with media source defaults
let audioIndex = mediaSource?.DefaultAudioStreamIndex;
let subtitleIndex = mediaSource?.DefaultSubtitleStreamIndex ?? -1;
// Try to match previous selections (sequential play)
// Simplified: just use previous indexes if available
if (previous?.indexes && settings) {
if (previous?.indexes && previous?.source && settings) {
if (
settings.rememberSubtitleSelections &&
previous.indexes.subtitleIndex !== undefined
) {
subtitleIndex = previous.indexes.subtitleIndex;
const ranker = new StreamRanker(new SubtitleStreamRanker());
const result = { DefaultSubtitleStreamIndex: subtitleIndex };
ranker.rankStream(
previous.indexes.subtitleIndex,
previous.source,
streams,
result,
);
subtitleIndex = result.DefaultSubtitleStreamIndex;
}
if (
settings.rememberAudioSelections &&
previous.indexes.audioIndex !== undefined
) {
audioIndex = previous.indexes.audioIndex;
const ranker = new StreamRanker(new AudioStreamRanker());
const result = { DefaultAudioStreamIndex: audioIndex };
ranker.rankStream(
previous.indexes.audioIndex,
previous.source,
streams,
result,
);
audioIndex = result.DefaultAudioStreamIndex;
}
}