mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-04 21:18:31 +01:00
The resolver field only needs to find the working URL — the Jellyseerr version requirement is irrelevant there and only polluted the UI. - jellyseerrProbe: validate reachability + that it's a jellyseerr (no version gate, no version-too-low outcome). - Drop the version-too-low reason from the whole resolver stack (types, resolve, hook, status text, i18n). - Min version 2.0.0 stays enforced in JellyseerrApi.test() at login: now writes an error log + toast, and uses numeric isVersionBelow (fixes the "2.10.0" < "2.0.0" string-compare bug).
194 lines
7.0 KiB
TypeScript
194 lines
7.0 KiB
TypeScript
import { useMutation } from "@tanstack/react-query";
|
|
import { useAtom } from "jotai";
|
|
import { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { View } from "react-native";
|
|
import { toast } from "sonner-native";
|
|
import { JellyseerrApi, useJellyseerr } from "@/hooks/useJellyseerr";
|
|
import { userAtom } from "@/providers/JellyfinProvider";
|
|
import { useSettings } from "@/utils/atoms/settings";
|
|
import { jellyseerrProbe } from "@/utils/serverUrl/probes/jellyseerr";
|
|
import { resolveServerUrl } from "@/utils/serverUrl/resolve";
|
|
import { Button } from "../Button";
|
|
import { Input } from "../common/Input";
|
|
import { ServerUrlField } from "../common/ServerUrlField";
|
|
import { Text } from "../common/Text";
|
|
import { ListGroup } from "../list/ListGroup";
|
|
import { ListItem } from "../list/ListItem";
|
|
|
|
export const JellyseerrSettings = () => {
|
|
const { jellyseerrUser, setJellyseerrUser, clearAllJellyseerData } =
|
|
useJellyseerr();
|
|
|
|
const { t } = useTranslation();
|
|
|
|
const [user] = useAtom(userAtom);
|
|
const { settings, updateSettings } = useSettings();
|
|
|
|
const [jellyseerrPassword, setJellyseerrPassword] = useState<
|
|
string | undefined
|
|
>(undefined);
|
|
|
|
const [jellyseerrServerUrl, setjellyseerrServerUrl] = useState<string>(
|
|
settings?.jellyseerrServerUrl ?? "",
|
|
);
|
|
const [resolvedUrl, setResolvedUrl] = useState<string | undefined>(
|
|
settings?.jellyseerrServerUrl ?? undefined,
|
|
);
|
|
|
|
const loginToJellyseerrMutation = useMutation({
|
|
mutationFn: async () => {
|
|
if (!user?.Name)
|
|
throw new Error("Missing required information for login");
|
|
|
|
// Prefer the already-resolved URL; otherwise resolve the raw input now
|
|
// (covers tapping Login before the field's on-blur resolve settled).
|
|
let finalUrl = resolvedUrl || settings?.jellyseerrServerUrl || "";
|
|
if (!finalUrl && jellyseerrServerUrl) {
|
|
const resolved = await resolveServerUrl(
|
|
jellyseerrServerUrl,
|
|
jellyseerrProbe,
|
|
);
|
|
if (!resolved.ok) throw new Error("Invalid server url");
|
|
finalUrl = resolved.url;
|
|
}
|
|
if (!finalUrl) throw new Error("Missing server url");
|
|
|
|
const jellyseerrTempApi = new JellyseerrApi(finalUrl);
|
|
const testResult = await jellyseerrTempApi.test();
|
|
if (!testResult.isValid) throw new Error("Invalid server url");
|
|
const loggedInUser = await jellyseerrTempApi.login(
|
|
user.Name,
|
|
jellyseerrPassword || "",
|
|
);
|
|
return { user: loggedInUser, url: finalUrl };
|
|
},
|
|
onSuccess: ({ user: loggedInUser, url }) => {
|
|
setJellyseerrUser(loggedInUser);
|
|
setResolvedUrl(url);
|
|
updateSettings({ jellyseerrServerUrl: url });
|
|
},
|
|
onError: () => {
|
|
toast.error(t("jellyseerr.failed_to_login"));
|
|
},
|
|
onSettled: () => {
|
|
setJellyseerrPassword(undefined);
|
|
},
|
|
});
|
|
|
|
const clearData = () => {
|
|
clearAllJellyseerData().finally(() => {
|
|
setJellyseerrUser(undefined);
|
|
setJellyseerrPassword(undefined);
|
|
setjellyseerrServerUrl("");
|
|
setResolvedUrl(undefined);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<View className=''>
|
|
<View>
|
|
{jellyseerrUser ? (
|
|
<>
|
|
<ListGroup title={"Jellyseerr"}>
|
|
<ListItem
|
|
title={t(
|
|
"home.settings.plugins.jellyseerr.total_media_requests",
|
|
)}
|
|
value={jellyseerrUser?.requestCount?.toString()}
|
|
/>
|
|
<ListItem
|
|
title={t("home.settings.plugins.jellyseerr.movie_quota_limit")}
|
|
value={
|
|
jellyseerrUser?.movieQuotaLimit?.toString() ??
|
|
t("home.settings.plugins.jellyseerr.unlimited")
|
|
}
|
|
/>
|
|
<ListItem
|
|
title={t("home.settings.plugins.jellyseerr.movie_quota_days")}
|
|
value={
|
|
jellyseerrUser?.movieQuotaDays?.toString() ??
|
|
t("home.settings.plugins.jellyseerr.unlimited")
|
|
}
|
|
/>
|
|
<ListItem
|
|
title={t("home.settings.plugins.jellyseerr.tv_quota_limit")}
|
|
value={
|
|
jellyseerrUser?.tvQuotaLimit?.toString() ??
|
|
t("home.settings.plugins.jellyseerr.unlimited")
|
|
}
|
|
/>
|
|
<ListItem
|
|
title={t("home.settings.plugins.jellyseerr.tv_quota_days")}
|
|
value={
|
|
jellyseerrUser?.tvQuotaDays?.toString() ??
|
|
t("home.settings.plugins.jellyseerr.unlimited")
|
|
}
|
|
/>
|
|
</ListGroup>
|
|
|
|
<View className='p-4'>
|
|
<Button color='red' onPress={clearData}>
|
|
{t(
|
|
"home.settings.plugins.jellyseerr.reset_jellyseerr_config_button",
|
|
)}
|
|
</Button>
|
|
</View>
|
|
</>
|
|
) : (
|
|
<View className='flex flex-col rounded-xl overflow-hidden p-4 bg-neutral-900'>
|
|
<Text className='text-xs text-red-600 mb-2'>
|
|
{t("home.settings.plugins.jellyseerr.jellyseerr_warning")}
|
|
</Text>
|
|
<View className='mb-2'>
|
|
<ServerUrlField
|
|
value={jellyseerrServerUrl}
|
|
onChangeText={setjellyseerrServerUrl}
|
|
onResolved={(url) => setResolvedUrl(url)}
|
|
probe={jellyseerrProbe}
|
|
label={t("home.settings.plugins.jellyseerr.server_url")}
|
|
hint={t("home.settings.plugins.jellyseerr.server_url_hint")}
|
|
placeholder={t(
|
|
"home.settings.plugins.jellyseerr.server_url_placeholder",
|
|
)}
|
|
editable={!loginToJellyseerrMutation.isPending}
|
|
/>
|
|
</View>
|
|
<View>
|
|
<Text className='font-bold mb-2'>
|
|
{t("home.settings.plugins.jellyseerr.password")}
|
|
</Text>
|
|
<Input
|
|
className='border border-neutral-800'
|
|
autoFocus={true}
|
|
focusable={true}
|
|
placeholder={t(
|
|
"home.settings.plugins.jellyseerr.password_placeholder",
|
|
{ username: user?.Name },
|
|
)}
|
|
value={jellyseerrPassword}
|
|
keyboardType='default'
|
|
secureTextEntry={true}
|
|
returnKeyType='done'
|
|
autoCapitalize='none'
|
|
textContentType='password'
|
|
onChangeText={setJellyseerrPassword}
|
|
editable={!loginToJellyseerrMutation.isPending}
|
|
/>
|
|
<Button
|
|
loading={loginToJellyseerrMutation.isPending}
|
|
disabled={loginToJellyseerrMutation.isPending}
|
|
color='purple'
|
|
className='h-12 mt-2'
|
|
onPress={() => loginToJellyseerrMutation.mutate()}
|
|
>
|
|
{t("home.settings.plugins.jellyseerr.login_button")}
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
)}
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|