This commit is contained in:
Alex Kim
2025-12-06 05:28:30 +11:00
parent c76d7eb877
commit bc78346760
10 changed files with 204 additions and 19 deletions

View File

@@ -28,7 +28,7 @@ import { useHaptic } from "@/hooks/useHaptic";
import { useIntroSkipper } from "@/hooks/useIntroSkipper";
import { usePlaybackManager } from "@/hooks/usePlaybackManager";
import { useTrickplay } from "@/hooks/useTrickplay";
import type { MpvPlayerViewRef, SubtitleTrack } from "@/modules";
import type { AudioTrack, MpvPlayerViewRef, SubtitleTrack } from "@/modules";
import { DownloadedItem } from "@/providers/Downloads/types";
import { useSettings } from "@/utils/atoms/settings";
import { getDefaultPlaySettings } from "@/utils/jellyfin/getDefaultPlaySettings";
@@ -71,8 +71,10 @@ interface Props {
getSubtitleTracks?:
| (() => Promise<SubtitleTrack[] | null>)
| (() => SubtitleTrack[]);
getAudioTracks?: (() => Promise<AudioTrack[] | null>) | (() => AudioTrack[]);
setSubtitleURL?: (url: string, customName: string) => void;
setSubtitleTrack?: (index: number) => void;
setAudioTrack?: (index: number) => void;
setVideoAspectRatio?: (aspectRatio: string | null) => Promise<void>;
setVideoScaleFactor?: (scaleFactor: number) => Promise<void>;
aspectRatio?: AspectRatio;
@@ -100,8 +102,10 @@ export const Controls: FC<Props> = ({
mediaSource,
isVideoLoaded,
getSubtitleTracks,
getAudioTracks,
setSubtitleURL,
setSubtitleTrack,
setAudioTrack,
setVideoAspectRatio,
setVideoScaleFactor,
aspectRatio = "default",
@@ -501,7 +505,9 @@ export const Controls: FC<Props> = ({
previousItem={previousItem}
nextItem={nextItem}
getSubtitleTracks={getSubtitleTracks}
getAudioTracks={getAudioTracks}
setSubtitleTrack={setSubtitleTrack}
setAudioTrack={setAudioTrack}
setSubtitleURL={setSubtitleURL}
aspectRatio={aspectRatio}
scaleFactor={scaleFactor}

View File

@@ -35,7 +35,9 @@ interface HeaderControlsProps {
previousItem?: BaseItemDto | null;
nextItem?: BaseItemDto | null;
getSubtitleTracks?: (() => Promise<any[] | null>) | (() => any[]);
getAudioTracks?: (() => Promise<any[] | null>) | (() => any[]);
setSubtitleTrack?: (index: number) => void;
setAudioTrack?: (index: number) => void;
setSubtitleURL?: (url: string, customName: string) => void;
aspectRatio?: AspectRatio;
scaleFactor?: ScaleFactor;
@@ -57,7 +59,9 @@ export const HeaderControls: FC<HeaderControlsProps> = ({
previousItem,
nextItem,
getSubtitleTracks,
getAudioTracks,
setSubtitleTrack,
setAudioTrack,
setSubtitleURL,
aspectRatio = "default",
scaleFactor = 1.0,
@@ -111,7 +115,9 @@ export const HeaderControls: FC<HeaderControlsProps> = ({
{!Platform.isTV && (!offline || !mediaSource?.TranscodingUrl) && (
<VideoProvider
getSubtitleTracks={getSubtitleTracks}
getAudioTracks={getAudioTracks}
setSubtitleTrack={setSubtitleTrack}
setAudioTrack={setAudioTrack}
setSubtitleURL={setSubtitleURL}
>
<View pointerEvents='auto'>

View File

@@ -9,12 +9,13 @@ import {
useMemo,
useState,
} from "react";
import type { SubtitleTrack } from "@/modules";
import type { AudioTrack, SubtitleTrack } from "@/modules";
import type { Track } from "../types";
import { useControlContext } from "./ControlContext";
interface VideoContextProps {
subtitleTracks: Track[] | null;
audioTracks: Track[] | null;
setSubtitleTrack: ((index: number) => void) | undefined;
setSubtitleURL: ((url: string, customName: string) => void) | undefined;
}
@@ -27,21 +28,29 @@ interface VideoProviderProps {
| (() => Promise<SubtitleTrack[] | null>)
| (() => SubtitleTrack[])
| undefined;
getAudioTracks:
| (() => Promise<AudioTrack[] | null>)
| (() => AudioTrack[])
| undefined;
setSubtitleTrack: ((index: number) => void) | undefined;
setAudioTrack: ((index: number) => void) | undefined;
setSubtitleURL: ((url: string, customName: string) => void) | undefined;
}
/**
* Video context provider for managing subtitle tracks.
s * Video context provider for managing subtitle and audio tracks.
* MPV player is used for all playback.
*/
export const VideoProvider: React.FC<VideoProviderProps> = ({
children,
getSubtitleTracks,
getAudioTracks,
setSubtitleTrack,
setAudioTrack,
setSubtitleURL,
}) => {
const [subtitleTracks, setSubtitleTracks] = useState<Track[] | null>(null);
const [audioTracks, setAudioTracks] = useState<Track[] | null>(null);
const ControlContext = useControlContext();
const isVideoLoaded = ControlContext?.isVideoLoaded;
@@ -122,6 +131,7 @@ export const VideoProvider: React.FC<VideoProviderProps> = ({
let subtitleData: SubtitleTrack[] | null = null;
try {
subtitleData = await getSubtitleTracks();
console.log("subtitleData", subtitleData);
} catch (error) {
console.log("[VideoContext] Failed to get subtitle tracks:", error);
return;
@@ -169,10 +179,49 @@ export const VideoProvider: React.FC<VideoProviderProps> = ({
fetchTracks();
}, [isVideoLoaded, getSubtitleTracks]);
// Fetch audio tracks
useEffect(() => {
const fetchAudioTracks = async () => {
if (getAudioTracks) {
let audioData: AudioTrack[] | null = null;
try {
audioData = await getAudioTracks();
console.log("audioData", audioData);
} catch (error) {
console.log("[VideoContext] Failed to get audio tracks:", error);
return;
}
const allAudio =
mediaSource?.MediaStreams?.filter((s) => s.Type === "Audio") || [];
let embedAudioIndex = 0;
const processedAudio: Track[] = allAudio?.map((audio) => {
const mpvIndex = audioData?.at(embedAudioIndex)?.id ?? 1;
embedAudioIndex++;
return {
name: audio.DisplayTitle || "Undefined Audio",
index: audio.Index ?? -1,
setTrack: () => {
setAudioTrack?.(mpvIndex);
router.setParams({
audioIndex: audio.Index?.toString() ?? "0",
});
},
};
});
setAudioTracks(processedAudio);
}
};
fetchAudioTracks();
}, [isVideoLoaded, getAudioTracks]);
return (
<VideoContext.Provider
value={{
subtitleTracks,
audioTracks,
setSubtitleTrack,
setSubtitleURL,
}}