Settings Fields V

This commit is contained in:
Simon Caron
2024-12-31 16:09:12 -05:00
parent 602de34824
commit 723233381c
7 changed files with 111 additions and 101 deletions

View File

@@ -14,6 +14,7 @@ import { Alert, ScrollView, View } from "react-native";
import * as Progress from "react-native-progress";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { toast } from "sonner-native";
import { useTranslation } from "react-i18next";
export default function settings() {
const { logout } = useJellyfin();
@@ -25,6 +26,8 @@ export default function settings() {
const insets = useSafeAreaInsets();
const { t } = useTranslation();
const { data: size, isLoading: appSizeLoading } = useQuery({
queryKey: ["appSize", appSizeUsage],
queryFn: async () => {
@@ -98,31 +101,31 @@ export default function settings() {
registerBackgroundFetchAsync
</Button> */}
<View>
<Text className="font-bold text-lg mb-2">User Info</Text>
<Text className="font-bold text-lg mb-2">{t("home.settings.user_info.user_info_title")}</Text>
<View className="flex flex-col rounded-xl overflow-hidden border-neutral-800 divide-y-2 divide-solid divide-neutral-800 ">
<ListItem title="User" subTitle={user?.Name} />
<ListItem title="Server" subTitle={api?.basePath} />
<ListItem title="Token" subTitle={api?.accessToken} />
<ListItem title={t("home.settings.user_info.user")} subTitle={user?.Name} />
<ListItem title={t("home.settings.user_info.server")} subTitle={api?.basePath} />
<ListItem title={t("home.settings.user_info.token")} subTitle={api?.accessToken} />
</View>
<Button className="my-2.5" color="black" onPress={logout}>
Log out
{t("home.settings.user_info.log_out_button")}
</Button>
</View>
<View>
<Text className="font-bold text-lg mb-2">Quick connect</Text>
<Text className="font-bold text-lg mb-2">{t("home.settings.quick_connect.quick_connect_title")}</Text>
<Button onPress={openQuickConnectAuthCodeInput} color="black">
Authorize
{t("home.settings.quick_connect.authorize_button")}
</Button>
</View>
<SettingToggles />
<View className="flex flex-col space-y-2">
<Text className="font-bold text-lg mb-2">Storage</Text>
<Text className="font-bold text-lg mb-2">{t("home.settings.storage.storage_title")}</Text>
<View className="mb-4 space-y-2">
{size && <Text>App usage: {size.app.bytesToReadable()}</Text>}
{size && <Text>{t("home.settings.storage.app_usage", {usedSpace: size.app.bytesToReadable()})}</Text>}
<Progress.Bar
className="bg-gray-100/10"
indeterminate={appSizeLoading}
@@ -135,20 +138,20 @@ export default function settings() {
/>
{size && (
<Text>
Available: {size.remaining?.bytesToReadable()}, Total:{" "}
{size.total?.bytesToReadable()}
{t("home.settings.storage.available_total", {availableSpace: size.remaining?.bytesToReadable(), totalSpace: size.total?.bytesToReadable()})}
{}
</Text>
)}
</View>
<Button color="red" onPress={onDeleteClicked}>
Delete all downloaded files
{t("home.settings.storage.delete_all_downloaded_files")}
</Button>
<Button color="red" onPress={onClearLogsClicked}>
Delete all logs
{t("home.settings.storage.delete_all_logs")}
</Button>
</View>
<View>
<Text className="font-bold text-lg mb-2">Logs</Text>
<Text className="font-bold text-lg mb-2">{t("home.settings.logs.logs_title")}</Text>
<View className="flex flex-col space-y-2">
{logs?.map((log, index) => (
<View key={index} className="bg-neutral-900 rounded-xl p-3">
@@ -167,7 +170,7 @@ export default function settings() {
</View>
))}
{logs?.length === 0 && (
<Text className="opacity-50">No logs available</Text>
<Text className="opacity-50">{t("home.settings.logs.no_logs_available")}</Text>
)}
</View>
</View>

View File

@@ -3,6 +3,7 @@ import * as DropdownMenu from "zeego/dropdown-menu";
import { Text } from "../common/Text";
import { useMedia } from "./MediaContext";
import { Switch } from "react-native-gesture-handler";
import { useTranslation } from "react-i18next";
interface Props extends ViewProps {}
@@ -10,12 +11,13 @@ export const AudioToggles: React.FC<Props> = ({ ...props }) => {
const media = useMedia();
const { settings, updateSettings } = media;
const cultures = media.cultures;
const { t } = useTranslation();
if (!settings) return null;
return (
<View>
<Text className="text-lg font-bold mb-2">Audio</Text>
<Text className="text-lg font-bold mb-2">{t("home.settings.audio.audio_title")}</Text>
<View className="flex flex-col rounded-xl mb-4 overflow-hidden divide-y-2 divide-solid divide-neutral-800">
<View
className={`
@@ -23,9 +25,9 @@ export const AudioToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Audio language</Text>
<Text className="font-semibold">{t("home.settings.audio.audio_language")}</Text>
<Text className="text-xs opacity-50">
Choose a default audio language.
{t("home.settings.audio.audio_language_hint")}
</Text>
</View>
<DropdownMenu.Root>
@@ -76,9 +78,9 @@ export const AudioToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-col">
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="flex flex-col">
<Text className="font-semibold">Use Default Audio</Text>
<Text className="font-semibold">{t("home.settings.audio.use_default_audio")}</Text>
<Text className="text-xs opacity-50">
Play default audio track regardless of language.
{t("home.settings.audio.use_default_audio_hint")}
</Text>
</View>
<Switch
@@ -93,11 +95,10 @@ export const AudioToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="flex flex-col">
<Text className="font-semibold">
Set Audio Track From Previous Item
{t("home.settings.audio.set_audio_track")}
</Text>
<Text className="text-xs opacity-50 min max-w-[85%]">
Try to set the audio track to the closest match to the last
video.
{t("home.settings.audio.set_audio_track_hint")}
</Text>
</View>
<Switch

View File

@@ -11,6 +11,7 @@ import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { useAtom } from "jotai";
import { toast } from "sonner-native";
import { useMutation } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
export const JellyseerrSettings = () => {
const {
@@ -20,6 +21,8 @@ export const JellyseerrSettings = () => {
clearAllJellyseerData,
} = useJellyseerr();
const { t } = useTranslation();
const [user] = useAtom(userAtom);
const [settings, updateSettings] = useSettings();
@@ -121,19 +124,16 @@ export const JellyseerrSettings = () => {
) : (
<View className="flex flex-col rounded-xl overflow-hidden p-4 bg-neutral-900">
<Text className="text-xs text-red-600 mb-2">
This integration is in its early stages. Expect things to change.
{t("home.settings.jellyseer.jellyseer_warning")}
</Text>
<Text className="font-bold mb-1">Server URL</Text>
<Text className="font-bold mb-1">{t("home.settings.jellyseer.server_url")}</Text>
<View className="flex flex-col shrink mb-2">
<Text className="text-xs text-gray-600">
Example: http(s)://your-host.url
</Text>
<Text className="text-xs text-gray-600">
(add port if required)
{t("home.settings.jellyseer.server_url_hint")}
</Text>
</View>
<Input
placeholder="Jellyseerr URL..."
placeholder={t("home.settings.jellyseer.server_url_placeholder")}
value={settings?.jellyseerrServerUrl ?? jellyseerrServerUrl}
defaultValue={
settings?.jellyseerrServerUrl ?? jellyseerrServerUrl
@@ -163,7 +163,7 @@ export const JellyseerrSettings = () => {
marginBottom: 8,
}}
>
{promptForJellyseerrPass ? "Clear" : "Save"}
{promptForJellyseerrPass ? t("home.settings.jellyseer.clear_button") : t("home.settings.jellyseer.save_button")}
</Button>
<View
@@ -172,11 +172,11 @@ export const JellyseerrSettings = () => {
opacity: promptForJellyseerrPass ? 1 : 0.5,
}}
>
<Text className="font-bold mb-2">Password</Text>
<Text className="font-bold mb-2">{t("home.settings.jellyseer.password")}</Text>
<Input
autoFocus={true}
focusable={true}
placeholder={`Enter password for Jellyfin user ${user?.Name}`}
placeholder={t("home.settings.jellyseer.password_placeholder", {username: user?.Name})}
value={jellyseerrPassword}
keyboardType="default"
secureTextEntry={true}
@@ -196,7 +196,7 @@ export const JellyseerrSettings = () => {
className="h-12 mt-2"
onPress={() => loginToJellyseerrMutation.mutate()}
>
Login
{t("home.settings.jellyseer.login_button")}
</Button>
</View>
</View>

View File

@@ -1,17 +1,19 @@
import { useSettings } from "@/utils/atoms/settings";
import { TouchableOpacity, View, ViewProps } from "react-native";
import { Text } from "../common/Text";
import { useTranslation } from "react-i18next";
interface Props extends ViewProps {}
export const MediaToggles: React.FC<Props> = ({ ...props }) => {
const [settings, updateSettings] = useSettings();
const { t } = useTranslation();
if (!settings) return null;
return (
<View>
<Text className="text-lg font-bold mb-2">Media</Text>
<Text className="text-lg font-bold mb-2">{t("home.settings.media.media_title")}</Text>
<View className="flex flex-col rounded-xl mb-4 overflow-hidden divide-y-2 divide-solid divide-neutral-800">
<View
className={`
@@ -19,9 +21,9 @@ export const MediaToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Forward skip length</Text>
<Text className="font-semibold">{t("home.settings.media.forward_skip_length")}</Text>
<Text className="text-xs opacity-50">
Choose length in seconds when skipping in video playback.
{t("home.settings.media.forward_skip_length_hint")}
</Text>
</View>
<View className="flex flex-row items-center">
@@ -57,9 +59,9 @@ export const MediaToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Rewind length</Text>
<Text className="font-semibold">{t("home.settings.media.rewind_length")}</Text>
<Text className="text-xs opacity-50">
Choose length in seconds when skipping in video playback.
{t("home.settings.media.rewind_length_hint")}
</Text>
</View>
<View className="flex flex-row items-center">

View File

@@ -43,6 +43,7 @@ import { AudioToggles } from "./AudioToggles";
import { JellyseerrApi, useJellyseerr } from "@/hooks/useJellyseerr";
import { ListItem } from "@/components/ListItem";
import { JellyseerrSettings } from "./Jellyseerr";
import { useTranslation } from "react-i18next";
interface Props extends ViewProps {}
@@ -59,6 +60,8 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
const queryClient = useQueryClient();
const { t } = useTranslation();
/********************
* Background task
*******************/
@@ -137,15 +140,14 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
</MediaProvider>
<View>
<Text className="text-lg font-bold mb-2">Other</Text>
<Text className="text-lg font-bold mb-2">{t("home.settings.other.other_title")}</Text>
<View className="flex flex-col rounded-xl overflow-hidden divide-y-2 divide-solid divide-neutral-800">
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="shrink">
<Text className="font-semibold">Auto rotate</Text>
<Text className="font-semibold">{t("home.settings.other.auto_rotate")}</Text>
<Text className="text-xs opacity-50">
Important on android since the video player orientation is
locked to the app orientation.
{t("home.settings.other.auto_rotate_hint")}
</Text>
</View>
<Switch
@@ -166,9 +168,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Video orientation</Text>
<Text className="font-semibold">{t("home.settings.other.video_orientation")}</Text>
<Text className="text-xs opacity-50">
Set the full screen video player orientation.
{t("home.settings.other.video_orientation_hint")}
</Text>
</View>
<DropdownMenu.Root>
@@ -263,9 +265,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="shrink">
<Text className="font-semibold">Safe area in controls</Text>
<Text className="font-semibold">{t("home.settings.other.safe_area_in_controls")}</Text>
<Text className="text-xs opacity-50">
Enable safe area in video player controls
{t("home.settings.other.safe_area_in_controls_hint")}
</Text>
</View>
<Switch
@@ -279,8 +281,8 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-col">
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="flex flex-col">
<Text className="font-semibold">Use popular lists plugin</Text>
<Text className="text-xs opacity-50">Made by: lostb1t</Text>
<Text className="font-semibold">{t("home.settings.other.use_popular_lists_plugin")}</Text>
<Text className="text-xs opacity-50">{t("home.settings.other.use_popular_lists_plugin_hint")}</Text>
<TouchableOpacity
onPress={() => {
Linking.openURL(
@@ -288,7 +290,7 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
);
}}
>
<Text className="text-xs text-purple-600">More info</Text>
<Text className="text-xs text-purple-600">{t("home.settings.other.more_info")}</Text>
</TouchableOpacity>
</View>
<Switch
@@ -353,9 +355,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Search engine</Text>
<Text className="font-semibold">{t("home.settings.other.search_engine")}</Text>
<Text className="text-xs opacity-50">
Choose the search engine you want to use.
{t("home.settings.other.search_engine_hint")}
</Text>
</View>
<DropdownMenu.Root>
@@ -421,7 +423,7 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
});
}}
>
Save
{t("home.settings.other.save_button")}
</Button>
</View>
@@ -436,10 +438,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="shrink">
<Text className="font-semibold">Show Custom Menu Links</Text>
<Text className="font-semibold">{t("home.settings.other.show_custom_menu_links")}</Text>
<Text className="text-xs opacity-50">
Show custom menu links defined inside your Jellyfin web
config.json file
{t("home.settings.other.show_custom_menu_links_hint")}
</Text>
<TouchableOpacity
onPress={() =>
@@ -448,7 +449,7 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
)
}
>
<Text className="text-xs text-purple-600">More info</Text>
<Text className="text-xs text-purple-600">{t("home.settings.other.more_info")}</Text>
</TouchableOpacity>
</View>
<Switch
@@ -462,7 +463,7 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
</View>
<View className="mt-4">
<Text className="text-lg font-bold mb-2">Downloads</Text>
<Text className="text-lg font-bold mb-2">{t("home.settings.downloads.downloads_title")}</Text>
<View className="flex flex-col rounded-xl overflow-hidden divide-y-2 divide-solid divide-neutral-800">
<View
className={`
@@ -470,10 +471,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Download method</Text>
<Text className="font-semibold">{t("home.settings.downloads.download_method")}</Text>
<Text className="text-xs opacity-50">
Choose the download method to use. Optimized requires the
optimized server.
{t("home.settings.downloads.download_method_hint")}
</Text>
</View>
<DropdownMenu.Root>
@@ -531,10 +531,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
}`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Remux max download</Text>
<Text className="font-semibold">{t("home.settings.downloads.remux_max_download")}</Text>
<Text className="text-xs opacity-50 shrink">
This is the total media you want to be able to download at the
same time.
{t("home.settings.downloads.remux_max_download_hint")}
</Text>
</View>
<Stepper
@@ -563,10 +562,9 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
}`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Auto download</Text>
<Text className="font-semibold">{t("home.settings.downloads.auto_download")}</Text>
<Text className="text-xs opacity-50 shrink">
This will automatically download the media file when it's
finished optimizing on the server.
{t("home.settings.downloads.auto_download_hint")}
</Text>
</View>
<Switch
@@ -589,11 +587,11 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-col shrink mb-2">
<View className="flex flex-row justify-between items-center">
<Text className="font-semibold">
Optimized versions server
{t("home.settings.downloads.optimized_versions_server")}
</Text>
</View>
<Text className="text-xs opacity-50">
Set the URL for the optimized versions server for downloads.
{t("home.settings.downloads.optimized_versions_server_hint")}
</Text>
</View>
<View></View>
@@ -629,7 +627,7 @@ export const SettingToggles: React.FC<Props> = ({ ...props }) => {
} else toast.error("Could not connect");
}}
>
Save
{t("home.settings.downloads.save_button")}
</Button>
</View>
</View>

View File

@@ -4,6 +4,7 @@ import { Text } from "../common/Text";
import { useMedia } from "./MediaContext";
import { Switch } from "react-native-gesture-handler";
import { SubtitlePlaybackMode } from "@jellyfin/sdk/lib/generated-client";
import { useTranslation } from "react-i18next";
interface Props extends ViewProps {}
@@ -11,6 +12,8 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
const media = useMedia();
const { settings, updateSettings } = media;
const cultures = media.cultures;
const { t } = useTranslation();
if (!settings) return null;
const subtitleModes = [
@@ -23,7 +26,7 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
return (
<View>
<Text className="text-lg font-bold mb-2">Subtitle</Text>
<Text className="text-lg font-bold mb-2">{t("home.settings.subtitles.subtitle_title")}</Text>
<View className="flex flex-col rounded-xl mb-4 overflow-hidden divide-y-2 divide-solid divide-neutral-800">
<View
className={`
@@ -31,9 +34,9 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Subtitle language</Text>
<Text className="font-semibold">{t("home.settings.subtitles.subtitle_language")}</Text>
<Text className="text-xs opacity-50">
Choose a default subtitle language.
{t("home.settings.subtitles.subtitle_language_hint")}
</Text>
</View>
<DropdownMenu.Root>
@@ -88,11 +91,9 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Subtitle Mode</Text>
<Text className="font-semibold">{t("home.settings.subtitles.subtitle_mode")}</Text>
<Text className="text-xs opacity-50 mr-2">
Subtitles are loaded based on the default and forced flags in the
embedded metadata. Language preferences are considered when
multiple options are available.
{t("home.settings.subtitles.subtitle_mode_hint")}
</Text>
</View>
<DropdownMenu.Root>
@@ -131,11 +132,10 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
<View className="flex flex-col">
<Text className="font-semibold">
Set Subtitle Track From Previous Item
{t("home.settings.subtitles.set_subtitle_track")}
</Text>
<Text className="text-xs opacity-50 min max-w-[85%]">
Try to set the subtitle track to the closest match to the last
video.
{t("home.settings.subtitles.set_subtitle_track_hint")}
</Text>
</View>
<Switch
@@ -153,10 +153,9 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Subtitle Size</Text>
<Text className="font-semibold">{t("home.settings.subtitles.subtitle_size")}</Text>
<Text className="text-xs opacity-50">
Choose a default subtitle size for direct play (only works for
some subtitle formats).
{t("home.settings.subtitles.subtitle_size_hint")}
</Text>
</View>
<View className="flex flex-row items-center">

View File

@@ -29,13 +29,16 @@
"suggested_episodes": "Suggested Episodes",
"settings": {
"settings_title": "Settings",
"user_info": "User Info",
"user": "User",
"server": "Server",
"token": "Token",
"log_out": "Log out",
"quick_connect": "Quick connect",
"authorize": "Authorize",
"user_info": {
"user_info_title": "User Info",
"user": "User",
"server": "Server",
"log_out_button": "Log out"
},
"quick_connect": {
"quick_connect_title": "Quick connect",
"authorize_button": "Authorize"
},
"media":{
"media_title": "Media",
"forward_skip_length": "Forward skip length",
@@ -58,14 +61,15 @@
"subtitle_language_hint": "Choose a default subtitle language.",
"subtitle_mode": "Subtitle Mode",
"subtitle_mode_hint": "Subtitles are loaded based on the default and forced flags in the\nembedded metadata. Language preferences are considered when\nmultiple options are available.",
"set_subtitle_track": "Try to set the subtitle track to the closest match to the last\nvideo.",
"set_subtitle_track": "Set Subtitle Track From Previous Item",
"set_subtitle_track_hint" :"Try to set the subtitle track to the closest match to the last\nvideo.",
"subtitle_size": "Subtitle Size",
"subtitle_size_hint": "Choose a default subtitle size for direct play (only works for\nsome subtitle formats)."
},
"other": {
"other_title": "Other",
"auto_rotate": "Auto rotate",
"auto_rotate_hint": "Important on android since the video player orientation is\nlocked to the app orientation.",
"auto_rotate_hint": "Important on android since the video player orientation is locked to the app orientation.",
"video_orientation": "Video orientation",
"video_orientation_hint": "Set the full screen video player orientation",
"safe_area_in_controls": "Safe area in controls",
@@ -76,18 +80,20 @@
"search_engine": "Search engine",
"search_engine_hint": "Choose the search engine you want to use.",
"show_custom_menu_links": "Show Custom Menu Links",
"show_custom_menu_links_hint": "Show custom menu links defined inside your Jellyfin web\nconfig.json file"
"show_custom_menu_links_hint": "Show custom menu links defined inside your Jellyfin web config.json file",
"save_button": "Save"
},
"downloads": {
"downloads_title": "Downloads",
"download_method": "Download method",
"download_method_hint": "Choose the download method to use. Optimized requires the\noptimized server.",
"download_method_hint": "Choose the download method to use. Optimized requires the optimized server.",
"remux_max_download": "Remux max download",
"remux_max_download_hint": "This is the total media you want to be able to download at the\nsame time.",
"remux_max_download_hint": "This is the total media you want to be able to download at the same time.",
"auto_download": "Auto download",
"auto_download_hint": "This will automatically download the media file when it's\nfinished optimizing on the server.",
"auto_download_hint": "This will automatically download the media file when it's finished optimizing on the server.",
"optimized_versions_server": "Optimized versions server",
"optimized_versions_server_hint": "TSet the URL for the optimized versions server for downloads."
"optimized_versions_server_hint": "Set the URL for the optimized versions server for downloads.",
"save_button": "Save"
},
"jellyseer": {
"jellyseer_warning": "This integration is in its early stages. Expect things to change.",
@@ -95,7 +101,10 @@
"server_url_hint": "Example: http(s)://your-host.url\n(add port if required)",
"server_url_placeholder": "Jellyseerr URL...",
"password": "Password",
"password_placeholder": "Enter password for Jellyfin user {{username}}"
"password_placeholder": "Enter password for Jellyfin user {{username}}",
"save_button": "Save",
"clear_button": "Clear",
"login_button": "Login"
},
"storage": {
"storage_title": "Storage",
@@ -107,9 +116,7 @@
"logs": {
"logs_title": "Logs",
"no_logs_available": "No logs available"
},
"save_button": "Save",
"login_button": "Login"
}
},
"downloads": {
"downloads_title": "Downloads",