mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Use a better display name for audios
This commit is contained in:
parent
4be4fa2c4f
commit
0d4b9fe488
@ -20,6 +20,17 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { imageFn } from "../traits";
|
import { imageFn } from "../traits";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
const getDisplayName = (sub: Track) => {
|
||||||
|
const languageNames = new Intl.DisplayNames([i18next.language ?? "en"], { type: "language" });
|
||||||
|
const lng = sub.language ? languageNames.of(sub.language) : undefined;
|
||||||
|
|
||||||
|
if (lng && sub.title && sub.title !== lng) return `${lng} - ${sub.title}`;
|
||||||
|
if (lng) return lng;
|
||||||
|
if (sub.title) return sub.title;
|
||||||
|
return `Unknwon (${sub.index})`;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A audio or subtitle track.
|
* A audio or subtitle track.
|
||||||
@ -50,14 +61,23 @@ export const TrackP = z.object({
|
|||||||
*/
|
*/
|
||||||
isForced: z.boolean(),
|
isForced: z.boolean(),
|
||||||
});
|
});
|
||||||
export type Audio = z.infer<typeof TrackP>;
|
export type Track = z.infer<typeof TrackP>;
|
||||||
|
|
||||||
|
export const AudioP = TrackP.transform((x) => ({
|
||||||
|
...x,
|
||||||
|
displayName: getDisplayName(x),
|
||||||
|
}));
|
||||||
|
export type Audio = z.infer<typeof AudioP>;
|
||||||
|
|
||||||
export const SubtitleP = TrackP.extend({
|
export const SubtitleP = TrackP.extend({
|
||||||
/*
|
/*
|
||||||
* The url of this track (only if this is a subtitle)..
|
* The url of this track (only if this is a subtitle)..
|
||||||
*/
|
*/
|
||||||
link: z.string().transform(imageFn).nullable(),
|
link: z.string().transform(imageFn).nullable(),
|
||||||
});
|
}).transform((x) => ({
|
||||||
|
...x,
|
||||||
|
displayName: getDisplayName(x),
|
||||||
|
}));
|
||||||
export type Subtitle = z.infer<typeof SubtitleP>;
|
export type Subtitle = z.infer<typeof SubtitleP>;
|
||||||
|
|
||||||
export const ChapterP = z.object({
|
export const ChapterP = z.object({
|
||||||
@ -97,7 +117,7 @@ export const WatchInfoP = z.object({
|
|||||||
/**
|
/**
|
||||||
* The list of audio tracks.
|
* The list of audio tracks.
|
||||||
*/
|
*/
|
||||||
audios: z.array(TrackP),
|
audios: z.array(AudioP),
|
||||||
/**
|
/**
|
||||||
* The list of subtitles tracks.
|
* The list of subtitles tracks.
|
||||||
*/
|
*/
|
||||||
|
@ -33,7 +33,7 @@ import {
|
|||||||
tooltip,
|
tooltip,
|
||||||
ts,
|
ts,
|
||||||
} from "@kyoo/primitives";
|
} from "@kyoo/primitives";
|
||||||
import { Chapter, KyooImage, Subtitle } from "@kyoo/models";
|
import { Chapter, KyooImage, Subtitle, Audio } from "@kyoo/models";
|
||||||
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
||||||
import { ImageStyle, Platform, Pressable, View, ViewProps } from "react-native";
|
import { ImageStyle, Platform, Pressable, View, ViewProps } from "react-native";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -52,6 +52,7 @@ export const Hover = ({
|
|||||||
poster,
|
poster,
|
||||||
chapters,
|
chapters,
|
||||||
subtitles,
|
subtitles,
|
||||||
|
audios,
|
||||||
fonts,
|
fonts,
|
||||||
previousSlug,
|
previousSlug,
|
||||||
nextSlug,
|
nextSlug,
|
||||||
@ -68,6 +69,7 @@ export const Hover = ({
|
|||||||
poster?: KyooImage | null;
|
poster?: KyooImage | null;
|
||||||
chapters?: Chapter[];
|
chapters?: Chapter[];
|
||||||
subtitles?: Subtitle[];
|
subtitles?: Subtitle[];
|
||||||
|
audios?: Audio[];
|
||||||
fonts?: string[];
|
fonts?: string[];
|
||||||
previousSlug?: string | null;
|
previousSlug?: string | null;
|
||||||
nextSlug?: string | null;
|
nextSlug?: string | null;
|
||||||
@ -123,6 +125,7 @@ export const Hover = ({
|
|||||||
<LeftButtons previousSlug={previousSlug} nextSlug={nextSlug} />
|
<LeftButtons previousSlug={previousSlug} nextSlug={nextSlug} />
|
||||||
<RightButtons
|
<RightButtons
|
||||||
subtitles={subtitles}
|
subtitles={subtitles}
|
||||||
|
audios={audios}
|
||||||
fonts={fonts}
|
fonts={fonts}
|
||||||
onMenuOpen={onMenuOpen}
|
onMenuOpen={onMenuOpen}
|
||||||
onMenuClose={onMenuClose}
|
onMenuClose={onMenuClose}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Subtitle } from "@kyoo/models";
|
import { Audio, Subtitle } from "@kyoo/models";
|
||||||
import { IconButton, tooltip, Menu, ts } from "@kyoo/primitives";
|
import { IconButton, tooltip, Menu, ts } from "@kyoo/primitives";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { Platform, View } from "react-native";
|
import { Platform, View } from "react-native";
|
||||||
@ -33,23 +33,15 @@ import { fullscreenAtom, subtitleAtom } from "../state";
|
|||||||
import { AudiosMenu, QualitiesMenu } from "../video";
|
import { AudiosMenu, QualitiesMenu } from "../video";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export const getDisplayName = (sub: Subtitle) => {
|
|
||||||
const languageNames = new Intl.DisplayNames([i18next.language ?? "en"], { type: "language" });
|
|
||||||
const lng = sub.language ? languageNames.of(sub.language) : undefined;
|
|
||||||
|
|
||||||
if (lng && sub.title) return `${lng} - ${sub.title}`;
|
|
||||||
if (lng) return lng;
|
|
||||||
if (sub.title) return sub.title;
|
|
||||||
return `Unknwon (${sub.index})`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const RightButtons = ({
|
export const RightButtons = ({
|
||||||
|
audios,
|
||||||
subtitles,
|
subtitles,
|
||||||
fonts,
|
fonts,
|
||||||
onMenuOpen,
|
onMenuOpen,
|
||||||
onMenuClose,
|
onMenuClose,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
|
audios?: Audio[];
|
||||||
subtitles?: Subtitle[];
|
subtitles?: Subtitle[];
|
||||||
fonts?: string[];
|
fonts?: string[];
|
||||||
onMenuOpen: () => void;
|
onMenuOpen: () => void;
|
||||||
@ -81,7 +73,7 @@ export const RightButtons = ({
|
|||||||
{subtitles.map((x) => (
|
{subtitles.map((x) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={x.index}
|
key={x.index}
|
||||||
label={x.link ? getDisplayName(x) : `${getDisplayName(x)} (${x.codec})`}
|
label={x.link ? x.displayName : `${x.displayName} (${x.codec})`}
|
||||||
selected={selectedSubtitle === x}
|
selected={selectedSubtitle === x}
|
||||||
disabled={!x.link}
|
disabled={!x.link}
|
||||||
onSelect={() => setSubtitle(x)}
|
onSelect={() => setSubtitle(x)}
|
||||||
@ -94,6 +86,7 @@ export const RightButtons = ({
|
|||||||
icon={MusicNote}
|
icon={MusicNote}
|
||||||
onMenuOpen={onMenuOpen}
|
onMenuOpen={onMenuOpen}
|
||||||
onMenuClose={onMenuClose}
|
onMenuClose={onMenuClose}
|
||||||
|
audios={audios}
|
||||||
{...tooltip(t("player.audios"), true)}
|
{...tooltip(t("player.audios"), true)}
|
||||||
{...spacing}
|
{...spacing}
|
||||||
/>
|
/>
|
||||||
|
@ -77,6 +77,7 @@ const mapData = (
|
|||||||
href: data ? (data.type === "movie" ? `/movie/${data.slug}` : `/show/${data.show!.slug}`) : "#",
|
href: data ? (data.type === "movie" ? `/movie/${data.slug}` : `/show/${data.show!.slug}`) : "#",
|
||||||
poster: data.type === "movie" ? data.poster : data.show!.poster,
|
poster: data.type === "movie" ? data.poster : data.show!.poster,
|
||||||
subtitles: info.subtitles,
|
subtitles: info.subtitles,
|
||||||
|
audios: info.audios,
|
||||||
chapters: info.chapters,
|
chapters: info.chapters,
|
||||||
fonts: info.fonts,
|
fonts: info.fonts,
|
||||||
previousSlug,
|
previousSlug,
|
||||||
|
@ -34,7 +34,7 @@ declare module "react-native-video" {
|
|||||||
|
|
||||||
export * from "react-native-video";
|
export * from "react-native-video";
|
||||||
|
|
||||||
import { Subtitle, getToken } from "@kyoo/models";
|
import { Audio, Subtitle, getToken } from "@kyoo/models";
|
||||||
import { IconButton, Menu } from "@kyoo/primitives";
|
import { IconButton, Menu } from "@kyoo/primitives";
|
||||||
import { ComponentProps, forwardRef, useEffect, useRef } from "react";
|
import { ComponentProps, forwardRef, useEffect, useRef } from "react";
|
||||||
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
|
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||||
@ -119,7 +119,7 @@ const Video = forwardRef<NativeVideo, VideoProps>(function Video(
|
|||||||
export default Video;
|
export default Video;
|
||||||
|
|
||||||
type CustomMenu = ComponentProps<typeof Menu<ComponentProps<typeof IconButton>>>;
|
type CustomMenu = ComponentProps<typeof Menu<ComponentProps<typeof IconButton>>>;
|
||||||
export const AudiosMenu = (props: CustomMenu) => {
|
export const AudiosMenu = ({ audios, ...props }: CustomMenu & { audios?: Audio[] }) => {
|
||||||
const info = useAtomValue(infoAtom);
|
const info = useAtomValue(infoAtom);
|
||||||
const [audio, setAudio] = useAtom(audioAtom);
|
const [audio, setAudio] = useAtom(audioAtom);
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ export const AudiosMenu = (props: CustomMenu) => {
|
|||||||
{info.audioTracks.map((x) => (
|
{info.audioTracks.map((x) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={x.index}
|
key={x.index}
|
||||||
label={x.title}
|
label={audios?.[x.index].displayName ?? x.title}
|
||||||
selected={audio === x.index}
|
selected={audio === x.index}
|
||||||
onSelect={() => setAudio(x.index)}
|
onSelect={() => setAudio(x.index)}
|
||||||
/>
|
/>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getToken, Subtitle } from "@kyoo/models";
|
import { getToken, Subtitle, Audio } from "@kyoo/models";
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
RefObject,
|
RefObject,
|
||||||
@ -38,7 +38,6 @@ import Hls, { Level, LoadPolicy } from "hls.js";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Menu } from "@kyoo/primitives";
|
import { Menu } from "@kyoo/primitives";
|
||||||
import toVttBlob from "srt-webvtt";
|
import toVttBlob from "srt-webvtt";
|
||||||
import { getDisplayName } from "./components/right-buttons";
|
|
||||||
|
|
||||||
let hls: Hls | null = null;
|
let hls: Hls | null = null;
|
||||||
|
|
||||||
@ -256,7 +255,7 @@ const useSubtitle = (
|
|||||||
const addSubtitle = async () => {
|
const addSubtitle = async () => {
|
||||||
const track: HTMLTrackElement = htmlTrack ?? document.createElement("track");
|
const track: HTMLTrackElement = htmlTrack ?? document.createElement("track");
|
||||||
track.kind = "subtitles";
|
track.kind = "subtitles";
|
||||||
track.label = getDisplayName(value);
|
track.label = value.displayName;
|
||||||
if (value.language) track.srclang = value.language;
|
if (value.language) track.srclang = value.language;
|
||||||
track.src = value.codec === "subrip" ? await toWebVtt(value.link!) : value.link!;
|
track.src = value.codec === "subrip" ? await toWebVtt(value.link!) : value.link!;
|
||||||
track.className = "subtitle_container";
|
track.className = "subtitle_container";
|
||||||
@ -300,14 +299,18 @@ const toWebVtt = async (srtUrl: string) => {
|
|||||||
return await toVttBlob(srt);
|
return await toVttBlob(srt);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AudiosMenu = (props: ComponentProps<typeof Menu>) => {
|
export const AudiosMenu = ({
|
||||||
|
audios,
|
||||||
|
...props
|
||||||
|
}: ComponentProps<typeof Menu> & { audios?: Audio[] }) => {
|
||||||
if (!hls || hls.audioTracks.length < 2) return null;
|
if (!hls || hls.audioTracks.length < 2) return null;
|
||||||
|
console.log(audios);
|
||||||
return (
|
return (
|
||||||
<Menu {...props}>
|
<Menu {...props}>
|
||||||
{hls.audioTracks.map((x, i) => (
|
{hls.audioTracks.map((x, i) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={i.toString()}
|
key={i.toString()}
|
||||||
label={x.name}
|
label={audios?.[i].displayName ?? x.name}
|
||||||
selected={hls!.audioTrack === i}
|
selected={hls!.audioTrack === i}
|
||||||
onSelect={() => (hls!.audioTrack = i)}
|
onSelect={() => (hls!.audioTrack = i)}
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user