mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-17 18:03:01 +01:00
Compare commits
7 Commits
fix/plugin
...
feat/andro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c8268800d | ||
|
|
76d9b3177b | ||
|
|
2e79815d78 | ||
|
|
43ce50fe70 | ||
|
|
bd0eef0407 | ||
|
|
16bb1b8717 | ||
|
|
259306df52 |
@@ -71,7 +71,7 @@ export default function AppearanceHideLibrariesPage() {
|
||||
))}
|
||||
</ListGroup>
|
||||
<Text className='px-4 text-xs text-neutral-500 mt-1'>
|
||||
{t("home.settings.other.select_liraries_you_want_to_hide")}
|
||||
{t("home.settings.other.select_libraries_you_want_to_hide")}
|
||||
</Text>
|
||||
</DisabledSetting>
|
||||
</ScrollView>
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function HideLibrariesPage() {
|
||||
))}
|
||||
</ListGroup>
|
||||
<Text className='px-4 text-xs text-neutral-500 mt-1'>
|
||||
{t("home.settings.other.select_liraries_you_want_to_hide")}
|
||||
{t("home.settings.other.select_libraries_you_want_to_hide")}
|
||||
</Text>
|
||||
</DisabledSetting>
|
||||
);
|
||||
|
||||
@@ -1318,7 +1318,7 @@ export default function DirectPlayerPage() {
|
||||
console.error("Video Error:", e.nativeEvent);
|
||||
Alert.alert(
|
||||
t("player.error"),
|
||||
t("player.an_error_occured_while_playing_the_video"),
|
||||
t("player.an_error_occurred_while_playing_the_video"),
|
||||
);
|
||||
writeToLog("ERROR", "Video Error", e.nativeEvent);
|
||||
}}
|
||||
|
||||
@@ -85,7 +85,8 @@ configureReanimatedLogger({
|
||||
if (!Platform.isTV) {
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldShowBanner: true,
|
||||
shouldShowList: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: false,
|
||||
}),
|
||||
@@ -350,9 +351,12 @@ function Layout() {
|
||||
notificationListener.current =
|
||||
Notifications?.addNotificationReceivedListener(
|
||||
(notification: Notification) => {
|
||||
// Log only the title — serializing the whole notification touches
|
||||
// the deprecated dataString getter (deprecation warning) and dumps
|
||||
// noisy payloads into the console.
|
||||
console.log(
|
||||
"Notification received while app running",
|
||||
notification,
|
||||
"Notification received while app running:",
|
||||
notification.request.content.title,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -16,9 +16,12 @@ export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({ items }) => {
|
||||
const { showActionSheetWithOptions } = useActionSheet();
|
||||
const router = useRouter();
|
||||
|
||||
// Keyed on SeriesId so recycled FlashList cells re-read the correct poster
|
||||
// instead of freezing the first-rendered series' image (empty deps bug).
|
||||
const base64Image = useMemo(() => {
|
||||
return storage.getString(items[0].SeriesId!);
|
||||
}, []);
|
||||
const seriesId = items[0]?.SeriesId;
|
||||
return seriesId ? storage.getString(seriesId) : undefined;
|
||||
}, [items[0]?.SeriesId]);
|
||||
|
||||
const deleteSeries = useCallback(
|
||||
async () =>
|
||||
|
||||
@@ -146,7 +146,7 @@ export const Login: React.FC = () => {
|
||||
} else {
|
||||
Alert.alert(
|
||||
t("login.connection_failed"),
|
||||
t("login.an_unexpected_error_occured"),
|
||||
t("login.an_unexpected_error_occurred"),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -437,7 +437,7 @@ export const TVLogin: React.FC = () => {
|
||||
} else {
|
||||
Alert.alert(
|
||||
t("login.connection_failed"),
|
||||
t("login.an_unexpected_error_occured"),
|
||||
t("login.an_unexpected_error_occurred"),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -499,7 +499,7 @@ export const TVLogin: React.FC = () => {
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: t("login.an_unexpected_error_occured");
|
||||
: t("login.an_unexpected_error_occurred");
|
||||
Alert.alert(t("login.connection_failed"), message);
|
||||
goToQRScreen();
|
||||
} finally {
|
||||
@@ -523,7 +523,7 @@ export const TVLogin: React.FC = () => {
|
||||
} else {
|
||||
Alert.alert(
|
||||
t("login.connection_failed"),
|
||||
t("login.an_unexpected_error_occured"),
|
||||
t("login.an_unexpected_error_occurred"),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -768,7 +768,7 @@ export const TVLogin: React.FC = () => {
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: t("login.an_unexpected_error_occured");
|
||||
: t("login.an_unexpected_error_occurred");
|
||||
Alert.alert(t("login.connection_failed"), message);
|
||||
goToQRScreen();
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ export const QuickConnect: React.FC<Props> = ({ ...props }) => {
|
||||
successHapticFeedback();
|
||||
Alert.alert(
|
||||
t("home.settings.quick_connect.success"),
|
||||
t("home.settings.quick_connect.quick_connect_autorized"),
|
||||
t("home.settings.quick_connect.quick_connect_authorized"),
|
||||
);
|
||||
setQuickConnectCode(undefined);
|
||||
bottomSheetModalRef?.current?.close();
|
||||
|
||||
212
components/settings/StorageLocationPicker.tsx
Normal file
212
components/settings/StorageLocationPicker.tsx
Normal file
@@ -0,0 +1,212 @@
|
||||
import {
|
||||
BottomSheetBackdrop,
|
||||
type BottomSheetBackdropProps,
|
||||
BottomSheetModal,
|
||||
BottomSheetScrollView,
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { forwardRef, useCallback, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Platform,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { toast } from "sonner-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import type { StorageLocation } from "@/modules";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import {
|
||||
clearStorageLocationsCache,
|
||||
getAvailableStorageLocations,
|
||||
} from "@/utils/storage";
|
||||
|
||||
interface StorageLocationPickerProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const StorageLocationPicker = forwardRef<
|
||||
BottomSheetModal,
|
||||
StorageLocationPickerProps
|
||||
>(({ onClose }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { settings, updateSettings } = useSettings();
|
||||
const insets = useSafeAreaInsets();
|
||||
const [selectedId, setSelectedId] = useState<string | undefined>(
|
||||
settings.downloadStorageLocation || "internal",
|
||||
);
|
||||
|
||||
const { data: locations, isLoading } = useQuery({
|
||||
queryKey: ["storageLocations"],
|
||||
queryFn: getAvailableStorageLocations,
|
||||
enabled: Platform.OS === "android",
|
||||
});
|
||||
|
||||
const handleSelect = (location: StorageLocation) => {
|
||||
setSelectedId(location.id);
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
updateSettings({ downloadStorageLocation: selectedId });
|
||||
clearStorageLocationsCache(); // Clear cache so next download uses new location
|
||||
toast.success(
|
||||
t("settings.storage.storage_location_updated", {
|
||||
defaultValue: "Storage location updated",
|
||||
}),
|
||||
);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const renderBackdrop = useCallback(
|
||||
(props: BottomSheetBackdropProps) => (
|
||||
<BottomSheetBackdrop
|
||||
{...props}
|
||||
disappearsOnIndex={-1}
|
||||
appearsOnIndex={0}
|
||||
/>
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
if (Platform.OS !== "android") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<BottomSheetModal
|
||||
ref={ref}
|
||||
enableDynamicSizing
|
||||
backdropComponent={renderBackdrop}
|
||||
handleIndicatorStyle={{
|
||||
backgroundColor: "white",
|
||||
}}
|
||||
backgroundStyle={{
|
||||
backgroundColor: "#171717",
|
||||
}}
|
||||
enablePanDownToClose
|
||||
enableDismissOnClose
|
||||
>
|
||||
<BottomSheetScrollView
|
||||
style={{
|
||||
paddingLeft: Math.max(16, insets.left),
|
||||
paddingRight: Math.max(16, insets.right),
|
||||
}}
|
||||
>
|
||||
<View className='px-4 pt-2'>
|
||||
<Text className='text-lg font-semibold mb-1'>
|
||||
{t("settings.storage.select_storage_location", {
|
||||
defaultValue: "Select Storage Location",
|
||||
})}
|
||||
</Text>
|
||||
<Text className='text-sm text-neutral-500 mb-4'>
|
||||
{t("settings.storage.existing_downloads_note", {
|
||||
defaultValue:
|
||||
"Existing downloads will remain in their current location",
|
||||
})}
|
||||
</Text>
|
||||
|
||||
{isLoading ? (
|
||||
<View className='items-center justify-center py-8'>
|
||||
<ActivityIndicator size='large' />
|
||||
<Text className='mt-4 text-neutral-500'>
|
||||
{t("settings.storage.loading_storage", {
|
||||
defaultValue: "Loading storage options...",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
) : !locations || locations.length === 0 ? (
|
||||
<View className='items-center justify-center py-8'>
|
||||
<Text className='text-neutral-500'>
|
||||
{t("settings.storage.no_storage_found", {
|
||||
defaultValue: "No storage locations found",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
{locations.map((location) => {
|
||||
const isSelected = selectedId === location.id;
|
||||
const freeSpaceGB = (location.freeSpace / 1024 ** 3).toFixed(2);
|
||||
const totalSpaceGB = (location.totalSpace / 1024 ** 3).toFixed(
|
||||
2,
|
||||
);
|
||||
const usedPercent = (
|
||||
((location.totalSpace - location.freeSpace) /
|
||||
location.totalSpace) *
|
||||
100
|
||||
).toFixed(0);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={location.id}
|
||||
onPress={() => handleSelect(location)}
|
||||
className={`p-4 mb-2 rounded-lg ${
|
||||
isSelected
|
||||
? "bg-purple-600/20 border border-purple-600"
|
||||
: "bg-neutral-800"
|
||||
}`}
|
||||
>
|
||||
<View className='flex-row items-center justify-between'>
|
||||
<View className='flex-1'>
|
||||
<View className='flex-row items-center'>
|
||||
<Text className='text-base font-semibold'>
|
||||
{location.label}
|
||||
</Text>
|
||||
{location.type === "external" && (
|
||||
<View className='ml-2 px-2 py-0.5 bg-blue-600/30 rounded'>
|
||||
<Text className='text-xs text-blue-400'>
|
||||
{t("settings.storage.removable", {
|
||||
defaultValue: "Removable",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<Text className='text-sm text-neutral-500 mt-1'>
|
||||
{t("settings.storage.space_info", {
|
||||
defaultValue:
|
||||
"{{free}} GB free of {{total}} GB ({{used}}% used)",
|
||||
free: freeSpaceGB,
|
||||
total: totalSpaceGB,
|
||||
used: usedPercent,
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
{isSelected && (
|
||||
<View className='w-6 h-6 rounded-full bg-purple-600 items-center justify-center ml-2'>
|
||||
<Text className='text-white text-xs'>✓</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
|
||||
<View className='flex-row gap-x-2 py-4'>
|
||||
<TouchableOpacity
|
||||
onPress={onClose}
|
||||
className='flex-1 py-3 rounded-lg bg-neutral-800 items-center'
|
||||
>
|
||||
<Text className='text-white font-semibold'>
|
||||
{t("common.cancel", { defaultValue: "Cancel" })}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={handleConfirm}
|
||||
className='flex-1 py-3 rounded-lg bg-purple-600 items-center'
|
||||
disabled={!selectedId}
|
||||
>
|
||||
<Text className='text-white font-semibold'>
|
||||
{t("common.confirm", { defaultValue: "Confirm" })}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</BottomSheetScrollView>
|
||||
</BottomSheetModal>
|
||||
);
|
||||
});
|
||||
@@ -1,19 +1,27 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { BottomSheetModal } from "@gorhom/bottom-sheet";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform, View } from "react-native";
|
||||
import { Alert, Platform, View } from "react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { Colors } from "@/constants/Colors";
|
||||
import { useHaptic } from "@/hooks/useHaptic";
|
||||
import { useDownload } from "@/providers/DownloadProvider";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { getStorageLabel } from "@/utils/storage";
|
||||
import { ListGroup } from "../list/ListGroup";
|
||||
import { ListItem } from "../list/ListItem";
|
||||
import { StorageLocationPicker } from "./StorageLocationPicker";
|
||||
|
||||
export const StorageSettings = () => {
|
||||
const { deleteAllFiles, appSizeUsage } = useDownload();
|
||||
const { settings } = useSettings();
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const successHapticFeedback = useHaptic("success");
|
||||
const errorHapticFeedback = useHaptic("error");
|
||||
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
|
||||
|
||||
const { data: size } = useQuery({
|
||||
queryKey: ["appSize"],
|
||||
@@ -27,16 +35,44 @@ export const StorageSettings = () => {
|
||||
used: (app.total - app.remaining) / app.total,
|
||||
};
|
||||
},
|
||||
// Keep the bar moving while a download is writing to disk.
|
||||
refetchInterval: 10 * 1000,
|
||||
});
|
||||
|
||||
const onDeleteClicked = async () => {
|
||||
try {
|
||||
await deleteAllFiles();
|
||||
successHapticFeedback();
|
||||
} catch (_e) {
|
||||
errorHapticFeedback();
|
||||
toast.error(t("home.settings.toasts.error_deleting_files"));
|
||||
}
|
||||
const { data: storageLabel } = useQuery({
|
||||
queryKey: ["storageLabel", settings.downloadStorageLocation],
|
||||
queryFn: () => getStorageLabel(settings.downloadStorageLocation),
|
||||
enabled: Platform.OS === "android",
|
||||
});
|
||||
|
||||
const onDeleteClicked = () => {
|
||||
Alert.alert(
|
||||
t("home.settings.storage.delete_all_downloaded_files_confirm"),
|
||||
t("home.settings.storage.delete_all_downloaded_files_confirm_desc"),
|
||||
[
|
||||
{
|
||||
text: t("common.cancel"),
|
||||
style: "cancel",
|
||||
},
|
||||
{
|
||||
text: t("common.ok"),
|
||||
style: "destructive",
|
||||
onPress: async () => {
|
||||
try {
|
||||
await deleteAllFiles();
|
||||
successHapticFeedback();
|
||||
} catch (_e) {
|
||||
errorHapticFeedback();
|
||||
toast.error(t("home.settings.toasts.error_deleting_files"));
|
||||
} finally {
|
||||
// Reflect the freed space immediately instead of waiting for
|
||||
// the next poll.
|
||||
queryClient.invalidateQueries({ queryKey: ["appSize"] });
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
const calculatePercentage = (value: number, total: number) => {
|
||||
@@ -102,14 +138,32 @@ export const StorageSettings = () => {
|
||||
</View>
|
||||
</View>
|
||||
{!Platform.isTV && (
|
||||
<ListGroup>
|
||||
<ListItem
|
||||
textColor='red'
|
||||
onPress={onDeleteClicked}
|
||||
title={t("home.settings.storage.delete_all_downloaded_files")}
|
||||
/>
|
||||
</ListGroup>
|
||||
<>
|
||||
{Platform.OS === "android" && (
|
||||
<ListGroup>
|
||||
<ListItem
|
||||
title={t("settings.storage.download_location", {
|
||||
defaultValue: "Download Location",
|
||||
})}
|
||||
value={storageLabel || "Internal Storage"}
|
||||
onPress={() => bottomSheetModalRef.current?.present()}
|
||||
/>
|
||||
</ListGroup>
|
||||
)}
|
||||
<ListGroup>
|
||||
<ListItem
|
||||
textColor='red'
|
||||
onPress={onDeleteClicked}
|
||||
title={t("home.settings.storage.delete_all_downloaded_files")}
|
||||
/>
|
||||
</ListGroup>
|
||||
</>
|
||||
)}
|
||||
|
||||
<StorageLocationPicker
|
||||
ref={bottomSheetModalRef}
|
||||
onClose={() => bottomSheetModalRef.current?.dismiss()}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,11 +4,16 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.IBinder
|
||||
import android.os.storage.StorageManager
|
||||
import android.os.storage.StorageVolume
|
||||
import android.util.Log
|
||||
import expo.modules.kotlin.Promise
|
||||
import expo.modules.kotlin.modules.Module
|
||||
import expo.modules.kotlin.modules.ModuleDefinition
|
||||
import java.io.File
|
||||
|
||||
data class DownloadTaskInfo(
|
||||
val url: String,
|
||||
@@ -142,6 +147,105 @@ class BackgroundDownloaderModule : Module() {
|
||||
promise.reject("ERROR", "Failed to get active downloads: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
|
||||
AsyncFunction("getAvailableStorageLocations") { promise: Promise ->
|
||||
try {
|
||||
val storageLocations = mutableListOf<Map<String, Any>>()
|
||||
|
||||
// Use getExternalFilesDirs which works reliably across all Android versions
|
||||
// This returns app-specific directories on both internal and external storage
|
||||
val externalDirs = context.getExternalFilesDirs(null)
|
||||
|
||||
Log.d(TAG, "getExternalFilesDirs returned ${externalDirs.size} locations")
|
||||
|
||||
// Also check with StorageManager for additional info
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
val volumes = storageManager.storageVolumes
|
||||
Log.d(TAG, "StorageManager reports ${volumes.size} volumes")
|
||||
for ((i, vol) in volumes.withIndex()) {
|
||||
Log.d(TAG, " Volume $i: isPrimary=${vol.isPrimary}, isRemovable=${vol.isRemovable}, state=${vol.state}, uuid=${vol.uuid}")
|
||||
}
|
||||
}
|
||||
|
||||
for ((index, dir) in externalDirs.withIndex()) {
|
||||
try {
|
||||
if (dir == null) {
|
||||
Log.w(TAG, "Directory at index $index is null - SD card may not be mounted")
|
||||
continue
|
||||
}
|
||||
|
||||
if (!dir.exists()) {
|
||||
Log.w(TAG, "Directory at index $index does not exist: ${dir.absolutePath}")
|
||||
continue
|
||||
}
|
||||
|
||||
val isPrimary = index == 0
|
||||
val isRemovable = !isPrimary && Environment.isExternalStorageRemovable(dir)
|
||||
|
||||
// Get volume UUID for better identification
|
||||
val volumeId = if (isPrimary) {
|
||||
"internal"
|
||||
} else {
|
||||
// Try to get a stable UUID for the SD card
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
try {
|
||||
val storageVolume = storageManager.getStorageVolume(dir)
|
||||
storageVolume?.uuid ?: "sdcard_$index"
|
||||
} catch (e: Exception) {
|
||||
"sdcard_$index"
|
||||
}
|
||||
} else {
|
||||
"sdcard_$index"
|
||||
}
|
||||
}
|
||||
|
||||
// Get human-readable label
|
||||
val label = if (isPrimary) {
|
||||
"Internal Storage"
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
try {
|
||||
val storageVolume = storageManager.getStorageVolume(dir)
|
||||
storageVolume?.getDescription(context) ?: "SD Card"
|
||||
} catch (e: Exception) {
|
||||
"SD Card"
|
||||
}
|
||||
} else {
|
||||
"SD Card"
|
||||
}
|
||||
}
|
||||
|
||||
val totalSpace = dir.totalSpace
|
||||
val freeSpace = dir.freeSpace
|
||||
|
||||
Log.d(TAG, "Storage location: $label (id: $volumeId, path: ${dir.absolutePath}, removable: $isRemovable)")
|
||||
|
||||
storageLocations.add(
|
||||
mapOf(
|
||||
"id" to volumeId,
|
||||
"path" to dir.absolutePath,
|
||||
"type" to (if (isRemovable || !isPrimary) "external" else "internal"),
|
||||
"label" to label,
|
||||
"totalSpace" to totalSpace,
|
||||
"freeSpace" to freeSpace
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error processing storage at index $index: ${e.message}", e)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "Returning ${storageLocations.size} storage locations")
|
||||
promise.resolve(storageLocations)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error getting storage locations: ${e.message}", e)
|
||||
promise.reject("ERROR", "Failed to get storage locations: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startDownloadInternal(urlString: String, destinationPath: String?): Int {
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
DownloadErrorEvent,
|
||||
DownloadProgressEvent,
|
||||
DownloadStartedEvent,
|
||||
StorageLocation,
|
||||
} from "./src/BackgroundDownloader.types";
|
||||
import BackgroundDownloaderModule from "./src/BackgroundDownloaderModule";
|
||||
|
||||
@@ -15,6 +16,7 @@ export interface BackgroundDownloader {
|
||||
cancelQueuedDownload(url: string): void;
|
||||
cancelAllDownloads(): void;
|
||||
getActiveDownloads(): Promise<ActiveDownload[]>;
|
||||
getAvailableStorageLocations(): Promise<StorageLocation[]>;
|
||||
|
||||
addProgressListener(
|
||||
listener: (event: DownloadProgressEvent) => void,
|
||||
@@ -64,6 +66,10 @@ const BackgroundDownloader: BackgroundDownloader = {
|
||||
return await BackgroundDownloaderModule.getActiveDownloads();
|
||||
},
|
||||
|
||||
async getAvailableStorageLocations(): Promise<StorageLocation[]> {
|
||||
return await BackgroundDownloaderModule.getAvailableStorageLocations();
|
||||
},
|
||||
|
||||
addProgressListener(
|
||||
listener: (event: DownloadProgressEvent) => void,
|
||||
): EventSubscription {
|
||||
@@ -106,4 +112,5 @@ export type {
|
||||
DownloadErrorEvent,
|
||||
DownloadProgressEvent,
|
||||
DownloadStartedEvent,
|
||||
StorageLocation,
|
||||
};
|
||||
|
||||
@@ -29,6 +29,15 @@ export interface ActiveDownload {
|
||||
state: "running" | "suspended" | "canceling" | "completed" | "unknown";
|
||||
}
|
||||
|
||||
export interface StorageLocation {
|
||||
id: string;
|
||||
path: string;
|
||||
type: "internal" | "external";
|
||||
label: string;
|
||||
totalSpace: number;
|
||||
freeSpace: number;
|
||||
}
|
||||
|
||||
export interface BackgroundDownloaderModuleType {
|
||||
startDownload(url: string, destinationPath?: string): Promise<number>;
|
||||
enqueueDownload(url: string, destinationPath?: string): Promise<number>;
|
||||
@@ -36,6 +45,7 @@ export interface BackgroundDownloaderModuleType {
|
||||
cancelQueuedDownload(url: string): void;
|
||||
cancelAllDownloads(): void;
|
||||
getActiveDownloads(): Promise<ActiveDownload[]>;
|
||||
getAvailableStorageLocations(): Promise<StorageLocation[]>;
|
||||
addListener(
|
||||
eventName: string,
|
||||
listener: (event: any) => void,
|
||||
|
||||
@@ -5,6 +5,7 @@ export type {
|
||||
DownloadErrorEvent,
|
||||
DownloadProgressEvent,
|
||||
DownloadStartedEvent,
|
||||
StorageLocation,
|
||||
} from "./background-downloader";
|
||||
export { default as BackgroundDownloader } from "./background-downloader";
|
||||
// Glass Poster (tvOS 26+)
|
||||
|
||||
@@ -6,16 +6,20 @@ import type {
|
||||
import { Directory, File, Paths } from "expo-file-system";
|
||||
import { getItemImage } from "@/utils/getItemImage";
|
||||
import { fetchAndParseSegments } from "@/utils/segments";
|
||||
import { filePathToUri } from "@/utils/storage";
|
||||
import { generateTrickplayUrl, getTrickplayInfo } from "@/utils/trickplay";
|
||||
import type { MediaTimeSegment, TrickPlayData } from "./types";
|
||||
import { generateFilename } from "./utils";
|
||||
|
||||
/**
|
||||
* Downloads trickplay images for an item
|
||||
* @param item - The item to download trickplay images for
|
||||
* @param storagePath - Optional custom storage path (for Android SD card support)
|
||||
* @returns TrickPlayData with path and size, or undefined if not available
|
||||
*/
|
||||
export async function downloadTrickplayImages(
|
||||
item: BaseItemDto,
|
||||
storagePath?: string,
|
||||
): Promise<TrickPlayData | undefined> {
|
||||
const trickplayInfo = getTrickplayInfo(item);
|
||||
if (!trickplayInfo || !item.Id) {
|
||||
@@ -23,7 +27,11 @@ export async function downloadTrickplayImages(
|
||||
}
|
||||
|
||||
const filename = generateFilename(item);
|
||||
const trickplayDir = new Directory(Paths.document, `${filename}_trickplay`);
|
||||
|
||||
// Use custom storage path if provided (Android SD card), otherwise use Paths.document
|
||||
const trickplayDir = storagePath
|
||||
? new Directory(filePathToUri(storagePath), `${filename}_trickplay`)
|
||||
: new Directory(Paths.document, `${filename}_trickplay`);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!trickplayDir.exists) {
|
||||
@@ -69,12 +77,17 @@ export async function downloadTrickplayImages(
|
||||
|
||||
/**
|
||||
* Downloads external subtitle files and updates their delivery URLs to local paths
|
||||
* @param mediaSource - The media source containing subtitle information
|
||||
* @param item - The item to download subtitles for
|
||||
* @param apiBasePath - The base path for the API
|
||||
* @param storagePath - Optional custom storage path (for Android SD card support)
|
||||
* @returns Updated media source with local subtitle paths
|
||||
*/
|
||||
export async function downloadSubtitles(
|
||||
mediaSource: MediaSourceInfo,
|
||||
item: BaseItemDto,
|
||||
apiBasePath: string,
|
||||
storagePath?: string,
|
||||
): Promise<MediaSourceInfo> {
|
||||
const externalSubtitles = mediaSource.MediaStreams?.filter(
|
||||
(stream) =>
|
||||
@@ -91,10 +104,17 @@ export async function downloadSubtitles(
|
||||
|
||||
const url = apiBasePath + subtitle.DeliveryUrl;
|
||||
const extension = subtitle.Codec || "srt";
|
||||
const destination = new File(
|
||||
Paths.document,
|
||||
`${filename}_subtitle_${subtitle.Index}.${extension}`,
|
||||
);
|
||||
|
||||
// Use custom storage path if provided (Android SD card), otherwise use Paths.document
|
||||
const destination = storagePath
|
||||
? new File(
|
||||
filePathToUri(storagePath),
|
||||
`${filename}_subtitle_${subtitle.Index}.${extension}`,
|
||||
)
|
||||
: new File(
|
||||
Paths.document,
|
||||
`${filename}_subtitle_${subtitle.Index}.${extension}`,
|
||||
);
|
||||
|
||||
// Skip if already exists
|
||||
if (destination.exists) {
|
||||
@@ -208,13 +228,21 @@ export async function downloadAdditionalAssets(params: {
|
||||
api: Api;
|
||||
saveImageFn: (itemId: string, url?: string) => Promise<void>;
|
||||
saveSeriesImageFn: (item: BaseItemDto) => Promise<void>;
|
||||
storagePath?: string;
|
||||
}): Promise<{
|
||||
trickPlayData?: TrickPlayData;
|
||||
updatedMediaSource: MediaSourceInfo;
|
||||
introSegments?: MediaTimeSegment[];
|
||||
creditSegments?: MediaTimeSegment[];
|
||||
}> {
|
||||
const { item, mediaSource, api, saveImageFn, saveSeriesImageFn } = params;
|
||||
const {
|
||||
item,
|
||||
mediaSource,
|
||||
api,
|
||||
saveImageFn,
|
||||
saveSeriesImageFn,
|
||||
storagePath,
|
||||
} = params;
|
||||
|
||||
// Run all downloads in parallel for speed
|
||||
const [
|
||||
@@ -223,11 +251,11 @@ export async function downloadAdditionalAssets(params: {
|
||||
segments,
|
||||
// Cover images (fire and forget, errors are logged)
|
||||
] = await Promise.all([
|
||||
downloadTrickplayImages(item),
|
||||
downloadTrickplayImages(item, storagePath),
|
||||
// Only download subtitles for non-transcoded streams
|
||||
mediaSource.TranscodingUrl
|
||||
? Promise.resolve(mediaSource)
|
||||
: downloadSubtitles(mediaSource, item, api.basePath || ""),
|
||||
: downloadSubtitles(mediaSource, item, api.basePath || "", storagePath),
|
||||
item.Id
|
||||
? fetchSegments(item.Id, api)
|
||||
: Promise.resolve({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directory, File, Paths } from "expo-file-system";
|
||||
import { Directory, File } from "expo-file-system";
|
||||
import { getAllDownloadedItems, getDownloadedItemById } from "./database";
|
||||
import type { DownloadedItem } from "./types";
|
||||
import { filePathToUri } from "./utils";
|
||||
@@ -39,13 +39,11 @@ export function deleteAllAssociatedFiles(item: DownloadedItem): void {
|
||||
stream.DeliveryUrl
|
||||
) {
|
||||
try {
|
||||
const subtitleFilename = stream.DeliveryUrl.split("/").pop();
|
||||
if (subtitleFilename) {
|
||||
const subtitleFile = new File(Paths.document, subtitleFilename);
|
||||
if (subtitleFile.exists) {
|
||||
subtitleFile.delete();
|
||||
console.log(`[DELETE] Subtitle deleted: ${subtitleFilename}`);
|
||||
}
|
||||
// Use the full path from DeliveryUrl (it's already a full file:// URI)
|
||||
const subtitleFile = new File(stream.DeliveryUrl);
|
||||
if (subtitleFile.exists) {
|
||||
subtitleFile.delete();
|
||||
console.log(`[DELETE] Subtitle deleted: ${stream.DeliveryUrl}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[DELETE] Failed to delete subtitle:", error);
|
||||
@@ -57,15 +55,13 @@ export function deleteAllAssociatedFiles(item: DownloadedItem): void {
|
||||
// Delete trickplay directory
|
||||
if (item.trickPlayData?.path) {
|
||||
try {
|
||||
const trickplayDirName = item.trickPlayData.path.split("/").pop();
|
||||
if (trickplayDirName) {
|
||||
const trickplayDir = new Directory(Paths.document, trickplayDirName);
|
||||
if (trickplayDir.exists) {
|
||||
trickplayDir.delete();
|
||||
console.log(
|
||||
`[DELETE] Trickplay directory deleted: ${trickplayDirName}`,
|
||||
);
|
||||
}
|
||||
// Use the full path from trickPlayData (it's already a full file:// URI)
|
||||
const trickplayDir = new Directory(item.trickPlayData.path);
|
||||
if (trickplayDir.exists) {
|
||||
trickplayDir.delete();
|
||||
console.log(
|
||||
`[DELETE] Trickplay directory deleted: ${item.trickPlayData.path}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[DELETE] Failed to delete trickplay directory:", error);
|
||||
@@ -96,5 +92,24 @@ export function getDownloadedItemSize(id: string): number {
|
||||
*/
|
||||
export function calculateTotalDownloadedSize(): number {
|
||||
const items = getAllDownloadedItems();
|
||||
return items.reduce((sum, item) => sum + (item.videoFileSize || 0), 0);
|
||||
return items.reduce((sum, item) => {
|
||||
// Trickplay bytes count too — getDownloadedItemSize models per-item size
|
||||
// as video + trickplay, the total must match.
|
||||
const trickplaySize = item.trickPlayData?.size ?? 0;
|
||||
// Read the live file size on disk so the total reflects actual usage and
|
||||
// self-heals items whose stored videoFileSize is 0 (old schema, or
|
||||
// `fileInfo.size` was undefined at download time). Fall back to the stored
|
||||
// value if the file can't be stat'd.
|
||||
if (item.videoFilePath) {
|
||||
try {
|
||||
const file = new File(filePathToUri(item.videoFilePath));
|
||||
if (file.exists) {
|
||||
return sum + (file.size ?? item.videoFileSize ?? 0) + trickplaySize;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Failed to stat downloaded file for size:", error);
|
||||
}
|
||||
}
|
||||
return sum + (item.videoFileSize ?? 0) + trickplaySize;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@ import { File, Paths } from "expo-file-system";
|
||||
import type { MutableRefObject } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform } from "react-native";
|
||||
import DeviceInfo from "react-native-device-info";
|
||||
import { toast } from "sonner-native";
|
||||
import type { Bitrate } from "@/components/BitrateSelector";
|
||||
import useImageStorage from "@/hooks/useImageStorage";
|
||||
import { BackgroundDownloader } from "@/modules";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { getOrSetDeviceId } from "@/utils/device";
|
||||
import useDownloadHelper from "@/utils/download";
|
||||
import { getStoragePath } from "@/utils/storage";
|
||||
import { downloadAdditionalAssets } from "../additionalDownloads";
|
||||
import {
|
||||
clearAllDownloadedItems,
|
||||
@@ -49,6 +52,7 @@ export function useDownloadOperations({
|
||||
onDataChange,
|
||||
}: UseDownloadOperationsProps) {
|
||||
const { t } = useTranslation();
|
||||
const { settings } = useSettings();
|
||||
const { saveSeriesPrimaryImage } = useDownloadHelper();
|
||||
const { saveImage } = useImageStorage();
|
||||
|
||||
@@ -81,6 +85,12 @@ export function useDownloadOperations({
|
||||
return;
|
||||
}
|
||||
|
||||
// Get storage path if custom location is set
|
||||
let storagePath: string | undefined;
|
||||
if (Platform.OS === "android" && settings.downloadStorageLocation) {
|
||||
storagePath = await getStoragePath(settings.downloadStorageLocation);
|
||||
}
|
||||
|
||||
// Download all additional assets BEFORE starting native video download
|
||||
const additionalAssets = await downloadAdditionalAssets({
|
||||
item,
|
||||
@@ -88,6 +98,7 @@ export function useDownloadOperations({
|
||||
api,
|
||||
saveImageFn: saveImage,
|
||||
saveSeriesImageFn: saveSeriesPrimaryImage,
|
||||
storagePath,
|
||||
});
|
||||
|
||||
// Ensure URL is absolute (not relative) before storing
|
||||
@@ -123,10 +134,19 @@ export function useDownloadOperations({
|
||||
// Add to processes
|
||||
setProcesses((prev) => [...prev, jobStatus]);
|
||||
|
||||
// Generate destination path
|
||||
// Generate destination path using custom storage location if set
|
||||
const filename = generateFilename(item);
|
||||
const videoFile = new File(Paths.document, `${filename}.mp4`);
|
||||
const destinationPath = uriToFilePath(videoFile.uri);
|
||||
let destinationPath: string;
|
||||
|
||||
if (storagePath) {
|
||||
// Use custom storage location
|
||||
destinationPath = `${storagePath}/${filename}.mp4`;
|
||||
console.log(`[DOWNLOAD] Using custom storage: ${destinationPath}`);
|
||||
} else {
|
||||
// Use default Paths.document
|
||||
const videoFile = new File(Paths.document, `${filename}.mp4`);
|
||||
destinationPath = uriToFilePath(videoFile.uri);
|
||||
}
|
||||
|
||||
console.log(`[DOWNLOAD] Starting video: ${item.Name}`);
|
||||
console.log(`[DOWNLOAD] Download URL: ${downloadUrl}`);
|
||||
@@ -289,7 +309,24 @@ export function useDownloadOperations({
|
||||
);
|
||||
|
||||
const appSizeUsage = useCallback(async () => {
|
||||
const totalSize = calculateTotalDownloadedSize();
|
||||
let totalSize = calculateTotalDownloadedSize();
|
||||
|
||||
// Also count in-progress downloads (they write straight to their final
|
||||
// path) so the growing file shows up as app usage instead of drifting
|
||||
// into the generic device share until completion.
|
||||
for (const process of processes) {
|
||||
try {
|
||||
const file = new File(
|
||||
Paths.document,
|
||||
`${generateFilename(process.item)}.mp4`,
|
||||
);
|
||||
if (file.exists) {
|
||||
totalSize += file.size ?? 0;
|
||||
}
|
||||
} catch {
|
||||
// File not created yet — ignore.
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const [freeDiskStorage, totalDiskCapacity] = await Promise.all([
|
||||
@@ -310,7 +347,7 @@ export function useDownloadOperations({
|
||||
appSize: totalSize,
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
}, [processes]);
|
||||
|
||||
return {
|
||||
startBackgroundDownload,
|
||||
|
||||
@@ -386,7 +386,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
||||
default:
|
||||
throw new Error(
|
||||
t(
|
||||
"login.an_unexpected_error_occured_did_you_enter_the_correct_url",
|
||||
"login.an_unexpected_error_occurred_did_you_enter_the_correct_url",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "حسنًا",
|
||||
"connection_failed": "فشل الاتصال",
|
||||
"could_not_connect_to_server": "تعذر الاتصال بالخادم. يرجى التحقق من الرابط واتصال الشبكة.",
|
||||
"an_unexpected_error_occured": "حدث خطأ غير متوقع",
|
||||
"an_unexpected_error_occurred": "حدث خطأ غير متوقع",
|
||||
"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": "حدث خطأ غير متوقع. هل أدخلت رابط الخادم بشكل صحيح؟",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "حدث خطأ غير متوقع. هل أدخلت رابط الخادم بشكل صحيح؟",
|
||||
"too_old_server_text": "تم اكتشاف خادم Jellyfin غير مدعوم",
|
||||
"too_old_server_description": "يرجى تحديث Jellyfin إلى أحدث إصدار"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "تفويض الدخول السريع",
|
||||
"enter_the_quick_connect_code": "أدخل رمز الدخول السريع...",
|
||||
"success": "نجاح",
|
||||
"quick_connect_autorized": "تم تفويض الدخول السريع",
|
||||
"quick_connect_authorized": "تم تفويض الدخول السريع",
|
||||
"error": "خطأ",
|
||||
"invalid_code": "رمز غير صالح",
|
||||
"authorize": "تفويض"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "إظهار روابط القائمة المخصصة",
|
||||
"show_large_home_carousel": "إظهار شريط العرض الكبير (تجريبي)",
|
||||
"hide_libraries": "إخفاء المكتبات",
|
||||
"select_liraries_you_want_to_hide": "اختر المكتبات التي تريد إخفاءها من تبويب المكتبة وأقسام الصفحة الرئيسية.",
|
||||
"select_libraries_you_want_to_hide": "اختر المكتبات التي تريد إخفاءها من تبويب المكتبة وأقسام الصفحة الرئيسية.",
|
||||
"disable_haptic_feedback": "تعطيل ردود الفعل اللمسية",
|
||||
"default_quality": "الجودة الافتراضية",
|
||||
"default_playback_speed": "سرعة التشغيل الافتراضية",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "الجهاز {{availableSpace}}%",
|
||||
"size_used": "تم استخدام {{used}} من {{total}}",
|
||||
"delete_all_downloaded_files": "حذف جميع الملفات التي تم تنزيلها",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "التخزين المؤقت للموسيقى",
|
||||
"music_cache_description": "تخزين الأغاني تلقائياً أثناء الاستماع لضمان تشغيل أكثر سلاسة ودعم الاستماع بدون اتصال",
|
||||
"clear_music_cache": "مسح التخزين المؤقت للموسيقى",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "خطأ",
|
||||
"failed_to_get_stream_url": "فشل في الحصول على رابط البث",
|
||||
"an_error_occured_while_playing_the_video": "حدث خطأ أثناء تشغيل الفيديو. تحقق من السجلات في الإعدادات.",
|
||||
"an_error_occurred_while_playing_the_video": "حدث خطأ أثناء تشغيل الفيديو. تحقق من السجلات في الإعدادات.",
|
||||
"client_error": "خطأ في المشغّل",
|
||||
"could_not_create_stream_for_chromecast": "تعذر إنشاء بث لـChromecast",
|
||||
"message_from_server": "رسالة من الخادم: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Entesos",
|
||||
"connection_failed": "Ha fallat la connexió",
|
||||
"could_not_connect_to_server": "No s'ha pogut connectar amb el servidor. Comproveu l'URL i la connexió de xarxa.",
|
||||
"an_unexpected_error_occured": "S'ha produït un error inesperat",
|
||||
"an_unexpected_error_occurred": "S'ha produït un error inesperat",
|
||||
"change_server": "Canvia el servidor",
|
||||
"invalid_username_or_password": "Nom d'usuari o contrasenya incorrectes",
|
||||
"user_does_not_have_permission_to_log_in": "L'usuari no té permís per iniciar sessió",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "El servidor triga massa a respondre, torneu-ho a provar més tard",
|
||||
"server_received_too_many_requests_try_again_later": "El servidor ha rebut massa sol·licituds, torneu-ho a provar més tard.",
|
||||
"there_is_a_server_error": "Error del servidor",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "S'ha produït un error inesperat. Heu introduït correctament l'URL del servidor?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "S'ha produït un error inesperat. Heu introduït correctament l'URL del servidor?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autoritza connexió ràpida",
|
||||
"enter_the_quick_connect_code": "Introdueix el codi de connexió ràpida...",
|
||||
"success": "Èxit",
|
||||
"quick_connect_autorized": "Connexió ràpida autoritzada",
|
||||
"quick_connect_authorized": "Connexió ràpida autoritzada",
|
||||
"error": "Error",
|
||||
"invalid_code": "Codi invàlid",
|
||||
"authorize": "Autoritza"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Mostrar enllaços del menú personalitzats",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Oculta biblioteques",
|
||||
"select_liraries_you_want_to_hide": "Seleccioneu les biblioteques que voleu ocultar de la pestanya Biblioteca i de les seccions de la pàgina d'inici.",
|
||||
"select_libraries_you_want_to_hide": "Seleccioneu les biblioteques que voleu ocultar de la pestanya Biblioteca i de les seccions de la pàgina d'inici.",
|
||||
"disable_haptic_feedback": "Desactiva la resposta hàptica",
|
||||
"default_quality": "Qualitat per defecte",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Dispositiu {{availableSpace}}%",
|
||||
"size_used": "{{used}} de {{total}} utilitzat",
|
||||
"delete_all_downloaded_files": "Suprimeix tots els fitxers descarregats",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Error",
|
||||
"failed_to_get_stream_url": "No s'ha pogut obtenir l'URL del flux",
|
||||
"an_error_occured_while_playing_the_video": "S'ha produït un error en reproduir el vídeo. Consulteu els registres a la configuració.",
|
||||
"an_error_occurred_while_playing_the_video": "S'ha produït un error en reproduir el vídeo. Consulteu els registres a la configuració.",
|
||||
"client_error": "Error del client",
|
||||
"could_not_create_stream_for_chromecast": "No s'ha pogut crear un flux per a Chromecast",
|
||||
"message_from_server": "Missatge del servidor: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Rozumím",
|
||||
"connection_failed": "Připojení se nezdařilo",
|
||||
"could_not_connect_to_server": "Nelze se připojit k serveru. Zkontrolujte adresu URL a síťové připojení.",
|
||||
"an_unexpected_error_occured": "Došlo k neočekávané chybě",
|
||||
"an_unexpected_error_occurred": "Došlo k neočekávané chybě",
|
||||
"change_server": "Změnit server",
|
||||
"invalid_username_or_password": "Neplatné uživatelské jméno nebo heslo",
|
||||
"user_does_not_have_permission_to_log_in": "Uživatel nemá oprávnění k přihlášení",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Reakce na server trvá příliš dlouho, zkuste to znovu později",
|
||||
"server_received_too_many_requests_try_again_later": "Server obdržel příliš mnoho požadavků, opakujte akci později.",
|
||||
"there_is_a_server_error": "Došlo k chybě serveru",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Došlo k neočekávané chybě. Vložili jste adresu URL serveru?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Došlo k neočekávané chybě. Vložili jste adresu URL serveru?",
|
||||
"too_old_server_text": "Objeven nepodporovaný Jellyfin server",
|
||||
"too_old_server_description": "Prosím aktualizujte Jellyfin na nejnovější verzi"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autorizovat rychlé připojení",
|
||||
"enter_the_quick_connect_code": "Zadejte kód rychlého připojení...",
|
||||
"success": "Úspěšně",
|
||||
"quick_connect_autorized": "Oprávněné Rychlé připojení",
|
||||
"quick_connect_authorized": "Oprávněné Rychlé připojení",
|
||||
"error": "Chyba",
|
||||
"invalid_code": "Neplatný kód",
|
||||
"authorize": "Autorizovat"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Zobrazit vlastní Menu odkazy",
|
||||
"show_large_home_carousel": "Zobrazit velký přehled (beta)",
|
||||
"hide_libraries": "Skrýt knihovny",
|
||||
"select_liraries_you_want_to_hide": "Vyberte knihovny, které chcete skrýt v záložce Knihovna a v sekcích domovské stránky.",
|
||||
"select_libraries_you_want_to_hide": "Vyberte knihovny, které chcete skrýt v záložce Knihovna a v sekcích domovské stránky.",
|
||||
"disable_haptic_feedback": "Zakázat Haptickou zpětnou vazbu",
|
||||
"default_quality": "Výchozí kvalita",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Zařízení {{availableSpace}}%",
|
||||
"size_used": "{{used}} z {{total}} využito",
|
||||
"delete_all_downloaded_files": "Odstranit všechny stažené soubory",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Chyba",
|
||||
"failed_to_get_stream_url": "Nepodařilo se získat URL streamu",
|
||||
"an_error_occured_while_playing_the_video": "Při přehrávání videa došlo k chybě. Zkontrolujte logy v nastavení.",
|
||||
"an_error_occurred_while_playing_the_video": "Při přehrávání videa došlo k chybě. Zkontrolujte logy v nastavení.",
|
||||
"client_error": "Chyba klienta",
|
||||
"could_not_create_stream_for_chromecast": "Nelze vytvořit stream pro Chromecast",
|
||||
"message_from_server": "Zpráva od serveru: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Forstået",
|
||||
"connection_failed": "Forbindelsen mislykkedes",
|
||||
"could_not_connect_to_server": "Kunne ikke oprette forbindelse til serveren. Tjek venligst URL'en og din netværksforbindelse.",
|
||||
"an_unexpected_error_occured": "Der opstod en uventet fejl",
|
||||
"an_unexpected_error_occurred": "Der opstod en uventet fejl",
|
||||
"change_server": "Skift server",
|
||||
"invalid_username_or_password": "Ugyldigt brugernavn eller adgangskode",
|
||||
"user_does_not_have_permission_to_log_in": "Brugeren har ikke tilladelse til at logge ind",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Serveren svarer for langsomt, prøv igen senere",
|
||||
"server_received_too_many_requests_try_again_later": "Serveren modtog for mange forespørgsler, prøv igen senere.",
|
||||
"there_is_a_server_error": "Der er en serverfejl",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Der opstod en uventet fejl. Har du indtastet serverens URL korrekt?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Der opstod en uventet fejl. Har du indtastet serverens URL korrekt?",
|
||||
"too_old_server_text": "Ikke Understøttet Jellyfin Server Opdaget",
|
||||
"too_old_server_description": "Opdater venligst Jellyfin til den seneste version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autoriser Hurtigforbindelse",
|
||||
"enter_the_quick_connect_code": "Indtast koden til hurtigforbindelse...",
|
||||
"success": "Succes",
|
||||
"quick_connect_autorized": "Hurtigforbindelse autoriseret",
|
||||
"quick_connect_authorized": "Hurtigforbindelse autoriseret",
|
||||
"error": "Fejl",
|
||||
"invalid_code": "Ugyldig kode",
|
||||
"authorize": "Autoriser"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Vis tilpassede menulinks",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Skjul biblioteker",
|
||||
"select_liraries_you_want_to_hide": "Vælg de biblioteker, du ønsker at skjule fra fanen Bibliotek og startside sektionerne.",
|
||||
"select_libraries_you_want_to_hide": "Vælg de biblioteker, du ønsker at skjule fra fanen Bibliotek og startside sektionerne.",
|
||||
"disable_haptic_feedback": "Deaktiver haptisk feedback",
|
||||
"default_quality": "Standard kvalitet",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Enhedsforbrug: {{availableSpace}}%",
|
||||
"size_used": "{{used}} af {{total}} brugt",
|
||||
"delete_all_downloaded_files": "Slet alle downloadede filer",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Fejl",
|
||||
"failed_to_get_stream_url": "Kunne ikke hente stream URL'en",
|
||||
"an_error_occured_while_playing_the_video": "Der opstod en fejl under afspilning af videoen. Tjek logfilerne i indstillinger.",
|
||||
"an_error_occurred_while_playing_the_video": "Der opstod en fejl under afspilning af videoen. Tjek logfilerne i indstillinger.",
|
||||
"client_error": "Klientfejl",
|
||||
"could_not_create_stream_for_chromecast": "Kunne ikke oprette en stream til Chromecast",
|
||||
"message_from_server": "Besked fra server: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Verstanden",
|
||||
"connection_failed": "Verbindung fehlgeschlagen",
|
||||
"could_not_connect_to_server": "Verbindung zum Server fehlgeschlagen. Bitte überprüf die URL und deine Netzwerkverbindung.",
|
||||
"an_unexpected_error_occured": "Ein unerwarteter Fehler ist aufgetreten",
|
||||
"an_unexpected_error_occurred": "Ein unerwarteter Fehler ist aufgetreten",
|
||||
"change_server": "Server wechseln",
|
||||
"invalid_username_or_password": "Ungültiger Benutzername oder Passwort",
|
||||
"user_does_not_have_permission_to_log_in": "Benutzer hat keine Berechtigung, um sich anzumelden",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Der Server benötigt zu lange, um zu antworten. Bitte versuch es später erneut",
|
||||
"server_received_too_many_requests_try_again_later": "Der Server hat zu viele Anfragen erhalten. Bitte versuch es später erneut.",
|
||||
"there_is_a_server_error": "Es gibt einen Serverfehler",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Ein unerwarteter Fehler ist aufgetreten. Hast du die Server-URL korrekt eingegeben?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Ein unerwarteter Fehler ist aufgetreten. Hast du die Server-URL korrekt eingegeben?",
|
||||
"too_old_server_text": "Nicht unterstützter Jellyfin Server entdeckt",
|
||||
"too_old_server_description": "Bitte aktualisiere Jellyfin auf die neueste Version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Quick Connect autorisieren",
|
||||
"enter_the_quick_connect_code": "Quick Connect-Code eingeben...",
|
||||
"success": "Erfolgreich verbunden",
|
||||
"quick_connect_autorized": "Quick Connect autorisiert",
|
||||
"quick_connect_authorized": "Quick Connect autorisiert",
|
||||
"error": "Fehler",
|
||||
"invalid_code": "Ungültiger Code",
|
||||
"authorize": "Autorisieren"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Benutzerdefinierte Menülinks anzeigen",
|
||||
"show_large_home_carousel": "Zeige große Startseiten-Übersicht (Beta)",
|
||||
"hide_libraries": "Bibliotheken ausblenden",
|
||||
"select_liraries_you_want_to_hide": "Bibliotheken auswählen die aus dem Bibliothekstab und der Startseite ausgeblendet werden sollen.",
|
||||
"select_libraries_you_want_to_hide": "Bibliotheken auswählen die aus dem Bibliothekstab und der Startseite ausgeblendet werden sollen.",
|
||||
"disable_haptic_feedback": "Haptisches Feedback deaktivieren",
|
||||
"default_quality": "Standardqualität",
|
||||
"default_playback_speed": "Standard-Wiedergabegeschwindigkeit",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Gerät {{availableSpace}}%",
|
||||
"size_used": "{{used}} von {{total}} genutzt",
|
||||
"delete_all_downloaded_files": "Alle heruntergeladenen Dateien löschen",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Musik-Cache",
|
||||
"music_cache_description": "Beim Anhören Titel automatisch in den Cache laden um bessere Wiedergabe und Offline-Wiedergabe zu ermöglichen",
|
||||
"clear_music_cache": "Musik-Cache leeren",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Fehler",
|
||||
"failed_to_get_stream_url": "Fehler beim Abrufen der Stream-URL",
|
||||
"an_error_occured_while_playing_the_video": "Ein Fehler ist beim Abspielen des Videos aufgetreten. Logs in den Einstellungen überprüfen.",
|
||||
"an_error_occurred_while_playing_the_video": "Ein Fehler ist beim Abspielen des Videos aufgetreten. Logs in den Einstellungen überprüfen.",
|
||||
"client_error": "Client-Fehler",
|
||||
"could_not_create_stream_for_chromecast": "Konnte keinen Stream für Chromecast erstellen",
|
||||
"message_from_server": "Nachricht vom Server: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Το Κατάλαβα",
|
||||
"connection_failed": "Η Σύνδεση Απέτυχε",
|
||||
"could_not_connect_to_server": "Δεν ήταν δυνατή η σύνδεση με τον διακομιστή. Παρακαλώ ελέγξτε τη διεύθυνση URL και τη σύνδεση δικτύου σας.",
|
||||
"an_unexpected_error_occured": "Παρουσιάστηκε Απροσδόκητο Σφάλμα",
|
||||
"an_unexpected_error_occurred": "Παρουσιάστηκε Απροσδόκητο Σφάλμα",
|
||||
"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 του διακομιστή?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Παρουσιάστηκε μη αναμενόμενο σφάλμα. Εισαγάγετε σωστά το URL του διακομιστή?",
|
||||
"too_old_server_text": "Ανακαλύφθηκε Μη Υποστηριζόμενος Εξυπηρετητής Jellyfin",
|
||||
"too_old_server_description": "Παρακαλούμε ενημερώστε το Jellyfin στην τελευταία έκδοση"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Εξουσιοδότηση Γρήγορης Σύνδεσης",
|
||||
"enter_the_quick_connect_code": "Εισάγετε τον κωδικό γρήγορης σύνδεσης...",
|
||||
"success": "Επιτυχία",
|
||||
"quick_connect_autorized": "Γρήγορη Σύνδεση Εξουσιοδοτήθηκε",
|
||||
"quick_connect_authorized": "Γρήγορη Σύνδεση Εξουσιοδοτήθηκε",
|
||||
"error": "Σφάλμα",
|
||||
"invalid_code": "Μη Έγκυρος Κωδικός",
|
||||
"authorize": "Εξουσιοδότηση"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Εμφάνιση Προσαρμοσμένων Συνδέσμων Μενού",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Απόκρυψη Βιβλιοθηκών",
|
||||
"select_liraries_you_want_to_hide": "Επιλέξτε τις βιβλιοθήκες που θέλετε να αποκρύψετε από την καρτέλα της Βιβλιοθήκης και τις ενότητες της αρχικής σελίδας.",
|
||||
"select_libraries_you_want_to_hide": "Επιλέξτε τις βιβλιοθήκες που θέλετε να αποκρύψετε από την καρτέλα της Βιβλιοθήκης και τις ενότητες της αρχικής σελίδας.",
|
||||
"disable_haptic_feedback": "Απενεργοποίηση Απτικής Ανατροφοδότησης",
|
||||
"default_quality": "Προεπιλεγμένη Ποιότητα",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Device {{availableSpace}}%",
|
||||
"size_used": "{{used}} {{total}} Χρησιμοποιείται",
|
||||
"delete_all_downloaded_files": "Διαγραφή Όλων Των Ληφθέντων Αρχείων",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Σφάλμα",
|
||||
"failed_to_get_stream_url": "Αποτυχία λήψης του URL ροής",
|
||||
"an_error_occured_while_playing_the_video": "Παρουσιάστηκε σφάλμα κατά την αναπαραγωγή του βίντεο. Ελέγξτε τα αρχεία καταγραφής στις ρυθμίσεις.",
|
||||
"an_error_occurred_while_playing_the_video": "Παρουσιάστηκε σφάλμα κατά την αναπαραγωγή του βίντεο. Ελέγξτε τα αρχεία καταγραφής στις ρυθμίσεις.",
|
||||
"client_error": "Σφάλμα Πελάτη",
|
||||
"could_not_create_stream_for_chromecast": "Αδυναμία δημιουργίας ροής για το Chromecast",
|
||||
"message_from_server": "Μήνυμα από το διακομιστή: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Got it",
|
||||
"connection_failed": "Connection failed",
|
||||
"could_not_connect_to_server": "Could not connect to the server. Please check the URL and your network connection.",
|
||||
"an_unexpected_error_occured": "An unexpected error occurred",
|
||||
"an_unexpected_error_occurred": "An unexpected error occurred",
|
||||
"change_server": "Change server",
|
||||
"invalid_username_or_password": "Invalid username or password",
|
||||
"user_does_not_have_permission_to_log_in": "User does not have permission to log in",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Server is taking too long to respond, try again later",
|
||||
"server_received_too_many_requests_try_again_later": "Server received too many requests, try again later.",
|
||||
"there_is_a_server_error": "There is a server error",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "An unexpected error occurred. Did you enter the server URL correctly?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "An unexpected error occurred. Did you enter the server URL correctly?",
|
||||
"too_old_server_text": "Unsupported Jellyfin server discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Authorize Quick Connect",
|
||||
"enter_the_quick_connect_code": "Enter the Quick Connect code...",
|
||||
"success": "Success",
|
||||
"quick_connect_autorized": "Quick Connect authorized",
|
||||
"quick_connect_authorized": "Quick Connect authorized",
|
||||
"error": "Error",
|
||||
"invalid_code": "Invalid code",
|
||||
"authorize": "Authorize"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Show custom menu links",
|
||||
"show_large_home_carousel": "Show large home carousel (beta)",
|
||||
"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.",
|
||||
"select_libraries_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_playback_speed": "Default playback speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Device {{availableSpace}}%",
|
||||
"size_used": "{{used}} of {{total}} used",
|
||||
"delete_all_downloaded_files": "Delete all downloaded files",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear music cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV player",
|
||||
"error": "Error",
|
||||
"failed_to_get_stream_url": "Failed to get the stream URL",
|
||||
"an_error_occured_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"an_error_occurred_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"client_error": "Client error",
|
||||
"could_not_create_stream_for_chromecast": "Could not create a stream for Chromecast",
|
||||
"message_from_server": "Message from server: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Entendido",
|
||||
"connection_failed": "Conexión fallida",
|
||||
"could_not_connect_to_server": "No se pudo conectar al servidor. Por favor comprueba la URL y tu conexión de red.",
|
||||
"an_unexpected_error_occured": "Ha ocurrido un error inesperado",
|
||||
"an_unexpected_error_occurred": "Ha ocurrido un error inesperado",
|
||||
"change_server": "Cambiar servidor",
|
||||
"invalid_username_or_password": "Usuario o contraseña inválidos",
|
||||
"user_does_not_have_permission_to_log_in": "El usuario no tiene permiso para iniciar sesión",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "El servidor está tardando mucho en responder, inténtalo de nuevo más tarde.",
|
||||
"server_received_too_many_requests_try_again_later": "El servidor está recibiendo muchas peticiones, inténtalo de nuevo más tarde.",
|
||||
"there_is_a_server_error": "Hay un error en el servidor",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Ha ocurrido un error inesperado. ¿Has introducido la URL correcta?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Ha ocurrido un error inesperado. ¿Has introducido la URL correcta?",
|
||||
"too_old_server_text": "Servidor Jellyfin no soportado descubierto",
|
||||
"too_old_server_description": "Por favor, actualiza Jellyfin a la última versión"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autorizar conexión rápida",
|
||||
"enter_the_quick_connect_code": "Introduce el código de conexión rápida...",
|
||||
"success": "Hecho",
|
||||
"quick_connect_autorized": "Conexión rápida autorizada",
|
||||
"quick_connect_authorized": "Conexión rápida autorizada",
|
||||
"error": "Error",
|
||||
"invalid_code": "Código inválido",
|
||||
"authorize": "Autorizar"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Mostrar enlaces de menú personalizados",
|
||||
"show_large_home_carousel": "Mostrar carrusel del menú principal grande (beta)",
|
||||
"hide_libraries": "Ocultar bibliotecas",
|
||||
"select_liraries_you_want_to_hide": "Selecciona las bibliotecas que quieres ocultar de la pestaña Bibliotecas y de Inicio.",
|
||||
"select_libraries_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_playback_speed": "Velocidad de reproducción predeterminada",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Dispositivo {{availableSpace}}%",
|
||||
"size_used": "{{used}} de {{total}} usado",
|
||||
"delete_all_downloaded_files": "Eliminar todos los archivos descargados",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Caché de música",
|
||||
"music_cache_description": "Cachear automáticamente las canciones mientras escuchas una reproducción más suave y soporte sin conexión",
|
||||
"clear_music_cache": "Borrar Caché de Música",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Error",
|
||||
"failed_to_get_stream_url": "Error al obtener la URL del Steam",
|
||||
"an_error_occured_while_playing_the_video": "Ha ocurrido un error al reproducir el vídeo. Comprueba los registros en la configuración.",
|
||||
"an_error_occurred_while_playing_the_video": "Ha ocurrido un error al reproducir el vídeo. Comprueba los registros en la configuración.",
|
||||
"client_error": "Error del cliente",
|
||||
"could_not_create_stream_for_chromecast": "No se pudo crear el Steam para Chromecast",
|
||||
"message_from_server": "Mensaje del servidor: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Okei",
|
||||
"connection_failed": "Yhteys epäonnistui",
|
||||
"could_not_connect_to_server": "Yhteyttä palvelimeen ei voitu muodostaa. Tarkista URL-osoite ja verkkoyhteytesi.",
|
||||
"an_unexpected_error_occured": "Odottamaton virhe tapahtui",
|
||||
"an_unexpected_error_occurred": "Odottamaton virhe tapahtui",
|
||||
"change_server": "Vaihda palvelinta",
|
||||
"invalid_username_or_password": "Virheellinen käyttäjätunnus tai salasana",
|
||||
"user_does_not_have_permission_to_log_in": "Käyttäjällä ei ole oikeuksia kirjautua sisään",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Palvelin reagoi liian hitaasti, yritä myöhemmin uudelleen",
|
||||
"server_received_too_many_requests_try_again_later": "Palvelin sai liian monta pyyntöä, yritä myöhemmin uudelleen.",
|
||||
"there_is_a_server_error": "Palvelimessa on virhe",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Odottamaton virhe tapahtui. Syötitkö palvelimen URL-osoitteen oikein?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Odottamaton virhe tapahtui. Syötitkö palvelimen URL-osoitteen oikein?",
|
||||
"too_old_server_text": "Ei-tuettu Jellyfin-palvelin löydetty",
|
||||
"too_old_server_description": "Ole hyvä ja päivitä Jellyfin uusimpaan versioon"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Valtuuta pikayhdistys",
|
||||
"enter_the_quick_connect_code": "Syötä nopean yhteyden koodi...",
|
||||
"success": "Onnistui",
|
||||
"quick_connect_autorized": "Pikayhdistys valtuutettu",
|
||||
"quick_connect_authorized": "Pikayhdistys valtuutettu",
|
||||
"error": "Virhe",
|
||||
"invalid_code": "Virheellinen koodi",
|
||||
"authorize": "Valtuuta"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Näytä mukautetut valikkolinkit",
|
||||
"show_large_home_carousel": "Näytä suuri kotikaruselli (beta)",
|
||||
"hide_libraries": "Piilota kirjastot",
|
||||
"select_liraries_you_want_to_hide": "Valitse kirjastot, jotka haluat piilottaa Kirjasto-välilehdeltä ja etusivun osioista.",
|
||||
"select_libraries_you_want_to_hide": "Valitse kirjastot, jotka haluat piilottaa Kirjasto-välilehdeltä ja etusivun osioista.",
|
||||
"disable_haptic_feedback": "Poista haptinen palautteet käytöstä",
|
||||
"default_quality": "Oletuslaatu",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Laitteen käyttö {{availableSpace}}%",
|
||||
"size_used": "{{used}} / {{total}} käytössä",
|
||||
"delete_all_downloaded_files": "Poista kaikki ladatut tiedostot",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Virhe",
|
||||
"failed_to_get_stream_url": "Lähetyksen URL-osoitteen haku epäonnistui",
|
||||
"an_error_occured_while_playing_the_video": "Videon toiston yhteydessä tapahtui virhe. Tarkista lokit asetuksista.",
|
||||
"an_error_occurred_while_playing_the_video": "Videon toiston yhteydessä tapahtui virhe. Tarkista lokit asetuksista.",
|
||||
"client_error": "Asiakkaan Virhe",
|
||||
"could_not_create_stream_for_chromecast": "Suoratoistoa ei voitu luoda Chromecastia varten",
|
||||
"message_from_server": "Viesti palvelimelta: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "D'accord",
|
||||
"connection_failed": "La connexion a échoué",
|
||||
"could_not_connect_to_server": "Impossible de se connecter au serveur. Veuillez vérifier l’URL et votre connexion réseau.",
|
||||
"an_unexpected_error_occured": "Une erreur inattendue s'est produite",
|
||||
"an_unexpected_error_occurred": "Une erreur inattendue s'est produite",
|
||||
"change_server": "Changer de serveur",
|
||||
"invalid_username_or_password": "Nom d'utilisateur ou mot de passe invalide",
|
||||
"user_does_not_have_permission_to_log_in": "L'utilisateur n'a pas la permission de se connecter",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Le serveur prend trop de temps à répondre, réessayez plus tard",
|
||||
"server_received_too_many_requests_try_again_later": "Le serveur a reçu trop de demandes, réessayez plus tard.",
|
||||
"there_is_a_server_error": "Il y a une erreur de serveur",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Une erreur inattendue s’est produite. Avez-vous correctement saisi l’URL du serveur ?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Une erreur inattendue s’est produite. Avez-vous correctement saisi l’URL du serveur ?",
|
||||
"too_old_server_text": "Serveur Jellyfin non pris en charge découvert",
|
||||
"too_old_server_description": "Veuillez mettre à jour Jellyfin vers la dernière version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autoriser une connexion rapide",
|
||||
"enter_the_quick_connect_code": "Entrez le code de connexion rapide...",
|
||||
"success": "Succès",
|
||||
"quick_connect_autorized": "Connexion rapide autorisée",
|
||||
"quick_connect_authorized": "Connexion rapide autorisée",
|
||||
"error": "Erreur",
|
||||
"invalid_code": "Code invalide",
|
||||
"authorize": "Autoriser"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Afficher les liens personnalisés",
|
||||
"show_large_home_carousel": "Afficher le grand carrousel d’accueil (bêta)",
|
||||
"hide_libraries": "Masquer les 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.",
|
||||
"select_libraries_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_playback_speed": "Vitesse de lecture par défaut",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Appareil {{availableSpace}}%",
|
||||
"size_used": "{{used}} de {{total}} utilisés",
|
||||
"delete_all_downloaded_files": "Supprimer tous les fichiers téléchargés",
|
||||
"delete_all_downloaded_files_confirm": "Supprimer tous les fichiers téléchargés ?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Êtes-vous sûr de vouloir supprimer tous les fichiers téléchargés ? Cette action est irréversible.",
|
||||
"music_cache_title": "Mise en cache de la musique",
|
||||
"music_cache_description": "Mettez automatiquement en cache les chansons au fur et à mesure que vous écoutez pour une lecture plus fluide et une prise en charge hors ligne",
|
||||
"clear_music_cache": "Vider le cache de la musique",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "Lecteur MPV",
|
||||
"error": "Erreur",
|
||||
"failed_to_get_stream_url": "Échec de l'obtention de l'URL du flux",
|
||||
"an_error_occured_while_playing_the_video": "Une erreur s’est produite lors de la lecture de la vidéo. Vérifiez les journaux dans les paramètres.",
|
||||
"an_error_occurred_while_playing_the_video": "Une erreur s’est produite lors de la lecture de la vidéo. Vérifiez les journaux dans les paramètres.",
|
||||
"client_error": "Erreur du client",
|
||||
"could_not_create_stream_for_chromecast": "Impossible de créer un flux sur la Chromecast",
|
||||
"message_from_server": "Message du serveur : {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "קיבלתי",
|
||||
"connection_failed": "ההתחברות נכשלה",
|
||||
"could_not_connect_to_server": "לא היה ניתן להתחבר לשרת. אנא בדוק את הקישור ואת חיבור הרשת שלך.",
|
||||
"an_unexpected_error_occured": "קרתה שגיאה לא צפויה",
|
||||
"an_unexpected_error_occurred": "קרתה שגיאה לא צפויה",
|
||||
"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": "קרתה שגיאה לא צפויה. האם כתובת השרת שהוקלדה נכונה?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "קרתה שגיאה לא צפויה. האם כתובת השרת שהוקלדה נכונה?",
|
||||
"too_old_server_text": "נמצא שרת Jellyfin שלא נתמך",
|
||||
"too_old_server_description": "אנא עדכן את גרסת ה-Jellyfin למעודכנת ביותר"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "אשר התחברות מהירה",
|
||||
"enter_the_quick_connect_code": "הקלד את קוד ההתחברות המהירה...",
|
||||
"success": "הצלחה",
|
||||
"quick_connect_autorized": "חיבור מהיר אושר",
|
||||
"quick_connect_authorized": "חיבור מהיר אושר",
|
||||
"error": "שגיאה",
|
||||
"invalid_code": "קוד שגוי",
|
||||
"authorize": "אשר"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "הצג קישורים לתפריטים מותאמים אישית",
|
||||
"show_large_home_carousel": "הצג קרוסלה גדולה במסך הבית (בטא)",
|
||||
"hide_libraries": "הסתר ספריות",
|
||||
"select_liraries_you_want_to_hide": "בחר את הספריות שתרצה להסתיר ממסך הספריות וגם ממסך הבית.",
|
||||
"select_libraries_you_want_to_hide": "בחר את הספריות שתרצה להסתיר ממסך הספריות וגם ממסך הבית.",
|
||||
"disable_haptic_feedback": "בטל משוב רטט",
|
||||
"default_quality": "איכות ברירת מחדל",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "מכשיר {{availableSpace}}%",
|
||||
"size_used": "השתמשת ב-{{used}} מתוך {{total}}",
|
||||
"delete_all_downloaded_files": "מחק את כל הקבצים שהורדו",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "שגיאה",
|
||||
"failed_to_get_stream_url": "נכשל בהשגת קישור הזרם",
|
||||
"an_error_occured_while_playing_the_video": "קרתה תקלה במהלך הניגון של הקובץ. בדוק את הלוגים בהגדרות.",
|
||||
"an_error_occurred_while_playing_the_video": "קרתה תקלה במהלך הניגון של הקובץ. בדוק את הלוגים בהגדרות.",
|
||||
"client_error": "שגיאת לקוח",
|
||||
"could_not_create_stream_for_chromecast": "נכשל ביצירת זרם עבור Chromecast",
|
||||
"message_from_server": "הודעה מהשרת: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Értettem",
|
||||
"connection_failed": "Kapcsolódás Sikertelen",
|
||||
"could_not_connect_to_server": "Nem sikerült csatlakozni a szerverhez. Kérjük, ellenőrizd az URL-t és a hálózati kapcsolatot.",
|
||||
"an_unexpected_error_occured": "Váratlan Hiba Történt",
|
||||
"an_unexpected_error_occurred": "Váratlan Hiba Történt",
|
||||
"change_server": "Szerverváltás",
|
||||
"invalid_username_or_password": "Érvénytelen Felhasználónév vagy Jelszó",
|
||||
"user_does_not_have_permission_to_log_in": "A felhasználónak nincs jogosultsága a bejelentkezéshez",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "A szerver túl sokáig válaszol, próbáld újra később",
|
||||
"server_received_too_many_requests_try_again_later": "A szerver túl sok kérést kapott, próbáld újra később.",
|
||||
"there_is_a_server_error": "Szerverhiba történt",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Váratlan hiba történt. Helyesen adtad meg a szerver URL-jét?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Váratlan hiba történt. Helyesen adtad meg a szerver URL-jét?",
|
||||
"too_old_server_text": "Nem Támogatott Jellyfin-szerver",
|
||||
"too_old_server_description": "Frissítsd a Jellyfint a legújabb verzióra"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Gyorscsatlakozás Engedélyezése",
|
||||
"enter_the_quick_connect_code": "Add meg a gyors csatlakozási kódot...",
|
||||
"success": "Siker",
|
||||
"quick_connect_autorized": "Gyorscsatlakozás Engedélyezve",
|
||||
"quick_connect_authorized": "Gyorscsatlakozás Engedélyezve",
|
||||
"error": "Hiba",
|
||||
"invalid_code": "Érvénytelen Kód",
|
||||
"authorize": "Engedélyezés"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Egyéni Menülinkek Megjelenítése",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Könyvtárak Elrejtése",
|
||||
"select_liraries_you_want_to_hide": "Válaszd ki azokat a könyvtárakat, amelyeket el szeretnél rejteni a Könyvtár fülön és a kezdőlapon.",
|
||||
"select_libraries_you_want_to_hide": "Válaszd ki azokat a könyvtárakat, amelyeket el szeretnél rejteni a Könyvtár fülön és a kezdőlapon.",
|
||||
"disable_haptic_feedback": "Haptikus Visszajelzés Letiltása",
|
||||
"default_quality": "Alapértelmezett Minőség",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Eszköz {{availableSpace}}%",
|
||||
"size_used": "{{used}} / {{total}} Használatban",
|
||||
"delete_all_downloaded_files": "Minden Letöltött Fájl Törlése",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Hiba",
|
||||
"failed_to_get_stream_url": "Nem sikerült lekérni a stream URL-t",
|
||||
"an_error_occured_while_playing_the_video": "Hiba történt a videó lejátszása közben. Ellenőrizd a naplókat a beállításokban.",
|
||||
"an_error_occurred_while_playing_the_video": "Hiba történt a videó lejátszása közben. Ellenőrizd a naplókat a beállításokban.",
|
||||
"client_error": "Kliens Hiba",
|
||||
"could_not_create_stream_for_chromecast": "A Chromecast stream létrehozása sikertelen volt",
|
||||
"message_from_server": "Üzenet a szervertől: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Capito",
|
||||
"connection_failed": "Connessione fallita",
|
||||
"could_not_connect_to_server": "Impossibile connettersi al server. Controllare l'URL e la connessione di rete.",
|
||||
"an_unexpected_error_occured": "Si è verificato un errore inaspettato",
|
||||
"an_unexpected_error_occurred": "Si è verificato un errore inaspettato",
|
||||
"change_server": "Cambiare il server",
|
||||
"invalid_username_or_password": "Nome utente o password non validi",
|
||||
"user_does_not_have_permission_to_log_in": "L'utente non ha il permesso di accedere",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Il server sta impiegando troppo tempo per rispondere, riprovare più tardi",
|
||||
"server_received_too_many_requests_try_again_later": "Il server ha ricevuto troppe richieste, riprovare più tardi.",
|
||||
"there_is_a_server_error": "Si è verificato un errore del server",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Si è verificato un errore imprevisto. L'URL del server è stato inserito correttamente?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Si è verificato un errore imprevisto. L'URL del server è stato inserito correttamente?",
|
||||
"too_old_server_text": "Scoperto Server Jellyfin non supportato",
|
||||
"too_old_server_description": "Aggiorna Jellyfin all'ultima versione"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autorizza Connessione Rapida",
|
||||
"enter_the_quick_connect_code": "Inserisci il codice per la Connessione Rapida...",
|
||||
"success": "Successo",
|
||||
"quick_connect_autorized": "Connessione Rapida autorizzata",
|
||||
"quick_connect_authorized": "Connessione Rapida autorizzata",
|
||||
"error": "Errore",
|
||||
"invalid_code": "Codice invalido",
|
||||
"authorize": "Autorizza"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Mostra i link del menu personalizzato",
|
||||
"show_large_home_carousel": "Mostra Carosello Grande nella Home (beta)",
|
||||
"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.",
|
||||
"select_libraries_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_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Dispositivo {{availableSpace}}%",
|
||||
"size_used": "{{used}} di {{total}} usato",
|
||||
"delete_all_downloaded_files": "Cancella Tutti i File Scaricati",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Precarica automaticamente i brani mentre ascolti per una riproduzione più fluida e il supporto offline",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Errore",
|
||||
"failed_to_get_stream_url": "Impossibile ottenere l'URL dello stream",
|
||||
"an_error_occured_while_playing_the_video": "Si è verificato un errore durante la riproduzione del video. Controllare i log nelle impostazioni.",
|
||||
"an_error_occurred_while_playing_the_video": "Si è verificato un errore durante la riproduzione del video. Controllare i log nelle impostazioni.",
|
||||
"client_error": "Errore del client",
|
||||
"could_not_create_stream_for_chromecast": "Impossibile creare uno stream per Chromecast",
|
||||
"message_from_server": "Messaggio dal server",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "了解",
|
||||
"connection_failed": "接続に失敗しました",
|
||||
"could_not_connect_to_server": "サーバーに接続できませんでした。URLとネットワーク接続を確認してください。",
|
||||
"an_unexpected_error_occured": "予期しないエラーが発生しました",
|
||||
"an_unexpected_error_occurred": "予期しないエラーが発生しました",
|
||||
"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を正しく入力しましたか?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "予期しないエラーが発生しました。サーバーのURLを正しく入力しましたか?",
|
||||
"too_old_server_text": "サポートされていないJellyfinサーバー発見",
|
||||
"too_old_server_description": "Jellyfinを最新バージョンにアップデートしてください"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "クイックコネクトを承認する",
|
||||
"enter_the_quick_connect_code": "クイックコネクトコードを入力...",
|
||||
"success": "成功しました",
|
||||
"quick_connect_autorized": "クイックコネクトが承認されました",
|
||||
"quick_connect_authorized": "クイックコネクトが承認されました",
|
||||
"error": "エラー",
|
||||
"invalid_code": "無効なコードです",
|
||||
"authorize": "承認"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "カスタムメニューのリンクを表示",
|
||||
"show_large_home_carousel": "大きなヒーロー(Beta)",
|
||||
"hide_libraries": "ライブラリを非表示",
|
||||
"select_liraries_you_want_to_hide": "ライブラリタブとホームページセクションから非表示にするライブラリを選択します。",
|
||||
"select_libraries_you_want_to_hide": "ライブラリタブとホームページセクションから非表示にするライブラリを選択します。",
|
||||
"disable_haptic_feedback": "触覚フィードバックを無効にする",
|
||||
"default_quality": "デフォルトの品質",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "デバイス {{availableSpace}}%",
|
||||
"size_used": "{{used}} / {{total}} 使用済み",
|
||||
"delete_all_downloaded_files": "すべてのダウンロードファイルを削除",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "エラー",
|
||||
"failed_to_get_stream_url": "ストリームURLを取得できませんでした",
|
||||
"an_error_occured_while_playing_the_video": "動画の再生中にエラーが発生しました。設定でログを確認してください。",
|
||||
"an_error_occurred_while_playing_the_video": "動画の再生中にエラーが発生しました。設定でログを確認してください。",
|
||||
"client_error": "クライアントエラー",
|
||||
"could_not_create_stream_for_chromecast": "Chromecastのストリームを作成できませんでした",
|
||||
"message_from_server": "サーバーからのメッセージ",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "성공",
|
||||
"connection_failed": "연결 실패",
|
||||
"could_not_connect_to_server": "서버에 연결되지 않았습니다. URL과 네트워크 상태를 확인하세요.",
|
||||
"an_unexpected_error_occured": "예기치 않은 오류가 발생했습니다",
|
||||
"an_unexpected_error_occurred": "예기치 않은 오류가 발생했습니다",
|
||||
"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을 올바르게 입력하셨습니까?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "예기치 않은 오류가 발생했습니다. 서버 URL을 올바르게 입력하셨습니까?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "퀵 커넥트 승인",
|
||||
"enter_the_quick_connect_code": "퀵 커넥트 코드 입력...",
|
||||
"success": "성공",
|
||||
"quick_connect_autorized": "퀵 커넥트 승인됨",
|
||||
"quick_connect_authorized": "퀵 커넥트 승인됨",
|
||||
"error": "오류",
|
||||
"invalid_code": "유효하지 않은 코드",
|
||||
"authorize": "승인"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "사용자 지정 메뉴 링크 표시",
|
||||
"show_large_home_carousel": "대형 홈 슬라이드 배너 표시 (베타)",
|
||||
"hide_libraries": "라이브러리 숨기기",
|
||||
"select_liraries_you_want_to_hide": "Select the libraries you want to hide from the Library tab and home page sections.",
|
||||
"select_libraries_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_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "디바이스 {{availableSpace}}%",
|
||||
"size_used": "{{used}} of {{total}} Used",
|
||||
"delete_all_downloaded_files": "Delete All Downloaded Files",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Error",
|
||||
"failed_to_get_stream_url": "Failed to get the stream URL",
|
||||
"an_error_occured_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"an_error_occurred_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"client_error": "Client Error",
|
||||
"could_not_create_stream_for_chromecast": "Could not create a stream for Chromecast",
|
||||
"message_from_server": "Message from Server: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Begrepen",
|
||||
"connection_failed": "Verbinding mislukt",
|
||||
"could_not_connect_to_server": "Kon niet verbinden met de server. Controleer de URL en je netwerkverbinding.",
|
||||
"an_unexpected_error_occured": "Er is een onverwachte fout opgetreden",
|
||||
"an_unexpected_error_occurred": "Er is een onverwachte fout opgetreden",
|
||||
"change_server": "Server wijzigen",
|
||||
"invalid_username_or_password": "Onjuiste gebruikersnaam of wachtwoord",
|
||||
"user_does_not_have_permission_to_log_in": "Gebruiker heeft geen rechten om aan te melden",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "De server doet er te lang over om te antwoorden, probeer later opnieuw",
|
||||
"server_received_too_many_requests_try_again_later": "De server heeft te veel aanvragen ontvangen, probeer later opnieuw",
|
||||
"there_is_a_server_error": "Er is een serverfout",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Er is een onverwachte fout opgetreden. Heb je de server URL correct ingegeven?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Er is een onverwachte fout opgetreden. Heb je de server URL correct ingegeven?",
|
||||
"too_old_server_text": "Niet-ondersteunde Jellyfin Server Ontdekt",
|
||||
"too_old_server_description": "Werk Jellyfin bij naar de laatste versie"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Snel Verbinden toestaan",
|
||||
"enter_the_quick_connect_code": "Vul de Snel Verbinden code in...",
|
||||
"success": "Succes",
|
||||
"quick_connect_autorized": "Snel Verbinden toegestaan",
|
||||
"quick_connect_authorized": "Snel Verbinden toegestaan",
|
||||
"error": "Fout",
|
||||
"invalid_code": "Ongeldige code",
|
||||
"authorize": "Toestaan"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Aangepaste menulinks tonen",
|
||||
"show_large_home_carousel": "Toon grote carrousel op startpagina (bèta)",
|
||||
"hide_libraries": "Verberg Bibliotheken",
|
||||
"select_liraries_you_want_to_hide": "Selecteer de bibliotheken die je wil verbergen van de Bibliotheektab en hoofdpagina onderdelen.",
|
||||
"select_libraries_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_playback_speed": "Standaard Afspeelsnelheid",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Toestel {{availableSpace}}%",
|
||||
"size_used": "{{used}} van {{total}} gebruikt",
|
||||
"delete_all_downloaded_files": "Verwijder alle gedownloade bestanden",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Fout",
|
||||
"failed_to_get_stream_url": "De stream-URL kon niet worden verkregen",
|
||||
"an_error_occured_while_playing_the_video": "Er is een fout opgetreden tijdens het afspelen van de video. Controleer de logs in de instellingen.",
|
||||
"an_error_occurred_while_playing_the_video": "Er is een fout opgetreden tijdens het afspelen van de video. Controleer de logs in de instellingen.",
|
||||
"client_error": "Fout van de client",
|
||||
"could_not_create_stream_for_chromecast": "Kon geen stream maken voor Chromecast",
|
||||
"message_from_server": "Bericht van de server",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Har det",
|
||||
"connection_failed": "Tilkobling mislyktes",
|
||||
"could_not_connect_to_server": "Kunne ikke koble til serveren. Kontroller nettadressen og nettverkstilkoblingen.",
|
||||
"an_unexpected_error_occured": "En uventet feil oppstod",
|
||||
"an_unexpected_error_occurred": "En uventet feil oppstod",
|
||||
"change_server": "Endre server",
|
||||
"invalid_username_or_password": "Ugyldig brukernavn eller passord",
|
||||
"user_does_not_have_permission_to_log_in": "Brukeren har ikke tillatelse til å logge inn",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Serveren tar for lang tid å svare, prøv igjen senere",
|
||||
"server_received_too_many_requests_try_again_later": "Serveren mottok for mange forespørsler, prøv igjen senere.",
|
||||
"there_is_a_server_error": "Det er en serverfeil",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Det oppstod en uventet feil. Sendte du inn URLen til serveren riktig?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Det oppstod en uventet feil. Sendte du inn URLen til serveren riktig?",
|
||||
"too_old_server_text": "Ustøttet Jellyfin Server oppdaget",
|
||||
"too_old_server_description": "Vennligst oppdater Jellyfin til nyeste versjon"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autoriser rask tilkobling",
|
||||
"enter_the_quick_connect_code": "Skriv inn hurtig-tilkobling kode...",
|
||||
"success": "Vellykket",
|
||||
"quick_connect_autorized": "Hurtig tilkobling autorisert",
|
||||
"quick_connect_authorized": "Hurtig tilkobling autorisert",
|
||||
"error": "Feil",
|
||||
"invalid_code": "Ugyldig kode",
|
||||
"authorize": "Autoriser"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Vis tilpassede menylenker",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Skjul biblioteker",
|
||||
"select_liraries_you_want_to_hide": "Velg bibliotekene du vil skjule deg for Biblioteket og avsnittene for hjemmesider.",
|
||||
"select_libraries_you_want_to_hide": "Velg bibliotekene du vil skjule deg for Biblioteket og avsnittene for hjemmesider.",
|
||||
"disable_haptic_feedback": "Deaktiver Haptisk tilbakemelding",
|
||||
"default_quality": "Standard kvalitet",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Enhet {{availableSpace}}%",
|
||||
"size_used": "{{used}} av {{total}} er i bruk",
|
||||
"delete_all_downloaded_files": "Slett alle nedlastede filer",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Feil",
|
||||
"failed_to_get_stream_url": "Kan ikke hente nettadressen for stream",
|
||||
"an_error_occured_while_playing_the_video": "En feil oppstod under video. Sjekk loggene i innstillingene.",
|
||||
"an_error_occurred_while_playing_the_video": "En feil oppstod under video. Sjekk loggene i innstillingene.",
|
||||
"client_error": "Feil med annonsør",
|
||||
"could_not_create_stream_for_chromecast": "Kan ikke opprette en strøm for Chromecast",
|
||||
"message_from_server": "Melding fra tjener: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Rozumiem",
|
||||
"connection_failed": "Połączenie nieudane",
|
||||
"could_not_connect_to_server": "Nie można połączyć się z serwerem. Sprawdź adres URL oraz połączenie sieciowe.",
|
||||
"an_unexpected_error_occured": "Wystąpił nieoczekiwany błąd",
|
||||
"an_unexpected_error_occurred": "Wystąpił nieoczekiwany błąd",
|
||||
"change_server": "Zmień serwer",
|
||||
"invalid_username_or_password": "Nieprawidłowa nazwa użytkownika lub hasło",
|
||||
"user_does_not_have_permission_to_log_in": "Użytkownik nie ma uprawnień do logowania",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Serwer zbyt długo nie odpowiada – spróbuj ponownie później",
|
||||
"server_received_too_many_requests_try_again_later": "Serwer otrzymał zbyt wiele żądań – spróbuj ponownie później.",
|
||||
"there_is_a_server_error": "Wystąpił błąd serwera",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Wystąpił nieoczekiwany błąd. Czy wpisałeś poprawny adres URL?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Wystąpił nieoczekiwany błąd. Czy wpisałeś poprawny adres URL?",
|
||||
"too_old_server_text": "Wykryto nieobsługiwany serwer Jellyfin",
|
||||
"too_old_server_description": "Proszę zaktualizować Jellyfin do najnowszej wersji"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autoryzuj szybkie połączenie",
|
||||
"enter_the_quick_connect_code": "Wpisz kod szybkiego połączenia...",
|
||||
"success": "Sukces",
|
||||
"quick_connect_autorized": "Szybkie połączenie autoryzowane",
|
||||
"quick_connect_authorized": "Szybkie połączenie autoryzowane",
|
||||
"error": "Błąd",
|
||||
"invalid_code": "Nieprawidłowy kod",
|
||||
"authorize": "Autoryzuj"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Pokaż niestandardowe odnośniki w menu",
|
||||
"show_large_home_carousel": "Wyświetl Dużą Karuzelę na ekranie głównym (beta)",
|
||||
"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.",
|
||||
"select_libraries_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_playback_speed": "Domyślna prędkość odtwarzania",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Urządzenie {{availableSpace}}%",
|
||||
"size_used": "{{used}} z {{total}} wykorzystane",
|
||||
"delete_all_downloaded_files": "Usuń wszystkie pobrane pliki",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Bufor muzyki",
|
||||
"music_cache_description": "Automatycznie buforuj piosenki w trakcie słuchania dla płynniejszego odtwarzania i wsparcia offline",
|
||||
"clear_music_cache": "Wyczyść bufor muzyki",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Błąd",
|
||||
"failed_to_get_stream_url": "Nie udało się pobrać adresu strumienia",
|
||||
"an_error_occured_while_playing_the_video": "Wystąpił błąd podczas odtwarzania wideo. Sprawdź logi w ustawieniach.",
|
||||
"an_error_occurred_while_playing_the_video": "Wystąpił błąd podczas odtwarzania wideo. Sprawdź logi w ustawieniach.",
|
||||
"client_error": "Błąd klienta",
|
||||
"could_not_create_stream_for_chromecast": "Nie udało się utworzyć strumienia dla Chromecasta",
|
||||
"message_from_server": "Wiadomość z serwera: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Tenho isso",
|
||||
"connection_failed": "Falha na conexão",
|
||||
"could_not_connect_to_server": "Não foi possível conectar ao servidor. Verifique a URL e sua conexão de rede.",
|
||||
"an_unexpected_error_occured": "Ocorreu um erro inesperado",
|
||||
"an_unexpected_error_occurred": "An unexpected error occurred",
|
||||
"change_server": "Alterar Servidor",
|
||||
"invalid_username_or_password": "Usuário ou senha inválidos",
|
||||
"user_does_not_have_permission_to_log_in": "Usuário não tem permissão para fazer login",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "O servidor está demorando muito para responder, tente novamente mais tarde",
|
||||
"server_received_too_many_requests_try_again_later": "O servidor recebeu muitos pedidos, tente novamente mais tarde.",
|
||||
"there_is_a_server_error": "Existe um erro no servidor",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Ocorreu um erro inesperado. Você inseriu a URL do servidor corretamente?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "An unexpected error occurred. Did you enter the server URL correctly?",
|
||||
"too_old_server_text": "Servidor Jellyfin Descoberto Não Suportado",
|
||||
"too_old_server_description": "Por favor, atualize o Jellyfin para a versão mais recente"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autorizar conexão rápida",
|
||||
"enter_the_quick_connect_code": "Insira o código de conexão rápida...",
|
||||
"success": "Sucesso",
|
||||
"quick_connect_autorized": "Acesso Rápido Autorizado",
|
||||
"quick_connect_authorized": "Quick Connect authorized",
|
||||
"error": "Erro",
|
||||
"invalid_code": "Código inválido",
|
||||
"authorize": "Autorizar"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Mostrar Links de Menu Personalizado",
|
||||
"show_large_home_carousel": "Mostrar Carrossel Grande (beta)",
|
||||
"hide_libraries": "Ocultar bibliotecas",
|
||||
"select_liraries_you_want_to_hide": "Selecione as bibliotecas que você deseja ocultar da aba Biblioteca e seções da página inicial.",
|
||||
"select_libraries_you_want_to_hide": "Select the libraries you want to hide from the Library tab and home page sections.",
|
||||
"disable_haptic_feedback": "Desativar o retorno tátil",
|
||||
"default_quality": "Qualidade Padrão",
|
||||
"default_playback_speed": "Velocidade padrão de reprodução",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Dispositivo {{availableSpace}}%",
|
||||
"size_used": "{{used}} de {{total}} Utilizados",
|
||||
"delete_all_downloaded_files": "Excluir todos os arquivos baixados",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Cache de Música",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Limpar Cache de Música",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "ERRO",
|
||||
"failed_to_get_stream_url": "Falha ao obter a URL de transmissão",
|
||||
"an_error_occured_while_playing_the_video": "Ocorreu um erro ao reproduzir o vídeo. Verifique os logs nas configurações.",
|
||||
"an_error_occurred_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"client_error": "Erro de Cliente",
|
||||
"could_not_create_stream_for_chromecast": "Não foi possível criar um fluxo para o Chromecast",
|
||||
"message_from_server": "Mensagem do Servidor: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Am înţeles",
|
||||
"connection_failed": "Conectare eșuată",
|
||||
"could_not_connect_to_server": "Nu s-a putut conecta la server. Verificați adresa URL și conexiunea la internet.",
|
||||
"an_unexpected_error_occured": "A apărut o eroare neașteptată",
|
||||
"an_unexpected_error_occurred": "A apărut o eroare neașteptată",
|
||||
"change_server": "Schimba",
|
||||
"invalid_username_or_password": "Nume de utilizator sau parolă greșită",
|
||||
"user_does_not_have_permission_to_log_in": "Utilizatorul nu are permisiunea de a se conecta",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Serverul răspunde prea greu, încearcă din nou mai târziu.",
|
||||
"server_received_too_many_requests_try_again_later": "Serverul a primit prea multe solicitări, încercați din nou mai târziu.",
|
||||
"there_is_a_server_error": "Eroare de server",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "A apărut o eroare neașteptată. Ați introdus corect adresa URL a serverului?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "A apărut o eroare neașteptată. Ați introdus corect adresa URL a serverului?",
|
||||
"too_old_server_text": "Serverul Jellyfin Neacceptat Descoperit",
|
||||
"too_old_server_description": "Vă rugăm să actualizați Jellyfin la cea mai recentă versiune"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Autorizare conectare rapidă",
|
||||
"enter_the_quick_connect_code": "Introduceți codul pt. conectare rapidă...",
|
||||
"success": "Succes",
|
||||
"quick_connect_autorized": "Conectare rapidă autorizată",
|
||||
"quick_connect_authorized": "Conectare rapidă autorizată",
|
||||
"error": "Eroare",
|
||||
"invalid_code": "Cod invalid.",
|
||||
"authorize": "Autorizează"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Afișează link-uri personalizate în meniu",
|
||||
"show_large_home_carousel": "Arată Caruselul Media Mare (beta)",
|
||||
"hide_libraries": "Ascunde bibliotecile",
|
||||
"select_liraries_you_want_to_hide": "Selectează bibliotecile pe care dorești să le ascunzi din fila Bibliotecă și din secțiunile paginii principale.",
|
||||
"select_libraries_you_want_to_hide": "Selectează bibliotecile pe care dorești să le ascunzi din fila Bibliotecă și din secțiunile paginii principale.",
|
||||
"disable_haptic_feedback": "Dezactivează vibrațiile tactile",
|
||||
"default_quality": "Calitate implicită",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Dispozitiv {{availableSpace}}%",
|
||||
"size_used": "{{used}} din {{total}} folosit",
|
||||
"delete_all_downloaded_files": "Ștergeți toate fișierele descărcate",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Eroare",
|
||||
"failed_to_get_stream_url": "Nu s-a putut obține adresa URL a fluxului",
|
||||
"an_error_occured_while_playing_the_video": "A apărut o eroare la redarea videoclipului. Verificați jurnalele în setări.",
|
||||
"an_error_occurred_while_playing_the_video": "A apărut o eroare la redarea videoclipului. Verificați jurnalele în setări.",
|
||||
"client_error": "Eroare client",
|
||||
"could_not_create_stream_for_chromecast": "Nu s-a putut crea un flux pentru Chromecast",
|
||||
"message_from_server": "Mesaj de la server: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Принято",
|
||||
"connection_failed": "Соединение не удалось",
|
||||
"could_not_connect_to_server": "Не удалось подключиться к серверу. Пожалуйста, проверьте URL и ваше интернет-соединение.",
|
||||
"an_unexpected_error_occured": "Возникла непредвиденная ошибка",
|
||||
"an_unexpected_error_occurred": "Возникла непредвиденная ошибка",
|
||||
"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?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Возникла непредвиденная ошибка. Вы правильно ввели URL?",
|
||||
"too_old_server_text": "Обнаружен неподдерживаемый сервер Jellyfin",
|
||||
"too_old_server_description": "Пожалуйста, обновите Jellyfin до последней версии"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Авторизовать через быстрое подключение",
|
||||
"enter_the_quick_connect_code": "Введите код для быстрого подключения...",
|
||||
"success": "Успех",
|
||||
"quick_connect_autorized": "Быстрое подключение авторизовано",
|
||||
"quick_connect_authorized": "Быстрое подключение авторизовано",
|
||||
"error": "Ошибка",
|
||||
"invalid_code": "Неверный код",
|
||||
"authorize": "Авторизовать"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Показать ссылки пользовательского меню",
|
||||
"show_large_home_carousel": "Показывать большую карусель (beta)",
|
||||
"hide_libraries": "Скрыть библиотеки",
|
||||
"select_liraries_you_want_to_hide": "Выберите Библиотеки, которое хотите спрятать из вкладки Библиотеки и домашней страницы.",
|
||||
"select_libraries_you_want_to_hide": "Выберите Библиотеки, которое хотите спрятать из вкладки Библиотеки и домашней страницы.",
|
||||
"disable_haptic_feedback": "Отключить тактильную обратную связь",
|
||||
"default_quality": "Качество по умолчанию",
|
||||
"default_playback_speed": "Скорость воспроизведения по умолчанию",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Устройство {{availableSpace}}%",
|
||||
"size_used": "{{used}} из {{total}} использовано",
|
||||
"delete_all_downloaded_files": "Удалить все загруженные файлы",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Кеш музыки",
|
||||
"music_cache_description": "Автоматически кешировать песни по мере прослушивания для плавного воспроизведения и поддержки отсутствия интернета",
|
||||
"clear_music_cache": "Очистить кеш музыки",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Ошибка",
|
||||
"failed_to_get_stream_url": "Не удалось получить URL потока",
|
||||
"an_error_occured_while_playing_the_video": "Возникла Неожиданная ошибка во время воспроизведения. Проверьте логи в настройках.",
|
||||
"an_error_occurred_while_playing_the_video": "Возникла Неожиданная ошибка во время воспроизведения. Проверьте логи в настройках.",
|
||||
"client_error": "Ошибка клиента",
|
||||
"could_not_create_stream_for_chromecast": "Не удалось создать поток для Chromecast",
|
||||
"message_from_server": "Сообщение от сервера: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Koden har mottagits",
|
||||
"connection_failed": "Anslutningen Misslyckades",
|
||||
"could_not_connect_to_server": "Det gick inte att ansluta till servern. Kontrollera webbadressen och din nätverksanslutning.",
|
||||
"an_unexpected_error_occured": "Ett Oväntat Fel Uppstod",
|
||||
"an_unexpected_error_occurred": "Ett Oväntat Fel Uppstod",
|
||||
"change_server": "Byt Server",
|
||||
"invalid_username_or_password": "Ogiltigt användarnamn eller lösenord",
|
||||
"user_does_not_have_permission_to_log_in": "Användaren har inte behörighet att logga in",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Servern svarar för långsamt, försök igen senare",
|
||||
"server_received_too_many_requests_try_again_later": "Servern har fått för många förfrågningar, försök igen senare.",
|
||||
"there_is_a_server_error": "Ett serverfel uppstod",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Ett oväntat fel uppstod. Har du angett serverns URL korrekt?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Ett oväntat fel uppstod. Har du angett serverns URL korrekt?",
|
||||
"too_old_server_text": "Jellyfin Servern Stöds Inte",
|
||||
"too_old_server_description": "Var God Uppdatera Jellyfin Till Den Senaste Versionen"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Godkänn snabbanslutning",
|
||||
"enter_the_quick_connect_code": "Ange snabbanslutningskod...",
|
||||
"success": "Snabbanslutning lyckades",
|
||||
"quick_connect_autorized": "Snabbanslutning Godkänd",
|
||||
"quick_connect_authorized": "Snabbanslutning Godkänd",
|
||||
"error": "Fel",
|
||||
"invalid_code": "Ogiltig kod",
|
||||
"authorize": "Autentisera"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Visa anpassade menylänkar",
|
||||
"show_large_home_carousel": "Visa toppbanner (beta)",
|
||||
"hide_libraries": "Dölj bibliotek",
|
||||
"select_liraries_you_want_to_hide": "Välj de bibliotek du vill dölja på fliken Bibliotek och på startsidan.",
|
||||
"select_libraries_you_want_to_hide": "Välj de bibliotek du vill dölja på fliken Bibliotek och på startsidan.",
|
||||
"disable_haptic_feedback": "Stäng av vibrationer",
|
||||
"default_quality": "Förvald Kvalitet",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Telefon {{availableSpace}}%",
|
||||
"size_used": "{{used}} av {{total}} används",
|
||||
"delete_all_downloaded_files": "Ta bort alla nerladdade filer",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Musikcache",
|
||||
"music_cache_description": "Cacha automatiskt låtar när du lyssnar för smidigare uppspelning och offline-stöd",
|
||||
"clear_music_cache": "Rensa musikcache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV 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.",
|
||||
"an_error_occurred_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}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Got It",
|
||||
"connection_failed": "Connection Failed",
|
||||
"could_not_connect_to_server": "Could not connect to the server. Please check the URL and your network connection.",
|
||||
"an_unexpected_error_occured": "An Unexpected Error Occurred",
|
||||
"an_unexpected_error_occurred": "An unexpected error occurred",
|
||||
"change_server": "Change Server",
|
||||
"invalid_username_or_password": "Invalid Username or Password",
|
||||
"user_does_not_have_permission_to_log_in": "ผู้ใช้ไม่มีสิทธิ์ในการเข้าสู่ระบบ",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Server is taking too long to respond, try again later",
|
||||
"server_received_too_many_requests_try_again_later": "Server received too many requests, try again later.",
|
||||
"there_is_a_server_error": "There is a server error",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "An unexpected error occurred. Did you enter the server URL correctly?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Authorize Quick Connect",
|
||||
"enter_the_quick_connect_code": "Enter the quick connect code...",
|
||||
"success": "Success",
|
||||
"quick_connect_autorized": "Quick Connect Authorized",
|
||||
"quick_connect_authorized": "Quick Connect authorized",
|
||||
"error": "Error",
|
||||
"invalid_code": "Invalid Code",
|
||||
"authorize": "Authorize"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Show Custom Menu Links",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"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.",
|
||||
"select_libraries_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_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Device {{availableSpace}}%",
|
||||
"size_used": "{{used}} of {{total}} Used",
|
||||
"delete_all_downloaded_files": "Delete All Downloaded Files",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Error",
|
||||
"failed_to_get_stream_url": "Failed to get the stream URL",
|
||||
"an_error_occured_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"an_error_occurred_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"client_error": "Client Error",
|
||||
"could_not_create_stream_for_chromecast": "Could not create a stream for Chromecast",
|
||||
"message_from_server": "Message from Server: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "jIyaj",
|
||||
"connection_failed": "ngoQlaHbe'",
|
||||
"could_not_connect_to_server": "SeHlaw veS Ho'Do'laHbe'. URL 'ej ret ghun mej.",
|
||||
"an_unexpected_error_occured": "num ghIq Doch",
|
||||
"an_unexpected_error_occurred": "num ghIq Doch",
|
||||
"change_server": "Ho'Do' veS yIghoS",
|
||||
"invalid_username_or_password": "tlhIngan pagh ngoq De' law'be'",
|
||||
"user_does_not_have_permission_to_log_in": "tlhIngan lut 'el je'laHbe'",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Ho'Do' veS jachrup. pItlh yIHaD",
|
||||
"server_received_too_many_requests_try_again_later": "Ho'Do' veS lutlh ngeb petlh law'. pItlh yIHaD.",
|
||||
"there_is_a_server_error": "Ho'Do' veS ghIq maS",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "num ghIq Doch. URL mej Danej'a'?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "num ghIq Doch. URL mej Danej'a'?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "**Jellyfin chu'qu' Dotlh yIchoHmoH**"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "parmaq ngoQ yIje'",
|
||||
"enter_the_quick_connect_code": "parmaq ngoQ De' yI'el...",
|
||||
"success": "Qapla'",
|
||||
"quick_connect_autorized": "parmaq ngoQ je'laH",
|
||||
"quick_connect_authorized": "parmaq ngoQ je'laH",
|
||||
"error": "ghIq",
|
||||
"invalid_code": "De' law'be'",
|
||||
"authorize": "yIje'"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "menuDaq ret teqlu' yInej",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "De'wI' bom yIQIj",
|
||||
"select_liraries_you_want_to_hide": "De'wI' bom Danej QIj yIwIv.",
|
||||
"select_libraries_you_want_to_hide": "De'wI' bom Danej QIj yIwIv.",
|
||||
"disable_haptic_feedback": "Qub quvHa' yIQIj",
|
||||
"default_quality": "wa' luj",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "naDev {{availableSpace}}%",
|
||||
"size_used": "{{used}} / {{total}} ram",
|
||||
"delete_all_downloaded_files": "Hoch Qaw' Doch yIQaw'",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "ghIq",
|
||||
"failed_to_get_stream_url": "tlhol ret URL tu'laHbe'",
|
||||
"an_error_occured_while_playing_the_video": "mu'tlhegh tlholDI' ghIq. menDaq De' qon mej.",
|
||||
"an_error_occurred_while_playing_the_video": "mu'tlhegh tlholDI' ghIq. menDaq De' qon mej.",
|
||||
"client_error": "lut 'el ghIq",
|
||||
"could_not_create_stream_for_chromecast": "Chromecast tlhol ret qonlaHbe'",
|
||||
"message_from_server": "Ho'Do' veS jach: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Anlaşıldı",
|
||||
"connection_failed": "Bağlantı başarısız",
|
||||
"could_not_connect_to_server": "Sunucuya bağlanılamadı. Lütfen URL'yi ve ağ bağlantınızı kontrol edin.",
|
||||
"an_unexpected_error_occured": "Beklenmedik bir hata oluştu",
|
||||
"an_unexpected_error_occurred": "Beklenmedik bir hata oluştu",
|
||||
"change_server": "Sunucu değiştir",
|
||||
"invalid_username_or_password": "Geçersiz kullanıcı adı veya şifre",
|
||||
"user_does_not_have_permission_to_log_in": "Kullanıcının giriş yapma izni yok",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Sunucunun yanıt vermesi çok uzun sürüyor, lütfen daha sonra tekrar deneyin",
|
||||
"server_received_too_many_requests_try_again_later": "Sunucu çok fazla istek aldı, lütfen daha sonra tekrar deneyin.",
|
||||
"there_is_a_server_error": "Sunucu hatası var",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Beklenmedik bir hata oluştu. Sunucu URL'sini doğru girdiğinizden emin misiniz?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Beklenmedik bir hata oluştu. Sunucu URL'sini doğru girdiğinizden emin misiniz?",
|
||||
"too_old_server_text": "Desteklenmeyen Jellyfin Sunucu sürümü bulundu.",
|
||||
"too_old_server_description": "Lütfen Jellyfin'i en son sürüme güncelleyin."
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Hızlı Bağlantıyı Yetkilendir",
|
||||
"enter_the_quick_connect_code": "Hızlı bağlantı kodunu girin...",
|
||||
"success": "Başarılı",
|
||||
"quick_connect_autorized": "Hızlı Bağlantı Yetkilendirildi",
|
||||
"quick_connect_authorized": "Hızlı Bağlantı Yetkilendirildi",
|
||||
"error": "Hata",
|
||||
"invalid_code": "Geçersiz kod",
|
||||
"authorize": "Yetkilendir"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Özel Menü Bağlantılarını Göster",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"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.",
|
||||
"select_libraries_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",
|
||||
"default_quality": "Varsayılan kalite",
|
||||
"default_playback_speed": "Varsayılan Oynatma Hızı",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Cihaz {{availableSpace}}%",
|
||||
"size_used": "{{used}} / {{total}} kullanıldı",
|
||||
"delete_all_downloaded_files": "Tüm indirilen dosyaları sil",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Müzik Ön Belleği",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Müzik Ön Belleğini Temizle",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Hata",
|
||||
"failed_to_get_stream_url": "Yayın URL'si alınamadı",
|
||||
"an_error_occured_while_playing_the_video": "Video oynatılırken bir hata oluştu. Ayarlardaki günlüklere bakın.",
|
||||
"an_error_occurred_while_playing_the_video": "Video oynatılırken bir hata oluştu. Ayarlardaki günlüklere bakın.",
|
||||
"client_error": "İstemci hatası",
|
||||
"could_not_create_stream_for_chromecast": "Chromecast için yayın oluşturulamadı",
|
||||
"message_from_server": "Sunucudan mesaj: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Готово",
|
||||
"connection_failed": "Помилка зʼєднання",
|
||||
"could_not_connect_to_server": "Неможливо підʼєднатися до серверу. Будь ласка перевірте URL і ваше зʼєднання з мережею",
|
||||
"an_unexpected_error_occured": "Сталася несподівана помилка",
|
||||
"an_unexpected_error_occurred": "Сталася несподівана помилка",
|
||||
"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 сервера правильний?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Відбулася несподівана помилка. Чи введений URL сервера правильний?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Авторизуйте Швидке Зʼєднання",
|
||||
"enter_the_quick_connect_code": "Введіть код для швидкого зʼєднання...",
|
||||
"success": "Успіх",
|
||||
"quick_connect_autorized": "Швидке Зʼєднання авторизовано",
|
||||
"quick_connect_authorized": "Швидке Зʼєднання авторизовано",
|
||||
"error": "Помилка",
|
||||
"invalid_code": "Не правильний код",
|
||||
"authorize": "Авторизувати"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Показати користувацькі посилання меню",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Сховати медіатеки",
|
||||
"select_liraries_you_want_to_hide": "Виберіть медіатеки, що бажаєте приховати з вкладки Медіатека і з секції на головній сторінці.",
|
||||
"select_libraries_you_want_to_hide": "Виберіть медіатеки, що бажаєте приховати з вкладки Медіатека і з секції на головній сторінці.",
|
||||
"disable_haptic_feedback": "Вимкнути тактильний зворотний зв'язок",
|
||||
"default_quality": "Якість за замовченням",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Гаджет {{availableSpace}}%",
|
||||
"size_used": "{{used}} з {{total}} використано",
|
||||
"delete_all_downloaded_files": "Видалити усі завантаженні файли",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Помилка",
|
||||
"failed_to_get_stream_url": "Не вдалося отримати URL-адресу потоку",
|
||||
"an_error_occured_while_playing_the_video": "Під час відтворення відео сталася помилка. Перевірте журнал в налаштуваннях.",
|
||||
"an_error_occurred_while_playing_the_video": "Під час відтворення відео сталася помилка. Перевірте журнал в налаштуваннях.",
|
||||
"client_error": "Помилка клієнту",
|
||||
"could_not_create_stream_for_chromecast": "Не вдалося створити потік для Chromecast",
|
||||
"message_from_server": "Повідомлення від серверу: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Đã hiểu",
|
||||
"connection_failed": "Kết nối thất bại",
|
||||
"could_not_connect_to_server": "Không thể kết nối tới máy chủ. Vui lòng kiểm tra URL và kết nối mạng.",
|
||||
"an_unexpected_error_occured": "Đã xảy ra lỗi không mong muốn",
|
||||
"an_unexpected_error_occurred": "Đã xảy ra lỗi không mong muốn",
|
||||
"change_server": "Đổi máy chủ",
|
||||
"invalid_username_or_password": "Tên đăng nhập hoặc mật khẩu không đúng",
|
||||
"user_does_not_have_permission_to_log_in": "Người dùng không có quyền đăng nhập",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Máy chủ phản hồi quá lâu, vui lòng thử lại sau",
|
||||
"server_received_too_many_requests_try_again_later": "Máy chủ nhận quá nhiều yêu cầu, vui lòng thử lại sau.",
|
||||
"there_is_a_server_error": "Đã xảy ra lỗi ở máy chủ",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "Đã xảy ra lỗi không mong muốn. Bạn có chắc đã nhập đúng URL máy chủ?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "Đã xảy ra lỗi không mong muốn. Bạn có chắc đã nhập đúng URL máy chủ?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Cho phép Kết nối nhanh",
|
||||
"enter_the_quick_connect_code": "Nhập mã kết nối nhanh...",
|
||||
"success": "Thành công",
|
||||
"quick_connect_autorized": "Kết nối nhanh đã được cho phép",
|
||||
"quick_connect_authorized": "Kết nối nhanh đã được cho phép",
|
||||
"error": "Lỗi",
|
||||
"invalid_code": "Mã không hợp lệ",
|
||||
"authorize": "Cho phép"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Hiện liên kết tùy chỉnh",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"hide_libraries": "Ẩn thư viện",
|
||||
"select_liraries_you_want_to_hide": "Chọn các thư viện muốn ẩn khỏi mục Thư viện và Trang chủ.",
|
||||
"select_libraries_you_want_to_hide": "Chọn các thư viện muốn ẩn khỏi mục Thư viện và Trang chủ.",
|
||||
"disable_haptic_feedback": "Tắt phản hồi rung",
|
||||
"default_quality": "Chất lượng mặc định",
|
||||
"default_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Thiết bị sử dụng {{availableSpace}}%",
|
||||
"size_used": "{{used}} / {{total}} đã dùng",
|
||||
"delete_all_downloaded_files": "Xóa toàn bộ tập tin đã tải",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Lỗi",
|
||||
"failed_to_get_stream_url": "Không thể lấy URL phát trực tiếp",
|
||||
"an_error_occured_while_playing_the_video": "Có lỗi khi phát video. Xem nhật ký trong cài đặt.",
|
||||
"an_error_occurred_while_playing_the_video": "Có lỗi khi phát video. Xem nhật ký trong cài đặt.",
|
||||
"client_error": "Lỗi phía máy khách",
|
||||
"could_not_create_stream_for_chromecast": "Không thể tạo luồng cho Chromecast",
|
||||
"message_from_server": "Thông báo từ máy chủ: {{message}}",
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
"got_it": "Got It",
|
||||
"connection_failed": "Connection Failed",
|
||||
"could_not_connect_to_server": "Could not connect to the server. Please check the URL and your network connection.",
|
||||
"an_unexpected_error_occured": "An Unexpected Error Occurred",
|
||||
"an_unexpected_error_occurred": "An unexpected error occurred",
|
||||
"change_server": "Change Server",
|
||||
"invalid_username_or_password": "Invalid Username or Password",
|
||||
"user_does_not_have_permission_to_log_in": "User does not have permission to log in",
|
||||
"server_is_taking_too_long_to_respond_try_again_later": "Server is taking too long to respond, try again later",
|
||||
"server_received_too_many_requests_try_again_later": "Server received too many requests, try again later.",
|
||||
"there_is_a_server_error": "There is a server error",
|
||||
"an_unexpected_error_occured_did_you_enter_the_correct_url": "An unexpected error occurred. Did you enter the server URL correctly?",
|
||||
"an_unexpected_error_occurred_did_you_enter_the_correct_url": "An unexpected error occurred. Did you enter the server URL correctly?",
|
||||
"too_old_server_text": "Unsupported Jellyfin Server Discovered",
|
||||
"too_old_server_description": "Please update Jellyfin to the latest version"
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"authorize_button": "Authorize Quick Connect",
|
||||
"enter_the_quick_connect_code": "Enter the quick connect code...",
|
||||
"success": "Success",
|
||||
"quick_connect_autorized": "Quick Connect Authorized",
|
||||
"quick_connect_authorized": "Quick Connect authorized",
|
||||
"error": "Error",
|
||||
"invalid_code": "Invalid Code",
|
||||
"authorize": "Authorize"
|
||||
@@ -298,7 +298,7 @@
|
||||
"show_custom_menu_links": "Show Custom Menu Links",
|
||||
"show_large_home_carousel": "Show Large Home Carousel (beta)",
|
||||
"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.",
|
||||
"select_libraries_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_playback_speed": "Default Playback Speed",
|
||||
@@ -384,6 +384,8 @@
|
||||
"device_usage": "Device {{availableSpace}}%",
|
||||
"size_used": "{{used}} of {{total}} Used",
|
||||
"delete_all_downloaded_files": "Delete All Downloaded Files",
|
||||
"delete_all_downloaded_files_confirm": "Delete All Downloaded Files?",
|
||||
"delete_all_downloaded_files_confirm_desc": "Are you sure you want to delete all downloaded files? This action cannot be undone.",
|
||||
"music_cache_title": "Music Cache",
|
||||
"music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support",
|
||||
"clear_music_cache": "Clear Music Cache",
|
||||
@@ -598,7 +600,7 @@
|
||||
"mpv_player_title": "MPV Player",
|
||||
"error": "Error",
|
||||
"failed_to_get_stream_url": "Failed to get the stream URL",
|
||||
"an_error_occured_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"an_error_occurred_while_playing_the_video": "An error occurred while playing the video. Check logs in settings.",
|
||||
"client_error": "Client Error",
|
||||
"could_not_create_stream_for_chromecast": "Could not create a stream for Chromecast",
|
||||
"message_from_server": "Message from Server: {{message}}",
|
||||
|
||||
@@ -224,6 +224,7 @@ export type Settings = {
|
||||
streamyStatsSeriesRecommendations?: boolean;
|
||||
streamyStatsPromotedWatchlists?: boolean;
|
||||
downloadQuality?: DownloadOption;
|
||||
downloadStorageLocation?: string;
|
||||
defaultBitrate?: Bitrate;
|
||||
libraryOptions: LibraryOptions;
|
||||
defaultAudioLanguage: CultureDto | null;
|
||||
@@ -321,6 +322,7 @@ export const defaultValues: Settings = {
|
||||
streamyStatsSeriesRecommendations: false,
|
||||
streamyStatsPromotedWatchlists: false,
|
||||
downloadQuality: DownloadOptions[0],
|
||||
downloadStorageLocation: undefined,
|
||||
defaultBitrate: BITRATES[0],
|
||||
libraryOptions: {
|
||||
display: "list",
|
||||
|
||||
143
utils/storage.ts
Normal file
143
utils/storage.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { Directory, Paths } from "expo-file-system";
|
||||
import { Platform } from "react-native";
|
||||
import { BackgroundDownloader, type StorageLocation } from "@/modules";
|
||||
|
||||
let cachedStorageLocations: StorageLocation[] | null = null;
|
||||
|
||||
// Debug mode: Set to true to simulate an SD card for testing in emulator
|
||||
// This creates a real writable directory that mimics SD card behavior
|
||||
const DEBUG_SIMULATE_SD_CARD = false;
|
||||
|
||||
/**
|
||||
* Get all available storage locations (Android only)
|
||||
* Returns cached result on subsequent calls
|
||||
*/
|
||||
export async function getAvailableStorageLocations(): Promise<
|
||||
StorageLocation[]
|
||||
> {
|
||||
if (Platform.OS !== "android") {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (cachedStorageLocations !== null) {
|
||||
return cachedStorageLocations;
|
||||
}
|
||||
|
||||
try {
|
||||
const locations = await BackgroundDownloader.getAvailableStorageLocations();
|
||||
|
||||
// Debug mode: Add a functional simulated SD card for testing
|
||||
if (DEBUG_SIMULATE_SD_CARD && locations.length === 1) {
|
||||
// Use a real writable path within the app's document directory
|
||||
const sdcardSimDir = new Directory(Paths.document, "sdcard_sim");
|
||||
|
||||
// Create the directory if it doesn't exist
|
||||
if (!sdcardSimDir.exists) {
|
||||
sdcardSimDir.create({ intermediates: true });
|
||||
}
|
||||
|
||||
const mockSdCard: StorageLocation = {
|
||||
id: "sdcard_sim",
|
||||
path: sdcardSimDir.uri.replace("file://", ""),
|
||||
type: "external",
|
||||
label: "SD Card (Simulated)",
|
||||
totalSpace: 64 * 1024 * 1024 * 1024, // 64 GB
|
||||
freeSpace: 32 * 1024 * 1024 * 1024, // 32 GB free
|
||||
};
|
||||
locations.push(mockSdCard);
|
||||
console.log("[DEBUG] Added simulated SD card:", mockSdCard.path);
|
||||
}
|
||||
|
||||
cachedStorageLocations = locations;
|
||||
return locations;
|
||||
} catch (error) {
|
||||
console.error("Failed to get storage locations:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cached storage locations
|
||||
* Useful when storage configuration might have changed
|
||||
*/
|
||||
export function clearStorageLocationsCache(): void {
|
||||
cachedStorageLocations = null;
|
||||
console.log("[Storage] Cache cleared");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a simplified label for a storage location ID
|
||||
* @param storageId - The storage location ID (e.g., "internal", "sdcard_0")
|
||||
* @returns Human-readable label (e.g., "Internal Storage", "SD Card")
|
||||
*/
|
||||
export async function getStorageLabel(storageId?: string): Promise<string> {
|
||||
if (!storageId || Platform.OS !== "android") {
|
||||
return "Internal Storage";
|
||||
}
|
||||
|
||||
const locations = await getAvailableStorageLocations();
|
||||
const location = locations.find((loc) => loc.id === storageId);
|
||||
|
||||
return location?.label || "Internal Storage";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filesystem path for a storage location ID
|
||||
* @param storageId - The storage location ID (e.g., "internal", "sdcard_0")
|
||||
* @returns The filesystem path, or default path if not found
|
||||
*/
|
||||
export async function getStoragePath(storageId?: string): Promise<string> {
|
||||
if (!storageId || Platform.OS !== "android") {
|
||||
return getDefaultStoragePath();
|
||||
}
|
||||
|
||||
const locations = await getAvailableStorageLocations();
|
||||
const location = locations.find((loc) => loc.id === storageId);
|
||||
|
||||
if (!location) {
|
||||
console.warn(`Storage location not found: ${storageId}, using default`);
|
||||
return getDefaultStoragePath();
|
||||
}
|
||||
|
||||
return location.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default storage path (current behavior using Paths.document)
|
||||
* @returns The default storage path
|
||||
*/
|
||||
export function getDefaultStoragePath(): string {
|
||||
// Paths.document returns a Directory with a URI like "file:///data/user/0/..."
|
||||
// We need to extract the actual path
|
||||
const uri = Paths.document.uri;
|
||||
return uri.replace("file://", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a storage location by ID
|
||||
* @param storageId - The storage location ID
|
||||
* @returns The storage location or undefined if not found
|
||||
*/
|
||||
export async function getStorageLocationById(
|
||||
storageId?: string,
|
||||
): Promise<StorageLocation | undefined> {
|
||||
if (!storageId || Platform.OS !== "android") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const locations = await getAvailableStorageLocations();
|
||||
return locations.find((loc) => loc.id === storageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert plain file path to file:// URI
|
||||
* Required for expo-file-system File constructor
|
||||
* @param path - The file path
|
||||
* @returns The file:// URI
|
||||
*/
|
||||
export function filePathToUri(path: string): string {
|
||||
if (path.startsWith("file://")) {
|
||||
return path;
|
||||
}
|
||||
return `file://${path}`;
|
||||
}
|
||||
Reference in New Issue
Block a user