mirror of
https://github.com/streamyfin/streamyfin.git
synced 2025-08-20 18:37:18 +02:00
135 lines
4.0 KiB
TypeScript
135 lines
4.0 KiB
TypeScript
import { TranscodedSubtitle } from "@/components/video-player/controls/types";
|
|
import { TrackInfo } from "@/modules/vlc-player";
|
|
import { MediaStream } from "@jellyfin/sdk/lib/generated-client";
|
|
import { Platform } from "react-native";
|
|
|
|
const disableSubtitle = {
|
|
name: "Disable",
|
|
index: -1,
|
|
IsTextSubtitleStream: true,
|
|
} as TranscodedSubtitle;
|
|
|
|
export class SubtitleHelper {
|
|
private mediaStreams: MediaStream[];
|
|
|
|
constructor(mediaStreams: MediaStream[]) {
|
|
this.mediaStreams = mediaStreams.filter((x) => x.Type === "Subtitle");
|
|
}
|
|
|
|
getSubtitles(): MediaStream[] {
|
|
return this.mediaStreams;
|
|
}
|
|
|
|
getUniqueSubtitles(): MediaStream[] {
|
|
const uniqueSubs: MediaStream[] = [];
|
|
const seen = new Set<string>();
|
|
|
|
this.mediaStreams.forEach((x) => {
|
|
if (!seen.has(x.DisplayTitle!)) {
|
|
seen.add(x.DisplayTitle!);
|
|
uniqueSubs.push(x);
|
|
}
|
|
});
|
|
|
|
return uniqueSubs;
|
|
}
|
|
|
|
getCurrentSubtitle(subtitleIndex?: number): MediaStream | undefined {
|
|
return this.mediaStreams.find((x) => x.Index === subtitleIndex);
|
|
}
|
|
|
|
getMostCommonSubtitleByName(
|
|
subtitleIndex: number | undefined
|
|
): number | undefined {
|
|
if (subtitleIndex === undefined) -1;
|
|
const uniqueSubs = this.getUniqueSubtitles();
|
|
const currentSub = this.getCurrentSubtitle(subtitleIndex);
|
|
|
|
return uniqueSubs.find((x) => x.DisplayTitle === currentSub?.DisplayTitle)
|
|
?.Index;
|
|
}
|
|
|
|
getTextSubtitles(): MediaStream[] {
|
|
return this.mediaStreams.filter((x) => x.IsTextSubtitleStream);
|
|
}
|
|
|
|
getImageSubtitles(): MediaStream[] {
|
|
return this.mediaStreams.filter((x) => !x.IsTextSubtitleStream);
|
|
}
|
|
|
|
getEmbeddedTrackIndex(sourceSubtitleIndex: number): number {
|
|
if (Platform.OS === "android") {
|
|
const textSubs = this.getTextSubtitles();
|
|
const matchingSubtitle = textSubs.find(
|
|
(sub) => sub.Index === sourceSubtitleIndex
|
|
);
|
|
|
|
if (!matchingSubtitle) return -1;
|
|
return textSubs.indexOf(matchingSubtitle);
|
|
}
|
|
|
|
// Get unique text-based subtitles because react-native-video removes hls text tracks duplicates. (iOS)
|
|
const uniqueTextSubs = this.getUniqueTextBasedSubtitles();
|
|
const matchingSubtitle = uniqueTextSubs.find(
|
|
(sub) => sub.Index === sourceSubtitleIndex
|
|
);
|
|
|
|
if (!matchingSubtitle) return -1;
|
|
return uniqueTextSubs.indexOf(matchingSubtitle);
|
|
}
|
|
|
|
sortSubtitles(
|
|
textSubs: TranscodedSubtitle[],
|
|
allSubs: MediaStream[]
|
|
): TranscodedSubtitle[] {
|
|
let textIndex = 0; // To track position in textSubtitles
|
|
// Merge text and image subtitles in the order of allSubs
|
|
const sortedSubtitles = allSubs.map((sub) => {
|
|
if (sub.IsTextSubtitleStream) {
|
|
if (textSubs.length === 0) return disableSubtitle;
|
|
const textSubtitle = textSubs[textIndex];
|
|
if (!textSubtitle) return disableSubtitle;
|
|
textIndex++;
|
|
return textSubtitle;
|
|
} else {
|
|
return {
|
|
name: sub.DisplayTitle!,
|
|
index: sub.Index!,
|
|
IsTextSubtitleStream: sub.IsTextSubtitleStream,
|
|
} as TranscodedSubtitle;
|
|
}
|
|
});
|
|
|
|
return sortedSubtitles;
|
|
}
|
|
|
|
getSortedSubtitles(subtitleTracks: TrackInfo[]): TranscodedSubtitle[] {
|
|
const textSubtitles =
|
|
subtitleTracks.map((s) => ({
|
|
name: s.name,
|
|
index: s.index,
|
|
IsTextSubtitleStream: true,
|
|
})) || [];
|
|
|
|
const sortedSubs =
|
|
Platform.OS === "android"
|
|
? this.sortSubtitles(textSubtitles, this.mediaStreams)
|
|
: this.sortSubtitles(textSubtitles, this.getUniqueSubtitles());
|
|
|
|
return sortedSubs;
|
|
}
|
|
|
|
getUniqueTextBasedSubtitles(): MediaStream[] {
|
|
return this.getUniqueSubtitles().filter((x) => x.IsTextSubtitleStream);
|
|
}
|
|
|
|
// HLS stream indexes are not the same as the actual source indexes.
|
|
// This function aims to get the source subtitle index from the embedded track index.
|
|
getSourceSubtitleIndex = (embeddedTrackIndex: number): number => {
|
|
if (Platform.OS === "android") {
|
|
return this.getSubtitles()[embeddedTrackIndex]?.Index ?? -1;
|
|
}
|
|
return this.getUniqueTextBasedSubtitles()[embeddedTrackIndex]?.Index ?? -1;
|
|
};
|
|
}
|