Fixed bug with dupe subtitle names for transcoded content

This commit is contained in:
Alex Kim
2024-11-25 15:35:05 +11:00
parent d218d0b1c2
commit 0054095b20
5 changed files with 113 additions and 66 deletions

View File

@@ -20,7 +20,13 @@ import { useQuery } from "@tanstack/react-query";
import * as Haptics from "expo-haptics";
import { useFocusEffect, useLocalSearchParams } from "expo-router";
import { useAtomValue } from "jotai";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { Pressable, useWindowDimensions, View } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import Video, {
@@ -123,6 +129,7 @@ const Player = () => {
return null;
}
console.log("getting med");
const res = await getStreamUrl({
api,
item,
@@ -259,7 +266,7 @@ const Player = () => {
// TODO: Use this when streaming with HLS url, but NOT when direct playing
// TODO: since playable duration is always 0 then.
// setIsBuffering(data.playableDuration === 0);
setIsBuffering(data.playableDuration === 0);
if (!item?.Id || data.currentTime === 0) {
return;
@@ -328,19 +335,25 @@ const Player = () => {
SelectedTrack | undefined
>(undefined);
// Set intial Subtitle Track.
// We will only select external tracks if they are are text based. Else it should be burned in already.
const textSubs =
stream?.mediaSource.MediaStreams?.filter((sub) => sub.Type === "Subtitle" && sub.IsTextSubtitleStream) || [];
stream?.mediaSource.MediaStreams?.filter(
(sub) => sub.Type === "Subtitle" && sub.IsTextSubtitleStream
) || [];
const uniqueTextSubs = Array.from(
new Set(textSubs.map((sub) => sub.DisplayTitle))
).map((title) => textSubs.find((sub) => sub.DisplayTitle === title));
const chosenSubtitleTrack = textSubs.find(
(sub) => sub.Index === subtitleIndex
);
useEffect(() => {
if (chosenSubtitleTrack && selectedTextTrack === undefined) {
console.log("Setting selected text track", chosenSubtitleTrack);
setSelectedTextTrack({
type: SelectedTrackType.INDEX,
value: textSubs.indexOf(chosenSubtitleTrack),
value: uniqueTextSubs.indexOf(chosenSubtitleTrack),
});
}
}, [embededTextTracks]);

View File

@@ -65,9 +65,6 @@ export const PlayButton: React.FC<Props> = ({
const colorChangeProgress = useSharedValue(0);
const [settings] = useSettings();
// console.log(bitrateValue);
const goToPlayer = useCallback(
(q: string, bitrateValue: number | undefined) => {
if (!bitrateValue) {

View File

@@ -12,8 +12,6 @@ import {
import { useAtomValue } from "jotai";
import { apiAtom } from "@/providers/JellyfinProvider";
import { useLocalSearchParams, useRouter } from "expo-router";
import { parse } from "@babel/core";
import { set } from "lodash";
interface DropdownViewProps {
showControls: boolean;
@@ -129,23 +127,26 @@ const DropdownView: React.FC<DropdownViewProps> = ({ showControls }) => {
);
const textSubtitlesMap = new Map(textSubtitles.map((s) => [s.name, s]));
const imageSubtitlesMap = new Map(imageSubtitles.map((s) => [s.name, s]));
const sortedSubtitles = allSubs
.map((sub) => {
const displayTitle = sub.DisplayTitle ?? "";
if (textSubtitlesMap.has(displayTitle)) {
return textSubtitlesMap.get(displayTitle);
}
if (imageSubtitlesMap.has(displayTitle)) {
return imageSubtitlesMap.get(displayTitle);
}
return null;
})
.filter(
(subtitle): subtitle is TranscodedSubtitle => subtitle !== null
);
const sortedSubtitles = Array.from(
new Set(
allSubs
.map((sub) => {
const displayTitle = sub.DisplayTitle ?? "";
if (textSubtitlesMap.has(displayTitle)) {
return textSubtitlesMap.get(displayTitle);
}
if (imageSubtitlesMap.has(displayTitle)) {
return imageSubtitlesMap.get(displayTitle);
}
return null;
})
.filter(
(subtitle): subtitle is TranscodedSubtitle => subtitle !== null
)
)
);
return [disableSubtitle, ...sortedSubtitles];
}
@@ -270,7 +271,9 @@ const DropdownView: React.FC<DropdownViewProps> = ({ showControls }) => {
value={selectedSubtitleIndex === sub.index}
key={`subtitle-item-${idx}`}
onValueChange={() => {
if (subtitleIndex === sub?.index.toString()) return;
console.log("Set sub index: ", sub.index);
if (selectedSubtitleIndex === sub?.index.toString())
return;
setSelectedSubtitleIndex(sub.index);
if (sub.IsTextSubtitleStream && isOnTextSubtitle) {
setSubtitleTrack && setSubtitleTrack(sub.index);
@@ -322,7 +325,7 @@ const DropdownView: React.FC<DropdownViewProps> = ({ showControls }) => {
key={`audio-item-${idx}`}
value={selectedAudioIndex === track.index}
onValueChange={() => {
if (audioIndex === track.index.toString()) return;
if (selectedAudioIndex === track.index.toString()) return;
setSelectedAudioIndex(track.index);
ChangeTranscodingAudio(track.index);
}}

View File

@@ -1,53 +1,89 @@
import { TrackInfo } from '@/modules/vlc-player';
import { BaseItemDto, MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client';
import React, { createContext, useContext, useState, ReactNode, useEffect } from 'react';
import { useControlContext } from './ControlContext';
import { TrackInfo } from "@/modules/vlc-player";
import {
BaseItemDto,
MediaSourceInfo,
} from "@jellyfin/sdk/lib/generated-client";
import React, {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from "react";
import { useControlContext } from "./ControlContext";
interface VideoContextProps {
audioTracks: TrackInfo[] | null;
subtitleTracks: TrackInfo[] | null;
setAudioTrack: ((index: number) => void) | undefined;
setSubtitleTrack: ((index: number) => void) | undefined;
setSubtitleURL: ((url: string, customName: string) => void) | undefined;
audioTracks: TrackInfo[] | null;
subtitleTracks: TrackInfo[] | null;
setAudioTrack: ((index: number) => void) | undefined;
setSubtitleTrack: ((index: number) => void) | undefined;
setSubtitleURL: ((url: string, customName: string) => void) | undefined;
}
const VideoContext = createContext<VideoContextProps | undefined>(undefined);
interface VideoProviderProps {
children: ReactNode;
getAudioTracks: (() => Promise<TrackInfo[] | null>) | (() => TrackInfo[]) | undefined;
getSubtitleTracks: (() => Promise<TrackInfo[] | null>) | (() => TrackInfo[]) | undefined;
getAudioTracks:
| (() => Promise<TrackInfo[] | null>)
| (() => TrackInfo[])
| undefined;
getSubtitleTracks:
| (() => Promise<TrackInfo[] | null>)
| (() => TrackInfo[])
| undefined;
setAudioTrack: ((index: number) => void) | undefined;
setSubtitleTrack: ((index: number) => void) | undefined;
setSubtitleURL: ((url: string, customName: string) => void) | undefined;
}
export const VideoProvider: React.FC<VideoProviderProps> = ({ children, getSubtitleTracks, getAudioTracks, setSubtitleTrack, setSubtitleURL, setAudioTrack }) => {
const [audioTracks, setAudioTracks] = useState<TrackInfo[] | null>(null);
const [subtitleTracks, setSubtitleTracks] = useState<TrackInfo[] | null>(
null
);
export const VideoProvider: React.FC<VideoProviderProps> = ({
children,
getSubtitleTracks,
getAudioTracks,
setSubtitleTrack,
setSubtitleURL,
setAudioTrack,
}) => {
const [audioTracks, setAudioTracks] = useState<TrackInfo[] | null>(null);
const [subtitleTracks, setSubtitleTracks] = useState<TrackInfo[] | null>(
null
);
const ControlContext = useControlContext();
const isVideoLoaded = ControlContext?.isVideoLoaded;
const ControlContext = useControlContext();
const isVideoLoaded = ControlContext?.isVideoLoaded;
useEffect(() => {
const fetchTracks = async () => {
if (getSubtitleTracks) {
const subtitles = await getSubtitleTracks();
console.log("Getting embeded subtitles...", subtitles);
setSubtitleTracks(subtitles);
}
if (getAudioTracks) {
const audio = await getAudioTracks();
setAudioTracks(audio);
}
};
fetchTracks();
}, [isVideoLoaded, getAudioTracks, getSubtitleTracks]);
useEffect(() => {
const fetchTracks = async () => {
if (
getSubtitleTracks &&
(subtitleTracks === null || subtitleTracks.length === 0)
) {
const subtitles = await getSubtitleTracks();
console.log("Getting embeded subtitles...", subtitles);
setSubtitleTracks(subtitles);
}
if (
getAudioTracks &&
(audioTracks === null || audioTracks.length === 0)
) {
const audio = await getAudioTracks();
setAudioTracks(audio);
}
};
fetchTracks();
}, [isVideoLoaded, getAudioTracks, getSubtitleTracks]);
return (
<VideoContext.Provider value={{ audioTracks, subtitleTracks, setSubtitleTrack, setSubtitleURL, setAudioTrack }}>
<VideoContext.Provider
value={{
audioTracks,
subtitleTracks,
setSubtitleTrack,
setSubtitleURL,
setAudioTrack,
}}
>
{children}
</VideoContext.Provider>
);
@@ -56,7 +92,7 @@ export const VideoProvider: React.FC<VideoProviderProps> = ({ children, getSubti
export const useVideoContext = () => {
const context = useContext(VideoContext);
if (context === undefined) {
throw new Error('useVideoContext must be used within a VideoProvider');
throw new Error("useVideoContext must be used within a VideoProvider");
}
return context;
};

View File

@@ -580,10 +580,8 @@ extension VlcPlayerView: VLCMediaPlayerDelegate {
"duration": player.media?.length.intValue ?? 0,
"error": false,
]
// Playing and not transcoding, we can let it in no HLS issue.
// We should also mark it as playing when the media is ready.
// Fix HLS issue.
if player.isPlaying && self.isMediaReady {
if player.isPlaying {
stateInfo["isPlaying"] = true
stateInfo["isBuffering"] = false
stateInfo["state"] = "Playing"