Handle audio settings

This commit is contained in:
Zoe Roux 2024-01-30 01:04:19 +01:00
parent 0be1bf4f15
commit 92a3c2945c
4 changed files with 47 additions and 12 deletions

View File

@ -63,7 +63,6 @@ const mapData = (
fonts: info?.fonts,
previousSlug,
nextSlug,
qualitiesAvailables: !!data.links.hls,
};
};
@ -139,6 +138,7 @@ export const Player = ({ slug, type }: { slug: string; type: "episode" | "movie"
>
<Video
links={data?.links}
audios={info?.audios}
subtitles={info?.subtitles}
setError={setPlaybackError}
fonts={info?.fonts}

View File

@ -18,7 +18,7 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { Episode, Subtitle, useAccount } from "@kyoo/models";
import { Audio, Episode, Subtitle, useAccount } from "@kyoo/models";
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
import { useAtomCallback } from "jotai/utils";
import { ElementRef, memo, useEffect, useLayoutEffect, useRef, useState, useCallback } from "react";
@ -83,10 +83,12 @@ export const fullscreenAtom = atom(
const privateFullscreen = atom(false);
export const subtitleAtom = atom<Subtitle | null>(null);
export const audioAtom = atom<Audio>({ index: 0 } as Audio);
export const Video = memo(function Video({
links,
subtitles,
audios,
setError,
fonts,
startTime: startTimeP,
@ -94,6 +96,7 @@ export const Video = memo(function Video({
}: {
links?: Episode["links"];
subtitles?: Subtitle[];
audios?: Audio[];
setError: (error: string | undefined) => void;
fonts?: string[];
startTime?: number | null;
@ -152,6 +155,26 @@ export const Video = memo(function Video({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [subtitles, setSubtitle, defaultSubLanguage, ref.current]);
const defaultAudioLanguage = account?.settings.audioLanguage ?? "default";
const setAudio = useSetAtom(audioAtom);
useEffect(() => {
if (!audios) return;
setAudio((audio) => {
if (audio) {
const ret = audios.find((x) => x.language === audio.language);
if (ret) return ret;
}
if (defaultAudioLanguage !== "default") {
const ret = audios.find((x) => x.language === defaultAudioLanguage);
if (ret) return ret;
}
return audios.find((x) => x.isDefault) ?? audios[0];
});
// When the video change, try to persist the subtitle language.
// Also include the player ref, it can be initalised after the subtitles.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [audios, setAudio, defaultAudioLanguage, ref.current]);
const volume = useAtomValue(volumeAtom);
const isMuted = useAtomValue(mutedAtom);

View File

@ -40,7 +40,7 @@ import { ComponentProps, forwardRef, useEffect, useRef } from "react";
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
import NativeVideo, { OnLoadData, VideoProps } from "react-native-video";
import { useTranslation } from "react-i18next";
import { PlayMode, playModeAtom, subtitleAtom } from "./state";
import { PlayMode, audioAtom, playModeAtom, subtitleAtom } from "./state";
import uuid from "react-native-uuid";
import { View } from "react-native";
import "@kyoo/primitives/src/types.d.ts";
@ -54,7 +54,6 @@ const MimeTypes: Map<string, string> = new Map([
const infoAtom = atom<OnLoadData | null>(null);
const videoAtom = atom(0);
const audioAtom = atom(0);
const clientId = uuid.v4() as string;
@ -94,7 +93,7 @@ const Video = forwardRef<NativeVideo, VideoProps>(function Video(
}}
onBuffer={onBuffer}
selectedVideoTrack={video === -1 ? { type: "auto" } : { type: "resolution", value: video }}
selectedAudioTrack={{ type: "index", value: audio }}
selectedAudioTrack={{ type: "index", value: audio.index }}
textTracks={subtitles?.map((x) => ({
type: MimeTypes.get(x.codec) as any,
uri: x.link!,
@ -130,8 +129,8 @@ export const AudiosMenu = ({ audios, ...props }: CustomMenu & { audios?: Audio[]
<Menu.Item
key={x.index}
label={audios?.[x.index].displayName ?? x.title}
selected={audio === x.index}
onSelect={() => setAudio(x.index)}
selected={audio!.index === x.index}
onSelect={() => setAudio(x as any)}
/>
))}
</Menu>

View File

@ -26,14 +26,13 @@ import {
useImperativeHandle,
useLayoutEffect,
useRef,
useReducer,
ComponentProps,
} from "react";
import { VideoProps } from "react-native-video";
import { useAtomValue, useSetAtom, useAtom } from "jotai";
import { useForceRerender, useYoshiki } from "yoshiki";
import Jassub from "jassub";
import { playAtom, PlayMode, playModeAtom, progressAtom, subtitleAtom } from "./state";
import { audioAtom, playAtom, PlayMode, playModeAtom, progressAtom, subtitleAtom } from "./state";
import Hls, { Level, LoadPolicy } from "hls.js";
import { useTranslation } from "react-i18next";
import { Menu, tooltip } from "@kyoo/primitives";
@ -180,6 +179,19 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [source.uri, source.hls]);
const mode = useAtomValue(playModeAtom);
const audio = useAtomValue(audioAtom);
useEffect(() => {
if (!hls) return;
const update = () => {
if (!hls) return;
hls.audioTrack = audio.index;
};
update();
hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, update);
return () => hls?.off(Hls.Events.AUDIO_TRACKS_UPDATED, update);
}, [audio, mode]);
const setPlay = useSetAtom(playAtom);
useEffect(() => {
if (!ref.current) return;
@ -334,6 +346,7 @@ export const AudiosMenu = ({
}: ComponentProps<typeof Menu<{ disabled?: boolean }>> & { audios?: Audio[] }) => {
const { t } = useTranslation();
const rerender = useForceRerender();
const [_, setAudio] = useAtom(audioAtom);
// force rerender when mode changes
useAtomValue(playModeAtom);
@ -343,8 +356,8 @@ export const AudiosMenu = ({
return () => hls!.off(Hls.Events.AUDIO_TRACK_LOADED, rerender);
});
if (!hls || hls.audioTracks.length < 2)
return <Menu {...props} disabled {...tooltip(t("player.notInPristine"))} />;
if (!hls) return <Menu {...props} disabled {...tooltip(t("player.notInPristine"))} />;
if (hls.audioTracks.length < 2) return null;
return (
<Menu {...props}>
@ -353,7 +366,7 @@ export const AudiosMenu = ({
key={i.toString()}
label={audios?.[i].displayName ?? x.name}
selected={hls!.audioTrack === i}
onSelect={() => (hls!.audioTrack = i)}
onSelect={() => setAudio(audios?.[i] ?? ({ index: i } as any))}
/>
))}
</Menu>