diff --git a/front/packages/models/src/resources/user.ts b/front/packages/models/src/resources/user.ts index e63b4c74..8e8be388 100644 --- a/front/packages/models/src/resources/user.ts +++ b/front/packages/models/src/resources/user.ts @@ -34,6 +34,30 @@ export const UserP = ResourceP("user").extend({ * The list of permissions of the user. The format of this is implementation dependent. */ permissions: z.array(z.string()), + /** + * User settings + */ + settings: z + .object({ + downloadQuality: z + .union([ + z.literal("original"), + z.literal("8k"), + z.literal("4k"), + z.literal("1440p"), + z.literal("1080p"), + z.literal("720p"), + z.literal("480p"), + z.literal("360p"), + z.literal("240p"), + ]) + .default("original") + .catch("original"), + audioLanguage: z.string().default("default").catch("default"), + subtitleLanguage: z.string().nullable().default(null).catch(null), + }) + // keep a default for older versions of the api + .default({}), }); export type User = z.infer; diff --git a/front/packages/ui/src/player/components/hover.tsx b/front/packages/ui/src/player/components/hover.tsx index 7420971a..528fae78 100644 --- a/front/packages/ui/src/player/components/hover.tsx +++ b/front/packages/ui/src/player/components/hover.tsx @@ -360,6 +360,7 @@ const ProgressBar = ({ url, chapters }: { url: string; chapters?: Chapter[] }) = hoverProgress ? ( diff --git a/front/packages/ui/src/settings/index.tsx b/front/packages/ui/src/settings/index.tsx index 8ba136ad..1967043d 100644 --- a/front/packages/ui/src/settings/index.tsx +++ b/front/packages/ui/src/settings/index.tsx @@ -24,12 +24,14 @@ import { ScrollView } from "react-native"; import { DefaultLayout } from "../layout"; import { AccountSettings } from "./account"; import { About, GeneralSettings } from "./general"; +import { PlaybackSettings } from "./playback"; export const SettingsPage: QueryPage = () => { const account = useAccount(); return ( + {account && } {account && } diff --git a/front/packages/ui/src/settings/playback.tsx b/front/packages/ui/src/settings/playback.tsx new file mode 100644 index 00000000..71df3d9b --- /dev/null +++ b/front/packages/ui/src/settings/playback.tsx @@ -0,0 +1,81 @@ +/* + * Kyoo - A portable and vast media library solution. + * Copyright (c) Kyoo. + * + * See AUTHORS.md and LICENSE file in the project root for full license information. + * + * Kyoo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Kyoo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kyoo. If not, see . + */ + +import { setUserTheme, useAccount } from "@kyoo/models"; +import { Select } from "@kyoo/primitives"; +import { useTranslation } from "react-i18next"; +import { Preference, SettingsContainer, useSetting } from "./base"; + +import SubtitleLanguage from "@material-symbols/svg-400/rounded/closed_caption-fill.svg"; +import AudioLanguage from "@material-symbols/svg-400/rounded/music_note-fill.svg"; + +// I gave up on finding a way to retrive this using the Intl api (probably does not exist) +// Simply copy pasted the list of languages from https://www.localeplanet.com/api/codelist.json +// prettier-ignore +const allLanguages = ["af", "agq", "ak", "am", "ar", "as", "asa", "ast", "az", "bas", "be", "bem", "bez", "bg", "bm", "bn", "bo", "br", "brx", "bs", "ca", "ccp", "ce", "cgg", "chr", "ckb", "cs", "cy", "da", "dav", "de", "dje", "dsb", "dua", "dyo", "dz", "ebu", "ee", "el", "en", "eo", "es", "et", "eu", "ewo", "fa", "ff", "fi", "fil", "fo", "fr", "fur", "fy", "ga", "gd", "gl", "gsw", "gu", "guz", "gv", "ha", "haw", "he", "hi", "hr", "hsb", "hu", "hy", "id", "ig", "ii", "is", "it", "ja", "jgo", "jmc", "ka", "kab", "kam", "kde", "kea", "khq", "ki", "kk", "kkj", "kl", "kln", "km", "kn", "ko", "kok", "ks", "ksb", "ksf", "ksh", "kw", "ky", "lag", "lb", "lg", "lkt", "ln", "lo", "lrc", "lt", "lu", "luo", "luy", "lv", "mas", "mer", "mfe", "mg", "mgh", "mgo", "mk", "ml", "mn", "mr", "ms", "mt", "mua", "my", "mzn", "naq", "nb", "nd", "nds", "ne", "nl", "nmg", "nn", "nnh", "nus", "nyn", "om", "or", "os", "pa", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "rof", "ru", "rw", "rwk", "sah", "saq", "sbp", "se", "seh", "ses", "sg", "shi", "si", "sk", "sl", "smn", "sn", "so", "sq", "sr", "sv", "sw", "ta", "te", "teo", "tg", "th", "ti", "to", "tr", "tt", "twq", "tzm", "ug", "uk", "ur", "uz", "vai", "vi", "vun", "wae", "wo", "xog", "yav", "yi", "yo", "yue", "zgh", "zh", "zu",]; + +export const PlaybackSettings = () => { + const { t, i18n } = useTranslation(); + const [audio, setAudio] = useSetting("audioLanguage")!; + const [subtitle, setSubtitle] = useSetting("subtitleLanguage")!; + const languages = new Intl.DisplayNames([i18n.language ?? "en"], { + type: "language", + languageDisplay: "standard", + }); + + return ( + + + setSubtitle(value === "none" ? null : value)} + values={["none", "default", ...allLanguages]} + getLabel={(key) => + key === "none" + ? t("settings.playback.subtitleLanguage.none") + : key === "default" + ? t("mediainfo.default") + : languages.of(key) ?? key + } + /> + + + ); +}; diff --git a/front/translations/en.json b/front/translations/en.json index a2fb01f2..e78045f1 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -92,6 +92,18 @@ "system": "System" } }, + "playback": { + "label": "Playback", + "audioLanguage": { + "label": "Audio language", + "description": "The default audio language used when playing multi-audio videos" + }, + "subtitleLanguage": { + "label": "Subtitle language", + "description": "The default subtitle language used", + "none": "None" + } + }, "account": { "label": "Account", "username": { diff --git a/front/translations/fr.json b/front/translations/fr.json index fd8aa6f1..8ab30aa8 100644 --- a/front/translations/fr.json +++ b/front/translations/fr.json @@ -92,6 +92,18 @@ "system": "Système" } }, + "playback": { + "label": "Lecteur", + "audioLanguage": { + "label": "Langue audio", + "description": "Langue audio par défaut utilisée lors de la lecture de vidéos multi-audio" + }, + "subtitleLanguage": { + "label": "Langue des sous-titres", + "description": "Langue des sous-titres utilisée par défaut", + "none": "Aucun" + } + }, "account": { "label": "Compte", "username": {