diff --git a/app/(auth)/vlc-player.tsx b/app/(auth)/vlc-player.tsx index 69f0213d..f4ee96d9 100644 --- a/app/(auth)/vlc-player.tsx +++ b/app/(auth)/vlc-player.tsx @@ -1,5 +1,4 @@ import { Controls } from "@/components/video-player/Controls"; -import { VideoDebugInfo } from "@/components/vlc/VideoDebugInfo"; import { useAndroidNavigationBar } from "@/hooks/useAndroidNavigationBar"; import { useOrientation } from "@/hooks/useOrientation"; import { useOrientationSettings } from "@/hooks/useOrientationSettings"; @@ -24,7 +23,6 @@ import { getPlaystateApi } from "@jellyfin/sdk/lib/utils/api"; import * as Haptics from "expo-haptics"; import { useFocusEffect } from "expo-router"; import { useAtomValue } from "jotai"; -import { set } from "lodash"; import React, { useCallback, useEffect, @@ -32,13 +30,9 @@ import React, { useRef, useState, } from "react"; -import { Alert, Dimensions, Pressable, StatusBar, View } from "react-native"; +import { Dimensions, Pressable, StatusBar, View } from "react-native"; import { useSharedValue } from "react-native-reanimated"; -import Video, { - OnProgressData, - SelectedTrackType, - VideoRef, -} from "react-native-video"; +import { SelectedTrackType } from "react-native-video"; export default function page() { const { playSettings, playUrl, playSessionId } = usePlaySettings(); @@ -276,6 +270,8 @@ export default function page() { }; }, []); + const [isVideoLoaded, setIsVideoLoaded] = useState(false); + return ( { + setIsVideoLoaded(true); console.log("onVideoLoadEnd"); }} /> @@ -340,6 +337,7 @@ export default function page() { setShowControls={setShowControls} setIgnoreSafeAreas={setIgnoreSafeAreas} ignoreSafeAreas={ignoreSafeAreas} + isVideoLoaded={isVideoLoaded} /> ); diff --git a/components/video-player/Controls.tsx b/components/video-player/Controls.tsx index 65e20efd..b299d49d 100644 --- a/components/video-player/Controls.tsx +++ b/components/video-player/Controls.tsx @@ -59,6 +59,7 @@ interface Props { togglePlay: (ticks: number) => void; setShowControls: (shown: boolean) => void; offline?: boolean; + isVideoLoaded?: boolean; } export const Controls: React.FC = ({ @@ -74,6 +75,7 @@ export const Controls: React.FC = ({ setShowControls, ignoreSafeAreas, setIgnoreSafeAreas, + isVideoLoaded, offline = false, }) => { const [settings] = useSettings(); @@ -247,14 +249,6 @@ export const Controls: React.FC = ({ MediaStream | undefined >(undefined); - const allSubtitleTracks = useMemo(() => { - const subs = item.MediaStreams?.filter( - (stream) => stream.Type === "Subtitle" - ); - console.log("allSubtitleTracks", subs); - return subs; - }, [item]); - const [audioTracks, setAudioTracks] = useState(null); const [subtitleTracks, setSubtitleTracks] = useState( null @@ -273,7 +267,55 @@ export const Controls: React.FC = ({ }; fetchTracks(); - }, [videoRef]); + }, [videoRef, isVideoLoaded]); + + type EmbeddedSubtitle = { + name: string; + index: number; + isExternal: false; + }; + + type ExternalSubtitle = { + name: string; + index: number; + isExternal: true; + deliveryUrl: string; + }; + + const allSubtitleTracks = useMemo(() => { + const embeddedSubs = + subtitleTracks?.map((s) => ({ + name: s.name, + index: s.index, + isExternal: false, + deliveryUrl: undefined, + })) || []; + + const externalSubs = + item.MediaStreams?.filter( + (stream) => stream.Type === "Subtitle" && stream.IsExternal + ).map((s) => ({ + name: s.DisplayTitle!, + index: s.Index!, + isExternal: s.DeliveryMethod === "External", + deliveryUrl: s.DeliveryUrl, + })) || []; + + // Create a Set of embedded subtitle names for quick lookup + const embeddedSubNames = new Set(embeddedSubs.map((sub) => sub.name)); + + // Filter out external subs that have the same name as embedded subs + const uniqueExternalSubs = externalSubs.filter( + (sub) => !embeddedSubNames.has(sub.name) + ); + + console.log([...embeddedSubs, ...uniqueExternalSubs]); + // Combine embedded and unique external subs + return [...embeddedSubs, ...uniqueExternalSubs] as ( + | EmbeddedSubtitle + | ExternalSubtitle + )[]; + }, [item, isVideoLoaded, subtitleTracks]); return ( = ({ loop={true} sideOffset={10} > - { videoRef.current?.setSubtitleTrack(-1); }} > - + None - - {subtitleTracks?.map((sub, idx: number) => ( - { - // if(sub. === 'External') { - // videoRef.current?.setSubtitleURL( - // `https://fredflix.se/Providers/Subtitles/Subtitles/` - // ); - // } + */} + {allSubtitleTracks.length > 0 + ? allSubtitleTracks?.map((sub, idx: number) => ( + { + if (sub.isExternal) { + videoRef.current?.setSubtitleURL(sub.deliveryUrl); + console.log( + "Setting external subtitle:", + sub.deliveryUrl + ); + return; + } - videoRef.current?.setSubtitleTrack(-1); - console.log(sub); - }} - > - - - {sub.name} - - - ))} + console.log("Settings embedded subtitle", sub.name); + videoRef.current?.setSubtitleTrack(sub.index); + console.log(sub); + }} + > + + + {sub.name} + + + )) + : null} diff --git a/modules/vlc-player/ios/VlcPlayerView.swift b/modules/vlc-player/ios/VlcPlayerView.swift index d6ac186c..07565d55 100644 --- a/modules/vlc-player/ios/VlcPlayerView.swift +++ b/modules/vlc-player/ios/VlcPlayerView.swift @@ -557,7 +557,7 @@ extension VlcPlayerView: VLCMediaPlayerDelegate { } // Dermine if the media has finished loading - if currentState == .buffering && !self.isMediaReady { + if player.isPlaying && !self.isMediaReady { self.isMediaReady = true self.onVideoLoadEnd?(stateInfo) } diff --git a/utils/profiles/native.js b/utils/profiles/native.js index 472f8bcc..3aa7d8b8 100644 --- a/utils/profiles/native.js +++ b/utils/profiles/native.js @@ -260,23 +260,27 @@ export default { SubtitleProfiles: [ { Format: "pgssub", - Method: "encode", + Method: "embed", + }, + { + Format: "subrip", + Method: "embed", }, { Format: "dvdsub", - Method: "encode", + Method: "embed", }, { Format: "dvbsub", - Method: "encode", + Method: "embed", }, { Format: "xsub", - Method: "encode", + Method: "embed", }, { Format: "vtt", - Method: "hls", + Method: "embed", }, { Format: "ttml",