mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-18 08:43:57 +00:00
feat: own tab to torbox
This commit is contained in:
2
src/renderer/src/declaration.d.ts
vendored
2
src/renderer/src/declaration.d.ts
vendored
@@ -28,6 +28,7 @@ import type {
|
||||
CatalogueSearchPayload,
|
||||
LibraryGame,
|
||||
GameRunning,
|
||||
TorBoxUser,
|
||||
} from "@types";
|
||||
import type { AxiosProgressEvent } from "axios";
|
||||
import type disk from "diskusage";
|
||||
@@ -142,6 +143,7 @@ declare global {
|
||||
minimized: boolean;
|
||||
}) => Promise<void>;
|
||||
authenticateRealDebrid: (apiToken: string) => Promise<RealDebridUser>;
|
||||
authenticateTorBox: (apiToken: string) => Promise<TorBoxUser>;
|
||||
onAchievementUnlocked: (cb: () => void) => () => Electron.IpcRenderer;
|
||||
|
||||
/* Download sources */
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useContext, useEffect, useState } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
||||
import * as styles from "./settings-debrid.css";
|
||||
import * as styles from "./settings-real-debrid.css";
|
||||
|
||||
import { useAppSelector, useToast } from "@renderer/hooks";
|
||||
|
||||
@@ -10,9 +10,8 @@ import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { settingsContext } from "@renderer/context";
|
||||
|
||||
const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
|
||||
const TORBOX_API_TOKEN_URL = "https://torbox.app/settings";
|
||||
|
||||
export function SettingsDebrid() {
|
||||
export function SettingsRealDebrid() {
|
||||
const userPreferences = useAppSelector(
|
||||
(state) => state.userPreferences.value
|
||||
);
|
||||
@@ -23,8 +22,6 @@ export function SettingsDebrid() {
|
||||
const [form, setForm] = useState({
|
||||
useRealDebrid: false,
|
||||
realDebridApiToken: null as string | null,
|
||||
useTorBox: false,
|
||||
torBoxApiToken: null as string | null,
|
||||
});
|
||||
|
||||
const { showSuccessToast, showErrorToast } = useToast();
|
||||
@@ -36,8 +33,6 @@ export function SettingsDebrid() {
|
||||
setForm({
|
||||
useRealDebrid: Boolean(userPreferences.realDebridApiToken),
|
||||
realDebridApiToken: userPreferences.realDebridApiToken ?? null,
|
||||
useTorBox: Boolean(userPreferences.torBoxApiToken),
|
||||
torBoxApiToken: userPreferences.torBoxApiToken ?? null,
|
||||
});
|
||||
}
|
||||
}, [userPreferences]);
|
||||
@@ -62,7 +57,7 @@ export function SettingsDebrid() {
|
||||
return;
|
||||
} else {
|
||||
showSuccessToast(
|
||||
t("real_debrid_linked_message", { username: user.username })
|
||||
t("debrid_linked_message", { username: user.username })
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -71,10 +66,9 @@ export function SettingsDebrid() {
|
||||
|
||||
updateUserPreferences({
|
||||
realDebridApiToken: form.useRealDebrid ? form.realDebridApiToken : null,
|
||||
torBoxApiToken: form.useTorBox ? form.torBoxApiToken : null,
|
||||
});
|
||||
} catch (err) {
|
||||
showErrorToast(t("real_debrid_invalid_token"));
|
||||
showErrorToast(t("debrid_invalid_token"));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -100,14 +94,18 @@ export function SettingsDebrid() {
|
||||
|
||||
{form.useRealDebrid && (
|
||||
<TextField
|
||||
label={t("real_debrid_api_token")}
|
||||
label={t("api_token")}
|
||||
value={form.realDebridApiToken ?? ""}
|
||||
type="password"
|
||||
onChange={(event) =>
|
||||
setForm({ ...form, realDebridApiToken: event.target.value })
|
||||
}
|
||||
placeholder="API Token"
|
||||
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
||||
containerProps={{
|
||||
style: {
|
||||
marginTop: `${SPACING_UNIT}px`,
|
||||
},
|
||||
}}
|
||||
rightContent={
|
||||
<Button
|
||||
type="submit"
|
||||
@@ -120,52 +118,12 @@ export function SettingsDebrid() {
|
||||
</Button>
|
||||
}
|
||||
hint={
|
||||
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
||||
<Trans i18nKey="debrid_api_token_hint" ns="settings">
|
||||
<Link to={REAL_DEBRID_API_TOKEN_URL} />
|
||||
</Trans>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_torbox")}
|
||||
checked={form.useTorBox}
|
||||
onChange={() =>
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
useTorBox: !form.useTorBox,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
|
||||
{form.useTorBox && (
|
||||
<TextField
|
||||
label={t("real_debrid_api_token")}
|
||||
value={form.torBoxApiToken ?? ""}
|
||||
type="password"
|
||||
onChange={(event) =>
|
||||
setForm({ ...form, torBoxApiToken: event.target.value })
|
||||
}
|
||||
placeholder="API Token"
|
||||
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
||||
rightContent={
|
||||
<Button
|
||||
type="submit"
|
||||
style={{
|
||||
alignSelf: "flex-end",
|
||||
}}
|
||||
disabled={isButtonDisabled}
|
||||
>
|
||||
{t("save")}
|
||||
</Button>
|
||||
}
|
||||
hint={
|
||||
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
||||
<Link to={TORBOX_API_TOKEN_URL} />
|
||||
</Trans>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
13
src/renderer/src/pages/settings/settings-torbox.css.ts
Normal file
13
src/renderer/src/pages/settings/settings-torbox.css.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { style } from "@vanilla-extract/css";
|
||||
|
||||
import { SPACING_UNIT } from "../../theme.css";
|
||||
|
||||
export const form = style({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
});
|
||||
|
||||
export const description = style({
|
||||
marginBottom: `${SPACING_UNIT * 2}px`,
|
||||
});
|
||||
119
src/renderer/src/pages/settings/settings-torbox.tsx
Normal file
119
src/renderer/src/pages/settings/settings-torbox.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
||||
import * as styles from "./settings-torbox.css";
|
||||
|
||||
import { useAppSelector, useToast } from "@renderer/hooks";
|
||||
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { settingsContext } from "@renderer/context";
|
||||
|
||||
const TORBOX_API_TOKEN_URL = "https://torbox.app/settings";
|
||||
|
||||
export function SettingsTorbox() {
|
||||
const userPreferences = useAppSelector(
|
||||
(state) => state.userPreferences.value
|
||||
);
|
||||
|
||||
const { updateUserPreferences } = useContext(settingsContext);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [form, setForm] = useState({
|
||||
useTorBox: false,
|
||||
torBoxApiToken: null as string | null,
|
||||
});
|
||||
|
||||
const { showSuccessToast, showErrorToast } = useToast();
|
||||
|
||||
const { t } = useTranslation("settings");
|
||||
|
||||
useEffect(() => {
|
||||
if (userPreferences) {
|
||||
setForm({
|
||||
useTorBox: Boolean(userPreferences.torBoxApiToken),
|
||||
torBoxApiToken: userPreferences.torBoxApiToken ?? null,
|
||||
});
|
||||
}
|
||||
}, [userPreferences]);
|
||||
|
||||
const handleFormSubmit: React.FormEventHandler<HTMLFormElement> = async (
|
||||
event
|
||||
) => {
|
||||
setIsLoading(true);
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
if (form.useTorBox) {
|
||||
const user = await window.electron.authenticateTorBox(
|
||||
form.torBoxApiToken!
|
||||
);
|
||||
|
||||
showSuccessToast(t("debrid_linked_message", { username: user.email }));
|
||||
} else {
|
||||
showSuccessToast(t("changes_saved"));
|
||||
}
|
||||
|
||||
updateUserPreferences({
|
||||
torBoxApiToken: form.useTorBox ? form.torBoxApiToken : null,
|
||||
});
|
||||
} catch (err) {
|
||||
showErrorToast(t("debrid_invalid_token"));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isButtonDisabled =
|
||||
(form.useTorBox && !form.torBoxApiToken) || isLoading;
|
||||
|
||||
return (
|
||||
<form className={styles.form} onSubmit={handleFormSubmit}>
|
||||
<p className={styles.description}>{t("torbox_description")}</p>
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_torbox")}
|
||||
checked={form.useTorBox}
|
||||
onChange={() =>
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
useTorBox: !form.useTorBox,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
|
||||
{form.useTorBox && (
|
||||
<TextField
|
||||
label={t("api_token")}
|
||||
value={form.torBoxApiToken ?? ""}
|
||||
type="password"
|
||||
onChange={(event) =>
|
||||
setForm({ ...form, torBoxApiToken: event.target.value })
|
||||
}
|
||||
placeholder="API Token"
|
||||
containerProps={{
|
||||
style: {
|
||||
marginTop: `${SPACING_UNIT}px`,
|
||||
},
|
||||
}}
|
||||
rightContent={
|
||||
<Button
|
||||
type="submit"
|
||||
style={{
|
||||
alignSelf: "flex-end",
|
||||
}}
|
||||
disabled={isButtonDisabled}
|
||||
>
|
||||
{t("save")}
|
||||
</Button>
|
||||
}
|
||||
hint={
|
||||
<Trans i18nKey="debrid_api_token_hint" ns="settings">
|
||||
<Link to={TORBOX_API_TOKEN_URL} />
|
||||
</Trans>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Button } from "@renderer/components";
|
||||
|
||||
import * as styles from "./settings.css";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SettingsDebrid } from "./settings-debrid";
|
||||
import { SettingsRealDebrid } from "./settings-real-debrid";
|
||||
import { SettingsGeneral } from "./settings-general";
|
||||
import { SettingsBehavior } from "./settings-behavior";
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { SettingsAccount } from "./settings-account";
|
||||
import { useUserDetails } from "@renderer/hooks";
|
||||
import { useMemo } from "react";
|
||||
import { SettingsTorbox } from "./settings-torbox";
|
||||
|
||||
export default function Settings() {
|
||||
const { t } = useTranslation("settings");
|
||||
@@ -25,7 +26,8 @@ export default function Settings() {
|
||||
t("general"),
|
||||
t("behavior"),
|
||||
t("download_sources"),
|
||||
t("debrid_services"),
|
||||
"Torbox",
|
||||
"Real-Debrid",
|
||||
];
|
||||
|
||||
if (userDetails) return [...categories, t("account")];
|
||||
@@ -50,7 +52,11 @@ export default function Settings() {
|
||||
}
|
||||
|
||||
if (currentCategoryIndex === 3) {
|
||||
return <SettingsDebrid />;
|
||||
return <SettingsTorbox />;
|
||||
}
|
||||
|
||||
if (currentCategoryIndex === 4) {
|
||||
return <SettingsRealDebrid />;
|
||||
}
|
||||
|
||||
return <SettingsAccount />;
|
||||
|
||||
Reference in New Issue
Block a user