mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 15:48:05 +00:00
feat: add "Are you still watching" modal overlay with configurable options (#663)
Co-authored-by: Fredrik Burmester <fredrik.burmester@gmail.com>
This commit is contained in:
@@ -66,11 +66,14 @@ export const PlayButton: React.FC<Props> = ({
|
||||
const startColor = useSharedValue(colorAtom);
|
||||
const widthProgress = useSharedValue(0);
|
||||
const colorChangeProgress = useSharedValue(0);
|
||||
const [settings] = useSettings();
|
||||
const [settings, updateSettings] = useSettings();
|
||||
const lightHapticFeedback = useHaptic("light");
|
||||
|
||||
const goToPlayer = useCallback(
|
||||
(q: string) => {
|
||||
if (settings.maxAutoPlayEpisodeCount.value !== -1) {
|
||||
updateSettings({ autoPlayEpisodeCount: 0 });
|
||||
}
|
||||
router.push(`/player/direct-player?${q}`);
|
||||
},
|
||||
[router],
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "@/utils/background-tasks";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useRouter } from "expo-router";
|
||||
import i18n, { TFunction } from "i18next";
|
||||
import type React from "react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -251,7 +252,46 @@ export const OtherSettings: React.FC = () => {
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem title={t("home.settings.other.max_auto_play_episode_count")}>
|
||||
<Dropdown
|
||||
data={AUTOPLAY_EPISODES_COUNT(t)}
|
||||
keyExtractor={(item) => item.key}
|
||||
titleExtractor={(item) => item.key}
|
||||
title={
|
||||
<TouchableOpacity className='flex flex-row items-center justify-between py-3 pl-3'>
|
||||
<Text className='mr-1 text-[#8E8D91]'>
|
||||
{t(settings?.maxAutoPlayEpisodeCount.key)}
|
||||
</Text>
|
||||
<Ionicons
|
||||
name='chevron-expand-sharp'
|
||||
size={18}
|
||||
color='#5A5960'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
}
|
||||
label={t("home.settings.other.max_auto_play_episode_count")}
|
||||
onSelected={(maxAutoPlayEpisodeCount) =>
|
||||
updateSettings({ maxAutoPlayEpisodeCount })
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</ListGroup>
|
||||
</DisabledSetting>
|
||||
);
|
||||
};
|
||||
|
||||
const AUTOPLAY_EPISODES_COUNT = (
|
||||
t: TFunction<"translation", undefined>,
|
||||
): {
|
||||
key: string;
|
||||
value: number;
|
||||
}[] => [
|
||||
{ key: t("home.settings.other.disabled"), value: -1 },
|
||||
{ key: "1", value: 1 },
|
||||
{ key: "2", value: 2 },
|
||||
{ key: "3", value: 3 },
|
||||
{ key: "4", value: 4 },
|
||||
{ key: "5", value: 5 },
|
||||
{ key: "6", value: 6 },
|
||||
{ key: "7", value: 7 },
|
||||
];
|
||||
|
||||
49
components/video-player/controls/ContinueWatchingOverlay.tsx
Normal file
49
components/video-player/controls/ContinueWatchingOverlay.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Button } from "@/components/Button";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { useRouter } from "expo-router";
|
||||
import { t } from "i18next";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
|
||||
export interface ContinueWatchingOverlayProps {
|
||||
goToNextItem: (options: {
|
||||
isAutoPlay: boolean;
|
||||
resetWatchCount: boolean;
|
||||
}) => void;
|
||||
}
|
||||
|
||||
const ContinueWatchingOverlay: React.FC<ContinueWatchingOverlayProps> = ({
|
||||
goToNextItem,
|
||||
}) => {
|
||||
const [settings] = useSettings();
|
||||
const router = useRouter();
|
||||
|
||||
return settings.autoPlayEpisodeCount >=
|
||||
settings.maxAutoPlayEpisodeCount.value ? (
|
||||
<View
|
||||
className={
|
||||
"absolute top-0 bottom-0 left-0 right-0 flex flex-col px-4 items-center justify-center bg-[#000000B3]"
|
||||
}
|
||||
>
|
||||
<Text className='text-2xl font-bold text-white py-4 '>
|
||||
Are you still watching ?
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => {
|
||||
goToNextItem({ isAutoPlay: false, resetWatchCount: true });
|
||||
}}
|
||||
color={"purple"}
|
||||
className='my-4 w-2/3'
|
||||
>
|
||||
{t("player.continue_watching")}
|
||||
</Button>
|
||||
|
||||
<Button onPress={router.back} color={"transparent"} className='w-2/3'>
|
||||
{t("player.go_back")}
|
||||
</Button>
|
||||
</View>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default ContinueWatchingOverlay;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Loader } from "@/components/Loader";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import ContinueWatchingOverlay from "@/components/video-player/controls/ContinueWatchingOverlay";
|
||||
import { useAdjacentItems } from "@/hooks/useAdjacentEpisodes";
|
||||
import { useCreditSkipper } from "@/hooks/useCreditSkipper";
|
||||
import { useHaptic } from "@/hooks/useHaptic";
|
||||
@@ -28,7 +29,7 @@ import { Image } from "expo-image";
|
||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { useAtom } from "jotai";
|
||||
import { debounce } from "lodash";
|
||||
import {
|
||||
import React, {
|
||||
type Dispatch,
|
||||
type FC,
|
||||
type MutableRefObject,
|
||||
@@ -121,7 +122,7 @@ export const Controls: FC<Props> = ({
|
||||
enableTrickplay = true,
|
||||
isVlc = false,
|
||||
}) => {
|
||||
const [settings] = useSettings();
|
||||
const [settings, updateSettings] = useSettings();
|
||||
const router = useRouter();
|
||||
const insets = useSafeAreaInsets();
|
||||
const [api] = useAtom(apiAtom);
|
||||
@@ -236,15 +237,76 @@ export const Controls: FC<Props> = ({
|
||||
goToItemCommon(previousItem);
|
||||
}, [previousItem, goToItemCommon]);
|
||||
|
||||
const goToNextItem = useCallback(() => {
|
||||
if (!nextItem) return;
|
||||
goToItemCommon(nextItem);
|
||||
}, [nextItem, goToItemCommon]);
|
||||
const goToNextItem = useCallback(
|
||||
({
|
||||
isAutoPlay,
|
||||
resetWatchCount,
|
||||
}: { isAutoPlay?: boolean; resetWatchCount?: boolean }) => {
|
||||
if (!nextItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAutoPlay) {
|
||||
// if we are not autoplaying, we won't update anything, we just go to the next item
|
||||
goToItemCommon(nextItem);
|
||||
if (resetWatchCount) {
|
||||
updateSettings({
|
||||
autoPlayEpisodeCount: 0,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip autoplay logic if maxAutoPlayEpisodeCount is -1
|
||||
if (settings.maxAutoPlayEpisodeCount.value === -1) {
|
||||
goToItemCommon(nextItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
settings.autoPlayEpisodeCount + 1 <
|
||||
settings.maxAutoPlayEpisodeCount.value
|
||||
) {
|
||||
goToItemCommon(nextItem);
|
||||
}
|
||||
|
||||
// Check if the autoPlayEpisodeCount is less than maxAutoPlayEpisodeCount for the autoPlay
|
||||
if (
|
||||
settings.autoPlayEpisodeCount < settings.maxAutoPlayEpisodeCount.value
|
||||
) {
|
||||
// update the autoPlayEpisodeCount in settings
|
||||
updateSettings({
|
||||
autoPlayEpisodeCount: settings.autoPlayEpisodeCount + 1,
|
||||
});
|
||||
}
|
||||
},
|
||||
[nextItem, goToItemCommon],
|
||||
);
|
||||
|
||||
// Add a memoized handler for autoplay next episode
|
||||
const handleNextEpisodeAutoPlay = useCallback(() => {
|
||||
goToNextItem({ isAutoPlay: true });
|
||||
}, [goToNextItem]);
|
||||
|
||||
// Add a memoized handler for manual next episode
|
||||
const handleNextEpisodeManual = useCallback(() => {
|
||||
goToNextItem({ isAutoPlay: false });
|
||||
}, [goToNextItem]);
|
||||
|
||||
// Add a memoized handler for ContinueWatchingOverlay
|
||||
const handleContinueWatching = useCallback(
|
||||
(options: { isAutoPlay?: boolean; resetWatchCount?: boolean }) => {
|
||||
goToNextItem(options);
|
||||
},
|
||||
[goToNextItem],
|
||||
);
|
||||
|
||||
const goToItem = useCallback(
|
||||
async (itemId: string) => {
|
||||
const gotoItem = await getItemById(api, itemId);
|
||||
if (!gotoItem) return;
|
||||
if (!gotoItem) {
|
||||
return;
|
||||
}
|
||||
goToItemCommon(gotoItem);
|
||||
},
|
||||
[goToItemCommon, api],
|
||||
@@ -300,7 +362,9 @@ export const Controls: FC<Props> = ({
|
||||
};
|
||||
|
||||
const handleSliderStart = useCallback(() => {
|
||||
if (!showControls) return;
|
||||
if (!showControls) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSliding(true);
|
||||
wasPlayingRef.current = isPlaying;
|
||||
@@ -339,7 +403,9 @@ export const Controls: FC<Props> = ({
|
||||
);
|
||||
|
||||
const handleSkipBackward = useCallback(async () => {
|
||||
if (!settings?.rewindSkipTime) return;
|
||||
if (!settings?.rewindSkipTime) {
|
||||
return;
|
||||
}
|
||||
wasPlayingRef.current = isPlaying;
|
||||
lightHapticFeedback();
|
||||
try {
|
||||
@@ -371,7 +437,9 @@ export const Controls: FC<Props> = ({
|
||||
? curr + secondsToMs(settings.forwardSkipTime)
|
||||
: ticksToSeconds(curr) + settings.forwardSkipTime;
|
||||
seek(Math.max(0, newTime));
|
||||
if (wasPlayingRef.current) play();
|
||||
if (wasPlayingRef.current) {
|
||||
play();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
writeToLog("ERROR", "Error seeking video forwards", error);
|
||||
@@ -546,7 +614,7 @@ export const Controls: FC<Props> = ({
|
||||
|
||||
{nextItem && !offline && (
|
||||
<TouchableOpacity
|
||||
onPress={goToNextItem}
|
||||
onPress={() => goToNextItem({ isAutoPlay: false })}
|
||||
className='aspect-square flex flex-col rounded-xl items-center justify-center p-2'
|
||||
>
|
||||
<Ionicons name='play-skip-forward' size={24} color='white' />
|
||||
@@ -741,17 +809,21 @@ export const Controls: FC<Props> = ({
|
||||
onPress={skipCredit}
|
||||
buttonText='Skip Credits'
|
||||
/>
|
||||
<NextEpisodeCountDownButton
|
||||
show={
|
||||
!nextItem
|
||||
? false
|
||||
: isVlc
|
||||
? remainingTime < 10000
|
||||
: remainingTime < 10
|
||||
}
|
||||
onFinish={goToNextItem}
|
||||
onPress={goToNextItem}
|
||||
/>
|
||||
{(settings.maxAutoPlayEpisodeCount.value === -1 ||
|
||||
settings.autoPlayEpisodeCount <
|
||||
settings.maxAutoPlayEpisodeCount.value) && (
|
||||
<NextEpisodeCountDownButton
|
||||
show={
|
||||
!nextItem
|
||||
? false
|
||||
: isVlc
|
||||
? remainingTime < 10000
|
||||
: remainingTime < 10
|
||||
}
|
||||
onFinish={handleNextEpisodeAutoPlay}
|
||||
onPress={handleNextEpisodeManual}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
@@ -799,6 +871,9 @@ export const Controls: FC<Props> = ({
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{settings.maxAutoPlayEpisodeCount.value !== -1 && (
|
||||
<ContinueWatchingOverlay goToNextItem={handleContinueWatching} />
|
||||
)}
|
||||
</ControlProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ const NextEpisodeCountDownButton: React.FC<NextEpisodeCountDownButtonProps> = ({
|
||||
>
|
||||
<Animated.View style={animatedStyle} />
|
||||
<View className='px-3 py-3'>
|
||||
<Text className='text-center font-bold'>
|
||||
<Text numberOfLines={1} className='text-center font-bold'>
|
||||
{t("player.next_episode")}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
2
i18n.ts
2
i18n.ts
@@ -11,8 +11,8 @@ import ja from "./translations/ja.json";
|
||||
import nl from "./translations/nl.json";
|
||||
import pl from "./translations/pl.json";
|
||||
import ptBR from "./translations/pt-BR.json";
|
||||
import sv from "./translations/sv.json";
|
||||
import ru from "./translations/ru.json";
|
||||
import sv from "./translations/sv.json";
|
||||
import tr from "./translations/tr.json";
|
||||
import uk from "./translations/uk.json";
|
||||
import zhCN from "./translations/zh-CN.json";
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Bibliotheken ausblenden",
|
||||
"select_liraries_you_want_to_hide": "Wähl die Bibliotheken aus, die du im Bibliothekstab und auf der Startseite ausblenden möchtest.",
|
||||
"disable_haptic_feedback": "Haptisches Feedback deaktivieren",
|
||||
"default_quality": "Standardqualität"
|
||||
"default_quality": "Standardqualität",
|
||||
"disabled": "Deaktiviert"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Downloads",
|
||||
@@ -370,7 +371,9 @@
|
||||
"audio_tracks": "Audiospuren:",
|
||||
"playback_state": "Wiedergabestatus:",
|
||||
"no_data_available": "Keine Daten verfügbar",
|
||||
"index": "Index:"
|
||||
"index": "Index:",
|
||||
"continue_watching": "Weiterschauen",
|
||||
"go_back": "Zurück"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Als Nächstes",
|
||||
|
||||
@@ -138,7 +138,9 @@
|
||||
"hide_libraries": "Hide Libraries",
|
||||
"select_liraries_you_want_to_hide": "Select the libraries you want to hide from the Library tab and home page sections.",
|
||||
"disable_haptic_feedback": "Disable Haptic Feedback",
|
||||
"default_quality": "Default quality"
|
||||
"default_quality": "Default quality",
|
||||
"max_auto_play_episode_count": "Max auto play episode count",
|
||||
"disabled": "Disabled"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Downloads",
|
||||
@@ -374,7 +376,9 @@
|
||||
"audio_tracks": "Audio Tracks:",
|
||||
"playback_state": "Playback State:",
|
||||
"no_data_available": "No data available",
|
||||
"index": "Index:"
|
||||
"index": "Index:",
|
||||
"continue_watching": "Continue Watching",
|
||||
"go_back": "Go back"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Next up",
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Ocultar bibliotecas",
|
||||
"select_liraries_you_want_to_hide": "Selecciona las bibliotecas que quieres ocultar de la pestaña Bibliotecas y de Inicio.",
|
||||
"disable_haptic_feedback": "Desactivar feedback háptico",
|
||||
"default_quality": "Calidad por defecto"
|
||||
"default_quality": "Calidad por defecto",
|
||||
"disabled": "Deshabilitado"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Descargas",
|
||||
@@ -370,7 +371,9 @@
|
||||
"audio_tracks": "Pistas de audio:",
|
||||
"playback_state": "Estado de la reproducción:",
|
||||
"no_data_available": "No hay datos disponibles",
|
||||
"index": "Índice:"
|
||||
"index": "Índice:",
|
||||
"continue_watching": "Continuar viendo",
|
||||
"go_back": "Volver"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "A continuación",
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Cacher des bibliothèques",
|
||||
"select_liraries_you_want_to_hide": "Sélectionnez les bibliothèques que vous souhaitez masquer dans l'onglet Bibliothèque et les sections de la page d'accueil.",
|
||||
"disable_haptic_feedback": "Désactiver le retour haptique",
|
||||
"default_quality": "Qualité par défaut"
|
||||
"default_quality": "Qualité par défaut",
|
||||
"disabled": "Désactivé"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Téléchargements",
|
||||
@@ -370,7 +371,9 @@
|
||||
"audio_tracks": "Pistes audio:",
|
||||
"playback_state": "État de lecture:",
|
||||
"no_data_available": "Aucune donnée disponible",
|
||||
"index": "Index:"
|
||||
"index": "Index :",
|
||||
"continue_watching": "Continuer à regarder",
|
||||
"go_back": "Retour"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "À suivre",
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Nascondi Librerie",
|
||||
"select_liraries_you_want_to_hide": "Selezionate le librerie che volete nascondere dalla scheda Libreria e dalle sezioni della pagina iniziale.",
|
||||
"disable_haptic_feedback": "Disabilita il feedback aptico",
|
||||
"default_quality": "Qualità predefinita"
|
||||
"default_quality": "Qualità predefinita",
|
||||
"disabled": "Disabilitato"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Scaricamento",
|
||||
@@ -370,7 +371,9 @@
|
||||
"audio_tracks": "Tracce audio:",
|
||||
"playback_state": "Stato della riproduzione:",
|
||||
"no_data_available": "Nessun dato disponibile",
|
||||
"index": "Indice:"
|
||||
"index": "Indice:",
|
||||
"continue_watching": "Continua a guardare",
|
||||
"go_back": "Indietro"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Il prossimo",
|
||||
|
||||
@@ -152,7 +152,9 @@
|
||||
"optimized_version_hint": "OptimizeサーバーのURLを入力します。URLにはhttpまたはhttpsを含め、オプションでポートを指定します。",
|
||||
"read_more_about_optimized_server": "Optimizeサーバーの詳細をご覧ください。",
|
||||
"url": "URL",
|
||||
"server_url_placeholder": "http(s)://domain.org:ポート"
|
||||
"server_url_placeholder": "http(s)://domain.org:ポート",
|
||||
"default_quality": "デフォルトの品質",
|
||||
"disabled": "無効"
|
||||
},
|
||||
"plugins": {
|
||||
"plugins_title": "プラグイン",
|
||||
@@ -369,7 +371,9 @@
|
||||
"audio_tracks": "音声トラック:",
|
||||
"playback_state": "再生状態:",
|
||||
"no_data_available": "データなし",
|
||||
"index": "インデックス:"
|
||||
"index": "インデックス:",
|
||||
"continue_watching": "視聴を続ける",
|
||||
"go_back": "戻る"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "次",
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Verberg Bibliotheken",
|
||||
"select_liraries_you_want_to_hide": "Selecteer de bibliotheken die je wil verbergen van de Bibliotheektab en hoofdpagina onderdelen.",
|
||||
"disable_haptic_feedback": "Haptische feedback uitschakelen",
|
||||
"default_quality": "Standaard kwaliteit"
|
||||
"default_quality": "Standaard kwaliteit",
|
||||
"disabled": "Uitgeschakeld"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Downloads",
|
||||
@@ -370,7 +371,9 @@
|
||||
"audio_tracks": "Audio Tracks:",
|
||||
"playback_state": "Afspeelstatus:",
|
||||
"no_data_available": "Geen data beschikbaar",
|
||||
"index": "Index:"
|
||||
"index": "Index:",
|
||||
"continue_watching": "Verder kijken",
|
||||
"go_back": "Terug"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Volgende",
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Ukryj biblioteki",
|
||||
"select_liraries_you_want_to_hide": "Wybierz biblioteki, które chcesz ukryć na karcie Biblioteka i w sekcjach strony głównej.",
|
||||
"disable_haptic_feedback": "Wyłącz wibracje",
|
||||
"default_quality": "Domyślna jakość"
|
||||
"default_quality": "Domyślna jakość",
|
||||
"disabled": "Wyłączone"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Pobieranie",
|
||||
@@ -374,7 +375,9 @@
|
||||
"audio_tracks": "Ścieżki audio:",
|
||||
"playback_state": "Stan odtwarzania:",
|
||||
"no_data_available": "Brak dostępnych danych",
|
||||
"index": "Indeks:"
|
||||
"index": "Indeks:",
|
||||
"continue_watching": "Kontynuuj oglądanie",
|
||||
"go_back": "Wstecz"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Następne",
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
"hide_libraries": "Ocultar bibliotecas",
|
||||
"select_liraries_you_want_to_hide": "Selecione as bibliotecas que você deseja ocultar das abas Biblioteca e Início.",
|
||||
"disable_haptic_feedback": "Desativar o feedback háptico",
|
||||
"default_quality": "Qualidade padrão"
|
||||
"default_quality": "Qualidade padrão",
|
||||
"disabled": "Desativado"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Downloads",
|
||||
@@ -371,7 +372,9 @@
|
||||
"audio_tracks": "Faixas do áudio:",
|
||||
"playback_state": "Playback State:",
|
||||
"no_data_available": "Nenhum dado disponível",
|
||||
"index": "Índice:"
|
||||
"index": "Índice:",
|
||||
"continue_watching": "Continuar assistindo",
|
||||
"go_back": "Voltar"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Próximo em",
|
||||
|
||||
@@ -1,478 +1,480 @@
|
||||
{
|
||||
"login": {
|
||||
"username_required": "Имя пользователя обязательно",
|
||||
"error_title": "Ошибка",
|
||||
"login_title": "Вход",
|
||||
"login_to_title": "Вход в",
|
||||
"username_placeholder": "Имя пользователя",
|
||||
"password_placeholder": "Пароль",
|
||||
"login_button": "Войти",
|
||||
"quick_connect": "Быстрое подключение",
|
||||
"enter_code_to_login": "Введите код {{code}} чтобы войти",
|
||||
"failed_to_initiate_quick_connect": "Не удалось инициировать быстрое подключение",
|
||||
"got_it": "Принято",
|
||||
"connection_failed": "Соединение не удалось",
|
||||
"could_not_connect_to_server": "Не удалось подключиться к серверу. Пожалуйста проверьте URL и ваше интернет соединение.",
|
||||
"an_unexpected_error_occured": "Возникла непредвиденная ошибка",
|
||||
"change_server": "Поменять сервер",
|
||||
"invalid_username_or_password": "Неправильное имя пользователя или пароль",
|
||||
"user_does_not_have_permission_to_log_in": "Пользователь не имеет прав на вход",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Сервер долго не отвечает, попробуйте позже.",
|
||||
"server_received_too_many_requests_try_again_later": "Сервер получил слишком много запросов, попробуйте позже.",
|
||||
"there_is_a_server_error": "Возникла ошибка сервера",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Возникла непредвиденная ошибка. Вы правильно ввели URL?"
|
||||
"login": {
|
||||
"username_required": "Имя пользователя обязательно",
|
||||
"error_title": "Ошибка",
|
||||
"login_title": "Вход",
|
||||
"login_to_title": "Вход в",
|
||||
"username_placeholder": "Имя пользователя",
|
||||
"password_placeholder": "Пароль",
|
||||
"login_button": "Войти",
|
||||
"quick_connect": "Быстрое подключение",
|
||||
"enter_code_to_login": "Введите код {{code}} чтобы войти",
|
||||
"failed_to_initiate_quick_connect": "Не удалось инициировать быстрое подключение",
|
||||
"got_it": "Принято",
|
||||
"connection_failed": "Соединение не удалось",
|
||||
"could_not_connect_to_server": "Не удалось подключиться к серверу. Пожалуйста проверьте URL и ваше интернет соединение.",
|
||||
"an_unexpected_error_occured": "Возникла непредвиденная ошибка",
|
||||
"change_server": "Поменять сервер",
|
||||
"invalid_username_or_password": "Неправильное имя пользователя или пароль",
|
||||
"user_does_not_have_permission_to_log_in": "Пользователь не имеет прав на вход",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Сервер долго не отвечает, попробуйте позже.",
|
||||
"server_received_too_many_requests_try_again_later": "Сервер получил слишком много запросов, попробуйте позже.",
|
||||
"there_is_a_server_error": "Возникла ошибка сервера",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Возникла непредвиденная ошибка. Вы правильно ввели URL?"
|
||||
},
|
||||
"server": {
|
||||
"enter_url_to_jellyfin_server": "Укажите URL на ваш Jellyfin сервер",
|
||||
"server_url_placeholder": "http(s)://your-server.com",
|
||||
"connect_button": "Подключиться",
|
||||
"previous_servers": "предыдущие серверы",
|
||||
"clear_button": "Очистить",
|
||||
"search_for_local_servers": "Поиск локальных серверов",
|
||||
"searching": "Поиск...",
|
||||
"servers": "Сервера"
|
||||
},
|
||||
"home": {
|
||||
"no_internet": "Нет интернета",
|
||||
"no_items": "Нет элементов",
|
||||
"no_internet_message": "Не переживайте, Вы всё ещё можете смотреть\nскачанный контент.",
|
||||
"go_to_downloads": "В загрузки",
|
||||
"oops": "Упс!",
|
||||
"error_message": "Что-то пошло не так.\nПожалуйста выйдите и зайдите снова.",
|
||||
"continue_watching": "Продолжить просмотр",
|
||||
"next_up": "Следующее",
|
||||
"recently_added_in": "Недавно добавлено в {{libraryName}}",
|
||||
"suggested_movies": "Предложенные фильмы",
|
||||
"suggested_episodes": "Предложенные серии",
|
||||
"intro": {
|
||||
"welcome_to_streamyfin": "Добро пожаловать в Streamyfin",
|
||||
"a_free_and_open_source_client_for_jellyfin": "Бесплатный клиент для Jellyfin с открытым кодом",
|
||||
"features_title": "Функции",
|
||||
"features_description": "Streamyfin имеет множество функций и интегрируется с широким спектром программ, которое вы можете найти в меню настроек:",
|
||||
"jellyseerr_feature_description": "Подключитесь к Jellyseerr и запрашивайте фильмы прямо в приложении.",
|
||||
"downloads_feature_title": "Загрузки",
|
||||
"downloads_feature_description": "Скачивайте фильмы и сериалы для просмотра без интернета. Используйте стандартный способ или установите сервер оптимизации для загрузки файлов в фоновом режиме.",
|
||||
"chromecast_feature_description": "Транслируйте фильмы и сериалы на ваши устройста с поддержкой Chromecast.",
|
||||
"centralised_settings_plugin_title": "Плагин для централизованной настройки",
|
||||
"centralised_settings_plugin_description": "Настраивайте параметры из централизованного места на сервере Jellyfin. Все настройки клиента для всех пользователей будут синхронизированы автоматически.",
|
||||
"done_button": "Готово",
|
||||
"go_to_settings_button": "Перейти в настройки",
|
||||
"read_more": "Узнать больше"
|
||||
},
|
||||
"server": {
|
||||
"enter_url_to_jellyfin_server": "Укажите URL на ваш Jellyfin сервер",
|
||||
"server_url_placeholder": "http(s)://your-server.com",
|
||||
"connect_button": "Подключиться",
|
||||
"previous_servers": "предыдущие серверы",
|
||||
"clear_button": "Очистить",
|
||||
"search_for_local_servers": "Поиск локальных серверов",
|
||||
"searching": "Поиск...",
|
||||
"servers": "Сервера"
|
||||
},
|
||||
"home": {
|
||||
"no_internet": "Нет интернета",
|
||||
"no_items": "Нет элементов",
|
||||
"no_internet_message": "Не переживайте, Вы всё ещё можете смотреть\nскачанный контент.",
|
||||
"go_to_downloads": "В загрузки",
|
||||
"oops": "Упс!",
|
||||
"error_message": "Что-то пошло не так.\nПожалуйста выйдите и зайдите снова.",
|
||||
"continue_watching": "Продолжить просмотр",
|
||||
"next_up": "Следующее",
|
||||
"recently_added_in": "Недавно добавлено в {{libraryName}}",
|
||||
"suggested_movies": "Предложенные фильмы",
|
||||
"suggested_episodes": "Предложенные серии",
|
||||
"intro": {
|
||||
"welcome_to_streamyfin": "Добро пожаловать в Streamyfin",
|
||||
"a_free_and_open_source_client_for_jellyfin": "Бесплатный клиент для Jellyfin с открытым кодом",
|
||||
"features_title": "Функции",
|
||||
"features_description": "Streamyfin имеет множество функций и интегрируется с широким спектром программ, которое вы можете найти в меню настроек:",
|
||||
"jellyseerr_feature_description": "Подключитесь к Jellyseerr и запрашивайте фильмы прямо в приложении.",
|
||||
"downloads_feature_title": "Загрузки",
|
||||
"downloads_feature_description": "Скачивайте фильмы и сериалы для просмотра без интернета. Используйте стандартный способ или установите сервер оптимизации для загрузки файлов в фоновом режиме.",
|
||||
"chromecast_feature_description": "Транслируйте фильмы и сериалы на ваши устройста с поддержкой Chromecast.",
|
||||
"centralised_settings_plugin_title": "Плагин для централизованной настройки",
|
||||
"centralised_settings_plugin_description": "Настраивайте параметры из централизованного места на сервере Jellyfin. Все настройки клиента для всех пользователей будут синхронизированы автоматически.",
|
||||
"done_button": "Готово",
|
||||
"go_to_settings_button": "Перейти в настройки",
|
||||
"read_more": "Узнать больше"
|
||||
"settings": {
|
||||
"settings_title": "Настройки",
|
||||
"log_out_button": "Выйти",
|
||||
"user_info": {
|
||||
"user_info_title": "Информация о пользователе",
|
||||
"user": "Пользователь",
|
||||
"server": "Сервер",
|
||||
"token": "Токен",
|
||||
"app_version": "Версия приложения"
|
||||
},
|
||||
"settings": {
|
||||
"settings_title": "Настройки",
|
||||
"log_out_button": "Выйти",
|
||||
"user_info": {
|
||||
"user_info_title": "Информация о пользователе",
|
||||
"user": "Пользователь",
|
||||
"server": "Сервер",
|
||||
"token": "Токен",
|
||||
"app_version": "Версия приложения"
|
||||
},
|
||||
"quick_connect": {
|
||||
"quick_connect_title": "Быстрое подключение",
|
||||
"authorize_button": "Авторизировать через быстрое подключение",
|
||||
"enter_the_quick_connect_code": "Введите код для быстрого подключения...",
|
||||
"success": "Успех",
|
||||
"quick_connect_autorized": "Быстрое подключение авторизовано",
|
||||
"error": "Ошибка",
|
||||
"invalid_code": "Неверный код",
|
||||
"authorize": "Авторизировать"
|
||||
},
|
||||
"media_controls": {
|
||||
"media_controls_title": "Медиа-контроль",
|
||||
"forward_skip_length": "Длина пропуска вперед",
|
||||
"rewind_length": "Длина перемотки",
|
||||
"seconds_unit": "c"
|
||||
},
|
||||
"audio": {
|
||||
"audio_title": "Аудио",
|
||||
"set_audio_track": "Устанавливать аудио дорожку из предыдущего элемента",
|
||||
"audio_language": "Язык аудио",
|
||||
"audio_hint": "Выберите стандартный язык аудио.",
|
||||
"none": "Отсутствует",
|
||||
"language": "Язык"
|
||||
},
|
||||
"subtitles": {
|
||||
"subtitle_title": "Субтитры",
|
||||
"subtitle_language": "Язык субтитров",
|
||||
"subtitle_mode": "Режим субтитров",
|
||||
"set_subtitle_track": "Устанавливать субтитры из предыдущего элемента",
|
||||
"subtitle_size": "Размер субтитров",
|
||||
"subtitle_hint": "Настроить субтитры.",
|
||||
"none": "Отсутствует",
|
||||
"language": "Язык",
|
||||
"loading": "Загрузка",
|
||||
"modes": {
|
||||
"Default": "Стандартный",
|
||||
"Smart": "Умный",
|
||||
"Always": "Всегда",
|
||||
"None": "Отсутствует",
|
||||
"OnlyForced": "Только принудительные"
|
||||
}
|
||||
},
|
||||
"other": {
|
||||
"other_title": "Другое",
|
||||
"follow_device_orientation": "Авто-поворот",
|
||||
"video_orientation": "Ориентация видео",
|
||||
"orientation": "Ориентация",
|
||||
"orientations": {
|
||||
"DEFAULT": "Стандартный",
|
||||
"ALL": "Все",
|
||||
"PORTRAIT": "Портретный",
|
||||
"PORTRAIT_UP": "Портрет вверх",
|
||||
"PORTRAIT_DOWN": "Портрет вниз",
|
||||
"LANDSCAPE": "Ландшафтный",
|
||||
"LANDSCAPE_LEFT": "Ландшафтный слева",
|
||||
"LANDSCAPE_RIGHT": "Ландшафтный справа",
|
||||
"OTHER": "Другое",
|
||||
"UNKNOWN": "Неизвестное"
|
||||
},
|
||||
"safe_area_in_controls": "Безопасная зона в элементах управления",
|
||||
"video_player": "Видео прейер",
|
||||
"video_players": {
|
||||
"VLC_3": "VLC 3",
|
||||
"VLC_4": "VLC 4 (Экспериментальный + PiP)"
|
||||
},
|
||||
"show_custom_menu_links": "Показать ссылки кастомного меню",
|
||||
"hide_libraries": "Скрыть библиотеки",
|
||||
"select_liraries_you_want_to_hide": "Выберите Библиотеки, которое хотите спрятать из вкладки Библиотеки и домашней страницы.",
|
||||
"disable_haptic_feedback": "Отключить тактильную обратную связь",
|
||||
"default_quality": "Качество по умолчанию"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Загрузки",
|
||||
"download_method": "способ загрузки",
|
||||
"remux_max_download": "Remux max скачать",
|
||||
"auto_download": "Авто-загрузка",
|
||||
"optimized_versions_server": "Оптимизированные версии сервера",
|
||||
"save_button": "Сохранить",
|
||||
"optimized_server": "Оптимизированный сервер",
|
||||
"optimized": "Оптимизированный",
|
||||
"default": "По умолчанию",
|
||||
"optimized_version_hint": "Укажите URL на оптимизированный сервер. URL должен включать http or https и опционально порт.",
|
||||
"read_more_about_optimized_server": "Узнать больше про оптимизацию сервера.",
|
||||
"url": "URL",
|
||||
"server_url_placeholder": "http(s)://domain.org:port"
|
||||
},
|
||||
"plugins": {
|
||||
"plugins_title": "Плагины",
|
||||
"jellyseerr": {
|
||||
"jellyseerr_warning": "Эта интеграция находится на ранней стадии. Ожидайте изменений.",
|
||||
"server_url": "URL сервера",
|
||||
"server_url_hint": "Пример: http(s)://your-host.url\n(Добавьте порт если необходимо)",
|
||||
"server_url_placeholder": "Jellyseerr URL...",
|
||||
"password": "Пароль",
|
||||
"password_placeholder": "Введите пароль для пользователя Jellyfin {{username}}",
|
||||
"save_button": "Сохранить",
|
||||
"clear_button": "Очистить",
|
||||
"login_button": "Войти",
|
||||
"total_media_requests": "Всего запросов на медиа",
|
||||
"movie_quota_limit": "Ограничение квоты на фильмы",
|
||||
"movie_quota_days": "Дни квоты на фильмы",
|
||||
"tv_quota_limit": "Ограничение квоты на сериалы",
|
||||
"tv_quota_days": "Дни квоты на сериалы",
|
||||
"reset_jellyseerr_config_button": "Сбросить конфигурацию Jellyseerr",
|
||||
"unlimited": "Неограниченно",
|
||||
"plus_n_more": "+{{n}} больше",
|
||||
"order_by": {
|
||||
"DEFAULT": "По умолчанию",
|
||||
"VOTE_COUNT_AND_AVERAGE": "Количеству голосов и среднему",
|
||||
"POPULARITY": "Популярности"
|
||||
}
|
||||
},
|
||||
"marlin_search": {
|
||||
"enable_marlin_search": "Включить Marlin Search ",
|
||||
"url": "URL",
|
||||
"server_url_placeholder": "http(s)://domain.org:port",
|
||||
"marlin_search_hint": "Введите URL для Marlin сервера. URL должен включать http or https и опционально порт.",
|
||||
"read_more_about_marlin": "Узнать больше о Marlin.",
|
||||
"save_button": "Сохранить",
|
||||
"toasts": {
|
||||
"saved": "Сохранено"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage": {
|
||||
"storage_title": "Хранилище",
|
||||
"app_usage": "Приложение {{usedSpace}}%",
|
||||
"device_usage": "Устройство {{availableSpace}}%",
|
||||
"size_used": "{{used}} из {{total}} использовано",
|
||||
"delete_all_downloaded_files": "Удалить все загруженные файлы",
|
||||
},
|
||||
"intro": {
|
||||
"show_intro": "Показать вступление",
|
||||
"reset_intro": "Сбросить вступление"
|
||||
},
|
||||
"logs": {
|
||||
"logs_title": "Логи",
|
||||
"no_logs_available": "Логи не доступны",
|
||||
"delete_all_logs": "Удалить все логи",
|
||||
},
|
||||
"languages": {
|
||||
"title": "Языки",
|
||||
"app_language": "Язык приложения",
|
||||
"app_language_description": "Выберите язык для приложения.",
|
||||
"system": "Системный"
|
||||
},
|
||||
"toasts": {
|
||||
"error_deleting_files": "Ошибка при удалении файлов",
|
||||
"background_downloads_enabled": "Фоновая загрузка включена",
|
||||
"background_downloads_disabled": "Фоновая загрузка отключена",
|
||||
"connected": "Подключено",
|
||||
"could_not_connect": "Не удалось подключиться",
|
||||
"invalid_url": "Неверный URL"
|
||||
"quick_connect": {
|
||||
"quick_connect_title": "Быстрое подключение",
|
||||
"authorize_button": "Авторизировать через быстрое подключение",
|
||||
"enter_the_quick_connect_code": "Введите код для быстрого подключения...",
|
||||
"success": "Успех",
|
||||
"quick_connect_autorized": "Быстрое подключение авторизовано",
|
||||
"error": "Ошибка",
|
||||
"invalid_code": "Неверный код",
|
||||
"authorize": "Авторизировать"
|
||||
},
|
||||
"media_controls": {
|
||||
"media_controls_title": "Медиа-контроль",
|
||||
"forward_skip_length": "Длина пропуска вперед",
|
||||
"rewind_length": "Длина перемотки",
|
||||
"seconds_unit": "c"
|
||||
},
|
||||
"audio": {
|
||||
"audio_title": "Аудио",
|
||||
"set_audio_track": "Устанавливать аудио дорожку из предыдущего элемента",
|
||||
"audio_language": "Язык аудио",
|
||||
"audio_hint": "Выберите стандартный язык аудио.",
|
||||
"none": "Отсутствует",
|
||||
"language": "Язык"
|
||||
},
|
||||
"subtitles": {
|
||||
"subtitle_title": "Субтитры",
|
||||
"subtitle_language": "Язык субтитров",
|
||||
"subtitle_mode": "Режим субтитров",
|
||||
"set_subtitle_track": "Устанавливать субтитры из предыдущего элемента",
|
||||
"subtitle_size": "Размер субтитров",
|
||||
"subtitle_hint": "Настроить субтитры.",
|
||||
"none": "Отсутствует",
|
||||
"language": "Язык",
|
||||
"loading": "Загрузка",
|
||||
"modes": {
|
||||
"Default": "Стандартный",
|
||||
"Smart": "Умный",
|
||||
"Always": "Всегда",
|
||||
"None": "Отсутствует",
|
||||
"OnlyForced": "Только принудительные"
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"title": "Сессии",
|
||||
"no_active_sessions": "Нет активных сессий",
|
||||
"other": {
|
||||
"other_title": "Другое",
|
||||
"follow_device_orientation": "Авто-поворот",
|
||||
"video_orientation": "Ориентация видео",
|
||||
"orientation": "Ориентация",
|
||||
"orientations": {
|
||||
"DEFAULT": "Стандартный",
|
||||
"ALL": "Все",
|
||||
"PORTRAIT": "Портретный",
|
||||
"PORTRAIT_UP": "Портрет вверх",
|
||||
"PORTRAIT_DOWN": "Портрет вниз",
|
||||
"LANDSCAPE": "Ландшафтный",
|
||||
"LANDSCAPE_LEFT": "Ландшафтный слева",
|
||||
"LANDSCAPE_RIGHT": "Ландшафтный справа",
|
||||
"OTHER": "Другое",
|
||||
"UNKNOWN": "Неизвестное"
|
||||
},
|
||||
"safe_area_in_controls": "Безопасная зона в элементах управления",
|
||||
"video_player": "Видео прейер",
|
||||
"video_players": {
|
||||
"VLC_3": "VLC 3",
|
||||
"VLC_4": "VLC 4 (Экспериментальный + PiP)"
|
||||
},
|
||||
"show_custom_menu_links": "Показать ссылки кастомного меню",
|
||||
"hide_libraries": "Скрыть библиотеки",
|
||||
"select_liraries_you_want_to_hide": "Выберите Библиотеки, которое хотите спрятать из вкладки Библиотеки и домашней страницы.",
|
||||
"disable_haptic_feedback": "Отключить тактильную обратную связь",
|
||||
"default_quality": "Качество по умолчанию",
|
||||
"disabled": "Отключено"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Загрузки",
|
||||
"tvseries": "Сериалы",
|
||||
"movies": "Фильмы",
|
||||
"queue": "Очередь",
|
||||
"queue_hint": "Очередь и загрузки будут удалены при перезагрузке приложения",
|
||||
"no_items_in_queue": "Нет элементов в очереди",
|
||||
"no_downloaded_items": "Нет загруженых предметов",
|
||||
"delete_all_movies_button": "Удалить все фильмы",
|
||||
"delete_all_tvseries_button": "Удалить все сериалы",
|
||||
"delete_all_button": "Удалить все",
|
||||
"active_download": "Активно загружается",
|
||||
"no_active_downloads": "Нет активных загрузок",
|
||||
"active_downloads": "Активные загрузки",
|
||||
"new_app_version_requires_re_download": "Новая версия приложения требует повторной загрузки",
|
||||
"new_app_version_requires_re_download_description": "Новая версия приложения требует повторной загрузки. Пожалуйста удалите всё и попробуйте заново.",
|
||||
"back": "Назад",
|
||||
"delete": "Удалить",
|
||||
"something_went_wrong": "Что-то пошло не так",
|
||||
"could_not_get_stream_url_from_jellyfin": "Не удалось получить ссылку трансляции из Jellyfin",
|
||||
"eta": "ETA {{eta}}",
|
||||
"methods": "Методы",
|
||||
"toasts": {
|
||||
"you_are_not_allowed_to_download_files": "Нет разрешения на скачивание файлов.",
|
||||
"deleted_all_movies_successfully": "Все фильмы были успешно удалены!",
|
||||
"failed_to_delete_all_movies": "Возникла ошибка при удалении всех фильмов",
|
||||
"deleted_all_tvseries_successfully": "Все сериалы были успешно удалены!",
|
||||
"failed_to_delete_all_tvseries": "Возникла ошибка при удалении всех сериалов",
|
||||
"download_cancelled": "Загрузка отменена",
|
||||
"could_not_cancel_download": "Не удалось отменить загрузку",
|
||||
"download_completed": "Загрузка завершена",
|
||||
"download_started_for": "Загрузка {{item}} началась",
|
||||
"item_is_ready_to_be_downloaded": "{{item}} готов к загрузке",
|
||||
"download_stated_for_item": "Загрузка {{item} началась",
|
||||
"download_failed_for_item": "Загрузка {{item}} провалилась с ошибкой: {{error}}",
|
||||
"download_completed_for_item": "{{item}} успешно загружен",
|
||||
"queued_item_for_optimization": "{{item}} поставлен в очередь для оптимизации",
|
||||
"failed_to_start_download_for_item": "Не удалось начать загрузку {{item}}: {{message}}",
|
||||
"server_responded_with_status_code": "Сервер ответил со статусом {{statusCode}}",
|
||||
"no_response_received_from_server": "Нет ответа от сервера",
|
||||
"error_setting_up_the_request": "Ошибка при создании запроса",
|
||||
"failed_to_start_download_for_item_unexpected_error": "Не удалось начать загрузку {{item}}: Неожиданная ошибка",
|
||||
"all_files_folders_and_jobs_deleted_successfully": "Все файлы, папки, и задачи были успешно удалены",
|
||||
"an_error_occured_while_deleting_files_and_jobs": "Возникла ошибка при удалении файлов и работ",
|
||||
"go_to_downloads": "В загрузки"
|
||||
"download_method": "способ загрузки",
|
||||
"remux_max_download": "Remux max скачать",
|
||||
"auto_download": "Авто-загрузка",
|
||||
"optimized_versions_server": "Оптимизированные версии сервера",
|
||||
"save_button": "Сохранить",
|
||||
"optimized_server": "Оптимизированный сервер",
|
||||
"optimized": "Оптимизированный",
|
||||
"default": "По умолчанию",
|
||||
"optimized_version_hint": "Укажите URL на оптимизированный сервер. URL должен включать http or https и опционально порт.",
|
||||
"read_more_about_optimized_server": "Узнать больше про оптимизацию сервера.",
|
||||
"url": "URL",
|
||||
"server_url_placeholder": "http(s)://domain.org:port"
|
||||
},
|
||||
"plugins": {
|
||||
"plugins_title": "Плагины",
|
||||
"jellyseerr": {
|
||||
"jellyseerr_warning": "Эта интеграция находится на ранней стадии. Ожидайте изменений.",
|
||||
"server_url": "URL сервера",
|
||||
"server_url_hint": "Пример: http(s)://your-host.url\n(Добавьте порт если необходимо)",
|
||||
"server_url_placeholder": "Jellyseerr URL...",
|
||||
"password": "Пароль",
|
||||
"password_placeholder": "Введите пароль для пользователя Jellyfin {{username}}",
|
||||
"save_button": "Сохранить",
|
||||
"clear_button": "Очистить",
|
||||
"login_button": "Войти",
|
||||
"total_media_requests": "Всего запросов на медиа",
|
||||
"movie_quota_limit": "Ограничение квоты на фильмы",
|
||||
"movie_quota_days": "Дни квоты на фильмы",
|
||||
"tv_quota_limit": "Ограничение квоты на сериалы",
|
||||
"tv_quota_days": "Дни квоты на сериалы",
|
||||
"reset_jellyseerr_config_button": "Сбросить конфигурацию Jellyseerr",
|
||||
"unlimited": "Неограниченно",
|
||||
"plus_n_more": "+{{n}} больше",
|
||||
"order_by": {
|
||||
"DEFAULT": "По умолчанию",
|
||||
"VOTE_COUNT_AND_AVERAGE": "Количеству голосов и среднему",
|
||||
"POPULARITY": "Популярности"
|
||||
}
|
||||
},
|
||||
"marlin_search": {
|
||||
"enable_marlin_search": "Включить Marlin Search ",
|
||||
"url": "URL",
|
||||
"server_url_placeholder": "http(s)://domain.org:port",
|
||||
"marlin_search_hint": "Введите URL для Marlin сервера. URL должен включать http or https и опционально порт.",
|
||||
"read_more_about_marlin": "Узнать больше о Marlin.",
|
||||
"save_button": "Сохранить",
|
||||
"toasts": {
|
||||
"saved": "Сохранено"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"search_here": "Искать здесь...",
|
||||
"search": "Поиск...",
|
||||
"x_items": "{{count}} предметов",
|
||||
"library": "Библиотека",
|
||||
"discover": "Найти новое",
|
||||
"no_results": "Нет результатов",
|
||||
"no_results_found_for": "Не было результатов при поиске",
|
||||
"movies": "Фильмы",
|
||||
"series": "Сериалы",
|
||||
"episodes": "Серии",
|
||||
"collections": "Коллекции",
|
||||
"actors": "Актеры",
|
||||
"request_movies": "Запросить фильмы",
|
||||
"request_series": "Запросить сериалы",
|
||||
"recently_added": "Недавно добавлено",
|
||||
"recent_requests": "Недавно запрошено",
|
||||
"plex_watchlist": "Список просмотра с Plex",
|
||||
"trending": "В тренде",
|
||||
"popular_movies": "Популярные фильмы",
|
||||
"movie_genres": "Популярные жанры",
|
||||
"upcoming_movies": "Предстоящие фильмы",
|
||||
"studios": "Студии",
|
||||
"popular_tv": "Популярные сериалы",
|
||||
"tv_genres": "жанры сериалов",
|
||||
"upcoming_tv": "Предстоящие сериалы",
|
||||
"networks": "Сети",
|
||||
"tmdb_movie_keyword": "TMDB Ключевые слова фильмов",
|
||||
"tmdb_movie_genre": "TMDB Жанры фильмов",
|
||||
"tmdb_tv_keyword": "TMDB Ключевые слова сериалов",
|
||||
"tmdb_tv_genre": "TMDB Жанры сериалов",
|
||||
"tmdb_search": "TMDB Поиск",
|
||||
"tmdb_studio": "TMDB Студии",
|
||||
"tmdb_network": "TMDB Сеть",
|
||||
"tmdb_movie_streaming_services": "TMDB Потоковые сервисы фильмов",
|
||||
"tmdb_tv_streaming_services": "TMDB Потоковые сервисы сериалов",
|
||||
},
|
||||
"library": {
|
||||
"no_items_found": "элементы не найдены",
|
||||
"no_results": "Нет результатов",
|
||||
"no_libraries_found": "Библиотеки не найдены",
|
||||
"item_types": {
|
||||
"movies": "фильмы",
|
||||
"series": "Сериалы",
|
||||
"boxsets": "Коллекции",
|
||||
"items": "элементы"
|
||||
},
|
||||
"options": {
|
||||
"display": "Отображать",
|
||||
"row": "Ряд",
|
||||
"list": "Список",
|
||||
"image_style": "Стиль изображения",
|
||||
"poster": "Постер",
|
||||
"cover": "Обложка",
|
||||
"show_titles": "Показывать загаловки",
|
||||
"show_stats": "Показывать статистику",
|
||||
"storage": {
|
||||
"storage_title": "Хранилище",
|
||||
"app_usage": "Приложение {{usedSpace}}%",
|
||||
"device_usage": "Устройство {{availableSpace}}%",
|
||||
"size_used": "{{used}} из {{total}} использовано",
|
||||
"delete_all_downloaded_files": "Удалить все загруженные файлы"
|
||||
},
|
||||
"intro": {
|
||||
"show_intro": "Показать вступление",
|
||||
"reset_intro": "Сбросить вступление"
|
||||
},
|
||||
"logs": {
|
||||
"logs_title": "Логи",
|
||||
"no_logs_available": "Логи не доступны",
|
||||
"delete_all_logs": "Удалить все логи"
|
||||
},
|
||||
"languages": {
|
||||
"title": "Языки",
|
||||
"app_language": "Язык приложения",
|
||||
"app_language_description": "Выберите язык для приложения.",
|
||||
"system": "Системный"
|
||||
},
|
||||
"filters": {
|
||||
"genres": "Жанры",
|
||||
"years": "Года",
|
||||
"sort_by": "Сортировать по",
|
||||
"sort_order": "Порядок сортировки",
|
||||
"asc": "По Возрастанию",
|
||||
"desc": "По убыванию",
|
||||
"tags": "Тэги"
|
||||
}
|
||||
},
|
||||
"favorites": {
|
||||
"series": "Сериалы",
|
||||
"movies": "Фильмы",
|
||||
"episodes": "Серии",
|
||||
"videos": "Видео",
|
||||
"boxsets": "Коллекции",
|
||||
"playlists": "Плейлисты",
|
||||
"noDataTitle": "Пока нет избранных",
|
||||
"noData": "Отметьте элементы как избранные, чтобы они отображались здесь для быстрого доступа."
|
||||
},
|
||||
"custom_links": {
|
||||
"no_links": "Нет ссылок"
|
||||
},
|
||||
"player": {
|
||||
"error": "Ошибка",
|
||||
"failed_to_get_stream_url": "Не удалось получить URL потока",
|
||||
"an_error_occured_while_playing_the_video": "Возникла Неожиданная ошибка во время воспроизведения. Проверьте логи в настройках.",
|
||||
"client_error": "Ошибка клиента",
|
||||
"could_not_create_stream_for_chromecast": "Не удалось создать поток для Chromecast",
|
||||
"message_from_server": "Сообщение от сервера: {{message}}",
|
||||
"video_has_finished_playing": "Видео закончило воспроизводиться!",
|
||||
"no_video_source": "Нет источника видео...",
|
||||
"next_episode": "Следующая серия",
|
||||
"refresh_tracks": "Обновить дорожки",
|
||||
"subtitle_tracks": "Субтитры:",
|
||||
"audio_tracks": "Аудио дорожки:",
|
||||
"playback_state": "Состояние воспроизведения:",
|
||||
"no_data_available": "Данные не доступны",
|
||||
"index": "Индекс:"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Следующее",
|
||||
"no_items_to_display": "Нет элементов для отображения",
|
||||
"cast_and_crew": "Актеры и съемочная группа",
|
||||
"series": "Серии",
|
||||
"seasons": "Сезоны",
|
||||
"season": "Сезон",
|
||||
"no_episodes_for_this_season": "В этом сезоне нет серий",
|
||||
"overview": "Обзор",
|
||||
"more_with": "Больше с {{name}}",
|
||||
"similar_items": "Похожие элементы",
|
||||
"no_similar_items_found": "Похожие элементы не найдены",
|
||||
"video": "Видео",
|
||||
"more_details": "Больше деталей",
|
||||
"quality": "Качество",
|
||||
"audio": "Звук",
|
||||
"subtitles": "Субтитры",
|
||||
"show_more": "Показать больше",
|
||||
"show_less": "Показать меньше",
|
||||
"appeared_in": "Появлялся в",
|
||||
"could_not_load_item": "Не удалось загрузить элемент",
|
||||
"none": "Отсутствует",
|
||||
"download": {
|
||||
"download_season": "Загрузить сезон",
|
||||
"download_series": "Загрузить сериал",
|
||||
"download_episode": "Загрузить серию",
|
||||
"download_movie": "Скачать фильм",
|
||||
"download_x_item": "Загрузить {{item_count}} элементов",
|
||||
"download_button": "Загрузить",
|
||||
"using_optimized_server": "Использовать оптимизированный сервер",
|
||||
"using_default_method": "Использовать стандартный метод",
|
||||
}
|
||||
},
|
||||
"live_tv": {
|
||||
"next": "Следующая",
|
||||
"previous": "Предыдущая",
|
||||
"live_tv": "Прямой эфир ТВ",
|
||||
"coming_soon": "Скоро",
|
||||
"on_now": "Сейчас в эфире",
|
||||
"shows": "Сериалы",
|
||||
"movies": "Фильмы",
|
||||
"sports": "Спорт",
|
||||
"for_kids": "Для детей",
|
||||
"news": "Новости"
|
||||
},
|
||||
"jellyseerr": {
|
||||
"confirm": "Подтвердить",
|
||||
"cancel": "Отменить",
|
||||
"yes": "Да",
|
||||
"whats_wrong": "В чем дело?",
|
||||
"issue_type": "Вид проблемы",
|
||||
"select_an_issue": "Выберите проблему",
|
||||
"types": "Типы",
|
||||
"describe_the_issue": "(опционально) Опишите проблему...",
|
||||
"submit_button": "Подать",
|
||||
"report_issue_button": "Сообщить о проблеме",
|
||||
"request_button": "Запросить",
|
||||
"are_you_sure_you_want_to_request_all_seasons": "Вы уверены, что хотите запросить все сезоны?",
|
||||
"failed_to_login": "Не удалось войти",
|
||||
"cast": "Транслировать",
|
||||
"details": "Детали",
|
||||
"status": "Статус",
|
||||
"original_title": "Оригинальное название",
|
||||
"series_type": "Тип сериала",
|
||||
"release_dates": "Дата релиза",
|
||||
"first_air_date": "Первая дата выхода в эфир",
|
||||
"next_air_date": "Следующая дата выхода в эфир",
|
||||
"revenue": "Прибыль",
|
||||
"budget": "Бюджет",
|
||||
"original_language": "Оригинальный язык",
|
||||
"production_country": "Страна производства",
|
||||
"studios": "Студия",
|
||||
"network": "Сеть",
|
||||
"currently_streaming_on": "Сейчас доступно на",
|
||||
"advanced": "Продвинутое",
|
||||
"request_as": "Запросить как",
|
||||
"tags": "Тэги",
|
||||
"quality_profile": "Профиль качества",
|
||||
"root_folder": "Корневая папка",
|
||||
"season_all": "Сезон (все)",
|
||||
"season_number": "Сезон {{season_number}}",
|
||||
"number_episodes": "{{episode_number}} серий",
|
||||
"born": "Рожден",
|
||||
"appearances": "Появления",
|
||||
"toasts": {
|
||||
"jellyseer_does_not_meet_requirements": "Сервер Jellyseerr не соответствует минимальным требованиям версии! Пожалуйста, обновите до версии не ниже 2.0.0",
|
||||
"jellyseerr_test_failed": "Тест Jellyseerr не пройден. Попробуйте еще раз.",
|
||||
"failed_to_test_jellyseerr_server_url": "Не удалось проверить URL-адрес сервера jellyseerr",
|
||||
"issue_submitted": "Проблема отправлена!",
|
||||
"requested_item": "Запрошено {{item}}!",
|
||||
"you_dont_have_permission_to_request": "У вас нет разрешения на запрос!",
|
||||
"something_went_wrong_requesting_media": "Что-то пошло не так при запросе медиафайлов!"
|
||||
"error_deleting_files": "Ошибка при удалении файлов",
|
||||
"background_downloads_enabled": "Фоновая загрузка включена",
|
||||
"background_downloads_disabled": "Фоновая загрузка отключена",
|
||||
"connected": "Подключено",
|
||||
"could_not_connect": "Не удалось подключиться",
|
||||
"invalid_url": "Неверный URL"
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
"home": "Дом",
|
||||
"search": "Поиск",
|
||||
"library": "Библиотека",
|
||||
"custom_links": "Кастомные ссылки",
|
||||
"favorites": "Избранное"
|
||||
"sessions": {
|
||||
"title": "Сессии",
|
||||
"no_active_sessions": "Нет активных сессий"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Загрузки",
|
||||
"tvseries": "Сериалы",
|
||||
"movies": "Фильмы",
|
||||
"queue": "Очередь",
|
||||
"queue_hint": "Очередь и загрузки будут удалены при перезагрузке приложения",
|
||||
"no_items_in_queue": "Нет элементов в очереди",
|
||||
"no_downloaded_items": "Нет загруженых предметов",
|
||||
"delete_all_movies_button": "Удалить все фильмы",
|
||||
"delete_all_tvseries_button": "Удалить все сериалы",
|
||||
"delete_all_button": "Удалить все",
|
||||
"active_download": "Активно загружается",
|
||||
"no_active_downloads": "Нет активных загрузок",
|
||||
"active_downloads": "Активные загрузки",
|
||||
"new_app_version_requires_re_download": "Новая версия приложения требует повторной загрузки",
|
||||
"new_app_version_requires_re_download_description": "Новая версия приложения требует повторной загрузки. Пожалуйста удалите всё и попробуйте заново.",
|
||||
"back": "Назад",
|
||||
"delete": "Удалить",
|
||||
"something_went_wrong": "Что-то пошло не так",
|
||||
"could_not_get_stream_url_from_jellyfin": "Не удалось получить ссылку трансляции из Jellyfin",
|
||||
"eta": "ETA {{eta}}",
|
||||
"methods": "Методы",
|
||||
"toasts": {
|
||||
"you_are_not_allowed_to_download_files": "Нет разрешения на скачивание файлов.",
|
||||
"deleted_all_movies_successfully": "Все фильмы были успешно удалены!",
|
||||
"failed_to_delete_all_movies": "Возникла ошибка при удалении всех фильмов",
|
||||
"deleted_all_tvseries_successfully": "Все сериалы были успешно удалены!",
|
||||
"failed_to_delete_all_tvseries": "Возникла ошибка при удалении всех сериалов",
|
||||
"download_cancelled": "Загрузка отменена",
|
||||
"could_not_cancel_download": "Не удалось отменить загрузку",
|
||||
"download_completed": "Загрузка завершена",
|
||||
"download_started_for": "Загрузка {{item}} началась",
|
||||
"item_is_ready_to_be_downloaded": "{{item}} готов к загрузке",
|
||||
"download_stated_for_item": "Загрузка {{item} началась",
|
||||
"download_failed_for_item": "Загрузка {{item}} провалилась с ошибкой: {{error}}",
|
||||
"download_completed_for_item": "{{item}} успешно загружен",
|
||||
"queued_item_for_optimization": "{{item}} поставлен в очередь для оптимизации",
|
||||
"failed_to_start_download_for_item": "Не удалось начать загрузку {{item}}: {{message}}",
|
||||
"server_responded_with_status_code": "Сервер ответил со статусом {{statusCode}}",
|
||||
"no_response_received_from_server": "Нет ответа от сервера",
|
||||
"error_setting_up_the_request": "Ошибка при создании запроса",
|
||||
"failed_to_start_download_for_item_unexpected_error": "Не удалось начать загрузку {{item}}: Неожиданная ошибка",
|
||||
"all_files_folders_and_jobs_deleted_successfully": "Все файлы, папки, и задачи были успешно удалены",
|
||||
"an_error_occured_while_deleting_files_and_jobs": "Возникла ошибка при удалении файлов и работ",
|
||||
"go_to_downloads": "В загрузки"
|
||||
}
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"search_here": "Искать здесь...",
|
||||
"search": "Поиск...",
|
||||
"x_items": "{{count}} предметов",
|
||||
"library": "Библиотека",
|
||||
"discover": "Найти новое",
|
||||
"no_results": "Нет результатов",
|
||||
"no_results_found_for": "Не было результатов при поиске",
|
||||
"movies": "Фильмы",
|
||||
"series": "Сериалы",
|
||||
"episodes": "Серии",
|
||||
"collections": "Коллекции",
|
||||
"actors": "Актеры",
|
||||
"request_movies": "Запросить фильмы",
|
||||
"request_series": "Запросить сериалы",
|
||||
"recently_added": "Недавно добавлено",
|
||||
"recent_requests": "Недавно запрошено",
|
||||
"plex_watchlist": "Список просмотра с Plex",
|
||||
"trending": "В тренде",
|
||||
"popular_movies": "Популярные фильмы",
|
||||
"movie_genres": "Популярные жанры",
|
||||
"upcoming_movies": "Предстоящие фильмы",
|
||||
"studios": "Студии",
|
||||
"popular_tv": "Популярные сериалы",
|
||||
"tv_genres": "жанры сериалов",
|
||||
"upcoming_tv": "Предстоящие сериалы",
|
||||
"networks": "Сети",
|
||||
"tmdb_movie_keyword": "TMDB Ключевые слова фильмов",
|
||||
"tmdb_movie_genre": "TMDB Жанры фильмов",
|
||||
"tmdb_tv_keyword": "TMDB Ключевые слова сериалов",
|
||||
"tmdb_tv_genre": "TMDB Жанры сериалов",
|
||||
"tmdb_search": "TMDB Поиск",
|
||||
"tmdb_studio": "TMDB Студии",
|
||||
"tmdb_network": "TMDB Сеть",
|
||||
"tmdb_movie_streaming_services": "TMDB Потоковые сервисы фильмов",
|
||||
"tmdb_tv_streaming_services": "TMDB Потоковые сервисы сериалов"
|
||||
},
|
||||
"library": {
|
||||
"no_items_found": "элементы не найдены",
|
||||
"no_results": "Нет результатов",
|
||||
"no_libraries_found": "Библиотеки не найдены",
|
||||
"item_types": {
|
||||
"movies": "фильмы",
|
||||
"series": "Сериалы",
|
||||
"boxsets": "Коллекции",
|
||||
"items": "элементы"
|
||||
},
|
||||
"options": {
|
||||
"display": "Отображать",
|
||||
"row": "Ряд",
|
||||
"list": "Список",
|
||||
"image_style": "Стиль изображения",
|
||||
"poster": "Постер",
|
||||
"cover": "Обложка",
|
||||
"show_titles": "Показывать загаловки",
|
||||
"show_stats": "Показывать статистику"
|
||||
},
|
||||
"filters": {
|
||||
"genres": "Жанры",
|
||||
"years": "Года",
|
||||
"sort_by": "Сортировать по",
|
||||
"sort_order": "Порядок сортировки",
|
||||
"asc": "По Возрастанию",
|
||||
"desc": "По убыванию",
|
||||
"tags": "Тэги"
|
||||
}
|
||||
},
|
||||
"favorites": {
|
||||
"series": "Сериалы",
|
||||
"movies": "Фильмы",
|
||||
"episodes": "Серии",
|
||||
"videos": "Видео",
|
||||
"boxsets": "Коллекции",
|
||||
"playlists": "Плейлисты",
|
||||
"noDataTitle": "Пока нет избранных",
|
||||
"noData": "Отметьте элементы как избранные, чтобы они отображались здесь для быстрого доступа."
|
||||
},
|
||||
"custom_links": {
|
||||
"no_links": "Нет ссылок"
|
||||
},
|
||||
"player": {
|
||||
"error": "Ошибка",
|
||||
"failed_to_get_stream_url": "Не удалось получить URL потока",
|
||||
"an_error_occured_while_playing_the_video": "Возникла Неожиданная ошибка во время воспроизведения. Проверьте логи в настройках.",
|
||||
"client_error": "Ошибка клиента",
|
||||
"could_not_create_stream_for_chromecast": "Не удалось создать поток для Chromecast",
|
||||
"message_from_server": "Сообщение от сервера: {{message}}",
|
||||
"video_has_finished_playing": "Видео закончило воспроизводиться!",
|
||||
"no_video_source": "Нет источника видео...",
|
||||
"next_episode": "Следующая серия",
|
||||
"refresh_tracks": "Обновить дорожки",
|
||||
"subtitle_tracks": "Субтитры:",
|
||||
"audio_tracks": "Аудио дорожки:",
|
||||
"playback_state": "Состояние воспроизведения:",
|
||||
"no_data_available": "Данные не доступны",
|
||||
"index": "Индекс:",
|
||||
"continue_watching": "Продолжить просмотр",
|
||||
"go_back": "Назад"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Следующее",
|
||||
"no_items_to_display": "Нет элементов для отображения",
|
||||
"cast_and_crew": "Актеры и съемочная группа",
|
||||
"series": "Серии",
|
||||
"seasons": "Сезоны",
|
||||
"season": "Сезон",
|
||||
"no_episodes_for_this_season": "В этом сезоне нет серий",
|
||||
"overview": "Обзор",
|
||||
"more_with": "Больше с {{name}}",
|
||||
"similar_items": "Похожие элементы",
|
||||
"no_similar_items_found": "Похожие элементы не найдены",
|
||||
"video": "Видео",
|
||||
"more_details": "Больше деталей",
|
||||
"quality": "Качество",
|
||||
"audio": "Звук",
|
||||
"subtitles": "Субтитры",
|
||||
"show_more": "Показать больше",
|
||||
"show_less": "Показать меньше",
|
||||
"appeared_in": "Появлялся в",
|
||||
"could_not_load_item": "Не удалось загрузить элемент",
|
||||
"none": "Отсутствует",
|
||||
"download": {
|
||||
"download_season": "Загрузить сезон",
|
||||
"download_series": "Загрузить сериал",
|
||||
"download_episode": "Загрузить серию",
|
||||
"download_movie": "Скачать фильм",
|
||||
"download_x_item": "Загрузить {{item_count}} элементов",
|
||||
"download_button": "Загрузить",
|
||||
"using_optimized_server": "Использовать оптимизированный сервер",
|
||||
"using_default_method": "Использовать стандартный метод"
|
||||
}
|
||||
},
|
||||
"live_tv": {
|
||||
"next": "Следующая",
|
||||
"previous": "Предыдущая",
|
||||
"live_tv": "Прямой эфир ТВ",
|
||||
"coming_soon": "Скоро",
|
||||
"on_now": "Сейчас в эфире",
|
||||
"shows": "Сериалы",
|
||||
"movies": "Фильмы",
|
||||
"sports": "Спорт",
|
||||
"for_kids": "Для детей",
|
||||
"news": "Новости"
|
||||
},
|
||||
"jellyseerr": {
|
||||
"confirm": "Подтвердить",
|
||||
"cancel": "Отменить",
|
||||
"yes": "Да",
|
||||
"whats_wrong": "В чем дело?",
|
||||
"issue_type": "Вид проблемы",
|
||||
"select_an_issue": "Выберите проблему",
|
||||
"types": "Типы",
|
||||
"describe_the_issue": "(опционально) Опишите проблему...",
|
||||
"submit_button": "Подать",
|
||||
"report_issue_button": "Сообщить о проблеме",
|
||||
"request_button": "Запросить",
|
||||
"are_you_sure_you_want_to_request_all_seasons": "Вы уверены, что хотите запросить все сезоны?",
|
||||
"failed_to_login": "Не удалось войти",
|
||||
"cast": "Транслировать",
|
||||
"details": "Детали",
|
||||
"status": "Статус",
|
||||
"original_title": "Оригинальное название",
|
||||
"series_type": "Тип сериала",
|
||||
"release_dates": "Дата релиза",
|
||||
"first_air_date": "Первая дата выхода в эфир",
|
||||
"next_air_date": "Следующая дата выхода в эфир",
|
||||
"revenue": "Прибыль",
|
||||
"budget": "Бюджет",
|
||||
"original_language": "Оригинальный язык",
|
||||
"production_country": "Страна производства",
|
||||
"studios": "Студия",
|
||||
"network": "Сеть",
|
||||
"currently_streaming_on": "Сейчас доступно на",
|
||||
"advanced": "Продвинутое",
|
||||
"request_as": "Запросить как",
|
||||
"tags": "Тэги",
|
||||
"quality_profile": "Профиль качества",
|
||||
"root_folder": "Корневая папка",
|
||||
"season_all": "Сезон (все)",
|
||||
"season_number": "Сезон {{season_number}}",
|
||||
"number_episodes": "{{episode_number}} серий",
|
||||
"born": "Рожден",
|
||||
"appearances": "Появления",
|
||||
"toasts": {
|
||||
"jellyseer_does_not_meet_requirements": "Сервер Jellyseerr не соответствует минимальным требованиям версии! Пожалуйста, обновите до версии не ниже 2.0.0",
|
||||
"jellyseerr_test_failed": "Тест Jellyseerr не пройден. Попробуйте еще раз.",
|
||||
"failed_to_test_jellyseerr_server_url": "Не удалось проверить URL-адрес сервера jellyseerr",
|
||||
"issue_submitted": "Проблема отправлена!",
|
||||
"requested_item": "Запрошено {{item}}!",
|
||||
"you_dont_have_permission_to_request": "У вас нет разрешения на запрос!",
|
||||
"something_went_wrong_requesting_media": "Что-то пошло не так при запросе медиафайлов!"
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
"home": "Дом",
|
||||
"search": "Поиск",
|
||||
"library": "Библиотека",
|
||||
"custom_links": "Кастомные ссылки",
|
||||
"favorites": "Избранное"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,5 +30,24 @@
|
||||
"home": "Hem",
|
||||
"search": "Sök",
|
||||
"library": "Bibliotek"
|
||||
},
|
||||
"player": {
|
||||
"error": "Fel",
|
||||
"failed_to_get_stream_url": "Kunde inte hämta stream-URL",
|
||||
"an_error_occured_while_playing_the_video": "Ett fel uppstod vid uppspelning av videon. Kontrollera loggarna i inställningarna.",
|
||||
"client_error": "Klientfel",
|
||||
"could_not_create_stream_for_chromecast": "Kunde inte skapa stream för Chromecast",
|
||||
"message_from_server": "Meddelande från servern: {{message}}",
|
||||
"video_has_finished_playing": "Videon har spelat klart!",
|
||||
"no_video_source": "Ingen videokälla...",
|
||||
"next_episode": "Nästa avsnitt",
|
||||
"refresh_tracks": "Uppdatera spår",
|
||||
"subtitle_tracks": "Textspår:",
|
||||
"audio_tracks": "Ljudspår:",
|
||||
"playback_state": "Uppspelningsstatus:",
|
||||
"no_data_available": "Inga data tillgängliga",
|
||||
"index": "Index:",
|
||||
"continue_watching": "Fortsätt titta",
|
||||
"go_back": "Tillbaka"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,9 @@
|
||||
"show_custom_menu_links": "Özel Menü Bağlantılarını Göster",
|
||||
"hide_libraries": "Kütüphaneleri Gizle",
|
||||
"select_liraries_you_want_to_hide": "Kütüphane sekmesinden ve ana sayfa bölümlerinden gizlemek istediğiniz kütüphaneleri seçin.",
|
||||
"disable_haptic_feedback": "Dokunsal Geri Bildirimi Devre Dışı Bırak"
|
||||
"disable_haptic_feedback": "Dokunsal Geri Bildirimi Devre Dışı Bırak",
|
||||
"default_quality": "Varsayılan kalite",
|
||||
"disabled": "Devre dışı"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "İndirmeler",
|
||||
@@ -369,7 +371,9 @@
|
||||
"audio_tracks": "Ses Parçaları:",
|
||||
"playback_state": "Oynatma Durumu:",
|
||||
"no_data_available": "Veri bulunamadı",
|
||||
"index": "İndeks:"
|
||||
"index": "İndeks:",
|
||||
"continue_watching": "İzlemeye devam et",
|
||||
"go_back": "Geri"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Sıradaki",
|
||||
|
||||
@@ -137,8 +137,9 @@
|
||||
"show_custom_menu_links": "Показати користувацькі посилання меню",
|
||||
"hide_libraries": "Сховати медіатеки",
|
||||
"select_liraries_you_want_to_hide": "Виберіть медіатеки, що бажаєте приховати з вкладки Медіатека і з секції на головній сторінці.",
|
||||
"disable_haptic_feedback": "Вимкнути тактильний відгук",
|
||||
"default_quality": "Якість за замовченням"
|
||||
"disable_haptic_feedback": "Вимкнути тактильний зворотний зв'язок",
|
||||
"default_quality": "Якість за замовченням",
|
||||
"disabled": "Вимкнено"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "Завантаження",
|
||||
@@ -374,7 +375,9 @@
|
||||
"audio_tracks": "Аудіо-доріжки:",
|
||||
"playback_state": "Стан відтворення:",
|
||||
"no_data_available": "Дані відсутні",
|
||||
"index": "Індекс:"
|
||||
"index": "Індекс:",
|
||||
"continue_watching": "Продовжити перегляд",
|
||||
"go_back": "Назад"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "Далі",
|
||||
@@ -477,4 +480,4 @@
|
||||
"custom_links": "Ваші Посилання",
|
||||
"favorites": "Улюблене"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +369,9 @@
|
||||
"audio_tracks": "音频轨道:",
|
||||
"playback_state": "播放状态:",
|
||||
"no_data_available": "无可用数据",
|
||||
"index": "索引:"
|
||||
"index": "索引:",
|
||||
"continue_watching": "继续观看",
|
||||
"go_back": "返回"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "下一个",
|
||||
|
||||
@@ -137,7 +137,9 @@
|
||||
"show_custom_menu_links": "顯示自定義菜單鏈接",
|
||||
"hide_libraries": "隱藏媒體庫",
|
||||
"select_liraries_you_want_to_hide": "選擇您想從媒體庫頁面和主頁隱藏的媒體庫。",
|
||||
"disable_haptic_feedback": "禁用觸覺回饋"
|
||||
"disable_haptic_feedback": "禁用觸覺回饋",
|
||||
"default_quality": "預設品質",
|
||||
"disabled": "已停用"
|
||||
},
|
||||
"downloads": {
|
||||
"downloads_title": "下載",
|
||||
@@ -369,7 +371,9 @@
|
||||
"audio_tracks": "音頻軌道:",
|
||||
"playback_state": "播放狀態:",
|
||||
"no_data_available": "無可用數據",
|
||||
"index": "索引:"
|
||||
"index": "索引:",
|
||||
"continue_watching": "繼續觀看",
|
||||
"go_back": "返回"
|
||||
},
|
||||
"item_card": {
|
||||
"next_up": "下一個",
|
||||
|
||||
@@ -114,6 +114,11 @@ export type HomeSectionNextUpResolver = {
|
||||
enableRewatching?: boolean;
|
||||
};
|
||||
|
||||
export interface MaxAutoPlayEpisodeCount {
|
||||
key: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export type HomeSectionLatestResolver = {
|
||||
parentId?: string;
|
||||
limit?: number;
|
||||
@@ -163,6 +168,8 @@ export type Settings = {
|
||||
hiddenLibraries?: string[];
|
||||
enableH265ForChromecast: boolean;
|
||||
defaultPlayer: VideoPlayer;
|
||||
maxAutoPlayEpisodeCount: MaxAutoPlayEpisodeCount;
|
||||
autoPlayEpisodeCount: number;
|
||||
};
|
||||
|
||||
export interface Lockable<T> {
|
||||
@@ -217,7 +224,9 @@ const defaultValues: Settings = {
|
||||
jellyseerrServerUrl: undefined,
|
||||
hiddenLibraries: [],
|
||||
enableH265ForChromecast: false,
|
||||
defaultPlayer: VideoPlayer.VLC_3, // ios only setting. does not matter what this is for android
|
||||
defaultPlayer: VideoPlayer.VLC_3, // ios-only setting. does not matter what this is for android
|
||||
maxAutoPlayEpisodeCount: { key: "3", value: 3 },
|
||||
autoPlayEpisodeCount: 0,
|
||||
};
|
||||
|
||||
const loadSettings = (): Partial<Settings> => {
|
||||
@@ -236,11 +245,11 @@ const loadSettings = (): Partial<Settings> => {
|
||||
const EXCLUDE_FROM_SAVE = ["home"];
|
||||
|
||||
const saveSettings = (settings: Settings) => {
|
||||
Object.keys(settings).forEach((key) => {
|
||||
for (const key of Object.keys(settings)) {
|
||||
if (EXCLUDE_FROM_SAVE.includes(key)) {
|
||||
delete settings[key as keyof Settings];
|
||||
}
|
||||
});
|
||||
}
|
||||
const jsonValue = JSON.stringify(settings);
|
||||
storage.set("settings", jsonValue);
|
||||
};
|
||||
@@ -271,7 +280,9 @@ export const useSettings = () => {
|
||||
);
|
||||
|
||||
const refreshStreamyfinPluginSettings = useCallback(async () => {
|
||||
if (!api) return;
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
const settings = await api.getStreamyfinPluginConfig().then(
|
||||
({ data }) => {
|
||||
writeInfoLog("Got plugin settings", data?.settings);
|
||||
@@ -284,7 +295,9 @@ export const useSettings = () => {
|
||||
}, [api]);
|
||||
|
||||
const updateSettings = (update: Partial<Settings>) => {
|
||||
if (!_settings) return;
|
||||
if (!_settings) {
|
||||
return;
|
||||
}
|
||||
const hasChanges = Object.entries(update).some(
|
||||
([key, value]) => _settings[key as keyof Settings] !== value,
|
||||
);
|
||||
@@ -305,34 +318,31 @@ export const useSettings = () => {
|
||||
// If admin sets locked to false but provides a value,
|
||||
// use user settings first and fallback on admin setting if required.
|
||||
const settings: Settings = useMemo(() => {
|
||||
let unlockedPluginDefaults = {} as Settings;
|
||||
const overrideSettings = Object.entries(pluginSettings || {}).reduce(
|
||||
(acc, [key, setting]) => {
|
||||
if (setting) {
|
||||
const { value, locked } = setting;
|
||||
const unlockedPluginDefaults = {} as Settings;
|
||||
const overrideSettings = Object.entries(pluginSettings ?? {}).reduce<
|
||||
Partial<Settings>
|
||||
>((acc, [key, setting]) => {
|
||||
if (setting) {
|
||||
const { value, locked } = setting;
|
||||
const settingsKey = key as keyof Settings;
|
||||
|
||||
// Make sure we override default settings with plugin settings when they are not locked.
|
||||
// Admin decided what users defaults should be and grants them the ability to change them too.
|
||||
if (
|
||||
locked === false &&
|
||||
value &&
|
||||
_settings?.[key as keyof Settings] !== value
|
||||
) {
|
||||
unlockedPluginDefaults = Object.assign(unlockedPluginDefaults, {
|
||||
[key as keyof Settings]: value,
|
||||
});
|
||||
}
|
||||
|
||||
acc = Object.assign(acc, {
|
||||
[key]: locked
|
||||
? value
|
||||
: (_settings?.[key as keyof Settings] ?? value),
|
||||
// Make sure we override default settings with plugin settings when they are not locked.
|
||||
if (
|
||||
!locked &&
|
||||
value !== undefined &&
|
||||
_settings?.[settingsKey] !== value
|
||||
) {
|
||||
Object.assign(unlockedPluginDefaults, {
|
||||
[settingsKey]: value,
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Settings,
|
||||
);
|
||||
|
||||
Object.assign(acc, {
|
||||
[settingsKey]: locked ? value : (_settings?.[settingsKey] ?? value),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
...defaultValues,
|
||||
|
||||
Reference in New Issue
Block a user