mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Handle audio settings
This commit is contained in:
parent
0be1bf4f15
commit
92a3c2945c
@ -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}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user