fix more of the debrid input and testing

This commit is contained in:
Pas 2025-11-19 12:57:19 -07:00
parent 0a7816ff77
commit c94d7bc243
3 changed files with 145 additions and 68 deletions

View file

@ -298,6 +298,7 @@ export function OnboardingPage() {
setdebridToken={usePreferencesStore((s) => s.setdebridToken)}
debridService={usePreferencesStore((s) => s.debridService)}
setdebridService={usePreferencesStore((s) => s.setdebridService)}
mode="onboarding"
/>
</div>
</BiggerCenterContainer>

View file

@ -25,6 +25,7 @@ import {
SetupPart,
Status,
testFebboxKey,
testTorboxToken,
testdebridToken,
} from "@/pages/parts/settings/SetupPart";
import { conf } from "@/setup/config";
@ -55,6 +56,8 @@ interface DebridProps {
setdebridToken: (value: string | null) => void;
debridService: string;
setdebridService: (value: string) => void;
// eslint-disable-next-line react/no-unused-prop-types
mode?: "onboarding" | "settings";
}
function ProxyEdit({
@ -255,14 +258,14 @@ export function FebboxSetup({
const exampleModal = useModal("febbox-example");
// Initialize expansion state for onboarding mode
const [isExpanded, setIsExpanded] = useState(
const [isFebboxExpanded, setIsFebboxExpanded] = useState(
mode === "onboarding" && febboxKey !== null && febboxKey !== "",
);
// Expand when key is set in onboarding mode
useEffect(() => {
if (mode === "onboarding" && febboxKey && febboxKey.length > 0) {
setIsExpanded(true);
setIsFebboxExpanded(true);
}
}, [febboxKey, mode]);
@ -296,14 +299,14 @@ export function FebboxSetup({
}, [febboxKey]);
// Toggle handler based on mode
const toggleExpanded = () => {
const toggleFebboxExpanded = () => {
if (mode === "onboarding") {
// Onboarding mode: expand/collapse, preserve key
if (isExpanded) {
if (isFebboxExpanded) {
setFebboxKey("");
setIsExpanded(false);
setIsFebboxExpanded(false);
} else {
setIsExpanded(true);
setIsFebboxExpanded(true);
}
} else {
// Settings mode: enable/disable
@ -312,7 +315,8 @@ export function FebboxSetup({
};
// Determine if content is visible
const isVisible = mode === "onboarding" ? isExpanded : febboxKey !== null;
const isFebboxVisible =
mode === "onboarding" ? isFebboxExpanded : febboxKey !== null;
if (conf().ALLOW_FEBBOX_KEY) {
return (
@ -329,14 +333,14 @@ export function FebboxSetup({
</div>
<div>
<Toggle
onClick={toggleExpanded}
onClick={toggleFebboxExpanded}
enabled={
mode === "onboarding" ? isExpanded : febboxKey !== null
mode === "onboarding" ? isFebboxExpanded : febboxKey !== null
}
/>
</div>
</div>
{isVisible ? (
{isFebboxVisible ? (
<>
<Divider marginClass="my-6 px-8 box-content -mx-8" />
@ -463,9 +467,15 @@ export function FebboxSetup({
}
}
async function getdebridTokenStatus(debridToken: string | null) {
async function getdebridTokenStatus(
debridToken: string | null,
debridService: string,
) {
if (debridToken) {
const status: Status = await testdebridToken(debridToken);
const status: Status =
debridService === "torbox"
? await testTorboxToken(debridToken)
: await testdebridToken(debridToken);
return status;
}
return "unset";
@ -476,11 +486,24 @@ export function DebridEdit({
setdebridToken,
debridService,
setdebridService,
mode = "settings",
}: DebridProps) {
const { t } = useTranslation();
const user = useAuthStore();
const preferences = usePreferencesStore();
// Initialize expansion state for onboarding mode
const [isDebridExpanded, setIsDebridExpanded] = useState(
mode === "onboarding" && debridToken !== null && debridToken !== "",
);
// Expand when key is set in onboarding mode
useEffect(() => {
if (mode === "onboarding" && debridToken && debridToken.length > 0) {
setIsDebridExpanded(true);
}
}, [debridToken, mode]);
// Enable Real Debrid token when account is loaded and we have a token
useEffect(() => {
if (user.account && debridToken === null && preferences.debridToken) {
@ -488,6 +511,26 @@ export function DebridEdit({
}
}, [user.account, debridToken, preferences.debridToken, setdebridToken]);
// Determine if content is visible
const isDebridVisible =
mode === "onboarding" ? isDebridExpanded : debridToken !== null;
// Toggle handler based on mode
const toggleDebridExpanded = () => {
if (mode === "onboarding") {
// Onboarding mode: expand/collapse, preserve key
if (isDebridExpanded) {
setdebridToken("");
setIsDebridExpanded(false);
} else {
setIsDebridExpanded(true);
}
} else {
// Settings mode: enable/disable
setdebridToken(debridToken === null ? "" : null);
}
};
const [status, setStatus] = useState<Status>("unset");
const statusMap: Record<Status, StatusCircleProps["type"]> = {
error: "error",
@ -499,11 +542,11 @@ export function DebridEdit({
useEffect(() => {
const checkTokenStatus = async () => {
const result = await getdebridTokenStatus(debridToken);
const result = await getdebridTokenStatus(debridToken, debridService);
setStatus(result);
};
checkTokenStatus();
}, [debridToken]);
}, [debridToken, debridService]);
if (conf().ALLOW_DEBRID_KEY) {
return (
@ -518,59 +561,66 @@ export function DebridEdit({
</Trans>
</div>
<div className="flex items-center gap-3">
<Toggle
onClick={() => setdebridToken(debridToken === null ? "" : null)}
enabled={debridToken !== null}
/>
<Toggle onClick={toggleDebridExpanded} enabled={isDebridVisible} />
</div>
</div>
<Divider marginClass="my-6 px-8 box-content -mx-8" />
<p className="text-white font-bold mb-3">{t("debrid.tokenLabel")}</p>
<div className="flex md:flex-row flex-col items-center w-full gap-4">
<div className="flex items-center w-full">
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
<AuthInputBox
onChange={(newToken) => {
setdebridToken(newToken);
}}
value={debridToken ?? ""}
placeholder="ABC123..."
passwordToggleable
className="flex-grow"
/>
</div>
<div className="flex items-center">
<Dropdown
options={[
{
id: "realdebrid",
name: t("debrid.serviceOptions.realdebrid"),
},
{
id: "torbox",
name: t("debrid.serviceOptions.torbox"),
},
]}
selectedItem={{
id: debridService,
name: t(`debrid.serviceOptions.${debridService}`),
}}
setSelectedItem={(item) => setdebridService(item.id)}
direction="up"
/>
</div>
</div>
{status === "error" && (
<p className="text-type-danger mt-4">{t("debrid.status.failure")}</p>
)}
{status === "api_down" && (
<p className="text-type-danger mt-4">{t("debrid.status.api_down")}</p>
)}
{status === "invalid_token" && (
<p className="text-type-danger mt-4">
{t("debrid.status.invalid_token")}
</p>
)}
{isDebridVisible ? (
<>
<Divider marginClass="my-6 px-8 box-content -mx-8" />
<p className="text-white font-bold mb-3">
{t("debrid.tokenLabel")}
</p>
<div className="flex md:flex-row flex-col items-center w-full gap-4">
<div className="flex items-center w-full">
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
<AuthInputBox
onChange={(newToken) => {
setdebridToken(newToken);
}}
value={debridToken ?? ""}
placeholder="ABC123..."
passwordToggleable
className="flex-grow"
/>
</div>
<div className="flex items-center">
<Dropdown
options={[
{
id: "realdebrid",
name: t("debrid.serviceOptions.realdebrid"),
},
{
id: "torbox",
name: t("debrid.serviceOptions.torbox"),
},
]}
selectedItem={{
id: debridService,
name: t(`debrid.serviceOptions.${debridService}`),
}}
setSelectedItem={(item) => setdebridService(item.id)}
direction="up"
/>
</div>
</div>
{status === "error" && (
<p className="text-type-danger mt-4">
{t("debrid.status.failure")}
</p>
)}
{status === "api_down" && (
<p className="text-type-danger mt-4">
{t("debrid.status.api_down")}
</p>
)}
{status === "invalid_token" && (
<p className="text-type-danger mt-4">
{t("debrid.status.invalid_token")}
</p>
)}
</>
) : null}
</SettingsCard>
);
}
@ -606,6 +656,7 @@ export function ConnectionsPart(
setdebridToken={props.setdebridToken}
debridService={props.debridService}
setdebridService={props.setdebridService}
mode="settings"
/>
</div>
</div>

View file

@ -1,5 +1,6 @@
/* eslint-disable no-console */
import classNames from "classnames";
import { FetchError } from "ofetch";
import { ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -174,12 +175,32 @@ export async function testdebridToken(
console.log("RD response did not indicate premium status");
attempts += 1;
if (attempts === maxAttempts) {
if (attempts === maxAttempts || data?.error_code === 8) {
return "invalid_token";
}
await sleep(3000);
} catch (error) {
console.error("RD API error:", error);
// Check if it's a FetchError with error_code 8 (bad_token)
if (error instanceof FetchError) {
try {
const errorData = error.data;
if (errorData?.error_code === 8) {
console.log("RD token is invalid (error_code 8)");
return "invalid_token";
}
} catch (parseError) {
console.error("Failed to parse RD error response:", parseError);
}
// For other HTTP errors (like 500, 502, etc.), treat as API down
if (error.statusCode && error.statusCode >= 500) {
console.log(`RD API down (status ${error.statusCode})`);
return "api_down";
}
}
attempts += 1;
if (attempts === maxAttempts) {
return "api_down";
@ -206,6 +227,7 @@ function useIsSetup() {
const proxyUrls = useAuthStore((s) => s.proxySet);
const febboxKey = usePreferencesStore((s) => s.febboxKey);
const debridToken = usePreferencesStore((s) => s.debridToken);
const debridService = usePreferencesStore((s) => s.debridService);
const { loading, value } = useAsync(async (): Promise<SetupData> => {
const extensionStatus: Status = (await isExtensionActive())
? "success"
@ -221,7 +243,10 @@ function useIsSetup() {
}
const febboxKeyStatus: Status = await testFebboxKey(febboxKey);
const debridTokenStatus: Status = await testdebridToken(debridToken);
const debridTokenStatus: Status =
debridService === "torbox"
? await testTorboxToken(debridToken)
: await testdebridToken(debridToken);
return {
extension: extensionStatus,
@ -232,7 +257,7 @@ function useIsSetup() {
}),
debridTokenTest: debridTokenStatus,
};
}, [proxyUrls, febboxKey, debridToken]);
}, [proxyUrls, febboxKey, debridToken, debridService]);
let globalState: Status = "unset";
if (