mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
add realdebrid setup
This commit is contained in:
parent
29c412707c
commit
715c26e6ab
9 changed files with 378 additions and 8 deletions
|
|
@ -977,6 +977,16 @@
|
|||
"invalid_token": "Failed to fetch a 'VIP' stream. Your token is invalid!"
|
||||
}
|
||||
},
|
||||
"realdebrid": {
|
||||
"title": "Real Debrid (Beta)",
|
||||
"description": "Enter your Real Debrid API key to access Real Debrid. Extension required.",
|
||||
"tokenLabel": "API Key",
|
||||
"status": {
|
||||
"failure": "Failed to connect to Real Debrid. Please check your API key.",
|
||||
"api_down": "Real Debrid API is currently unavailable. Please try again later.",
|
||||
"invalid_token": "Invalid API key or non-premium account. Real Debrid requires a premium account."
|
||||
}
|
||||
},
|
||||
"watchParty": {
|
||||
"status": {
|
||||
"inSync": "In sync",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export interface SettingsInput {
|
|||
defaultSubtitleLanguage?: string;
|
||||
proxyUrls?: string[] | null;
|
||||
febboxKey?: string | null;
|
||||
realDebridKey?: string | null;
|
||||
enableThumbnails?: boolean;
|
||||
enableAutoplay?: boolean;
|
||||
enableSkipCredits?: boolean;
|
||||
|
|
@ -28,6 +29,7 @@ export interface SettingsResponse {
|
|||
defaultSubtitleLanguage?: string | null;
|
||||
proxyUrls?: string[] | null;
|
||||
febboxKey?: string | null;
|
||||
realDebridKey?: string | null;
|
||||
enableThumbnails?: boolean;
|
||||
enableAutoplay?: boolean;
|
||||
enableSkipCredits?: boolean;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export function useSettingsState(
|
|||
proxyUrls: string[] | null,
|
||||
backendUrl: string | null,
|
||||
febboxKey: string | null,
|
||||
realDebridKey: string | null,
|
||||
profile:
|
||||
| {
|
||||
colorA: string;
|
||||
|
|
@ -69,6 +70,12 @@ export function useSettingsState(
|
|||
useDerived(backendUrl);
|
||||
const [febboxKeyState, setFebboxKey, resetFebboxKey, febboxKeyChanged] =
|
||||
useDerived(febboxKey);
|
||||
const [
|
||||
realDebridKeyState,
|
||||
setRealDebridKey,
|
||||
resetRealDebridKey,
|
||||
realDebridKeyChanged,
|
||||
] = useDerived(realDebridKey);
|
||||
const [themeState, setTheme, resetTheme, themeChanged] = useDerived(theme);
|
||||
const setPreviewTheme = usePreviewThemeStore((s) => s.setPreviewTheme);
|
||||
const resetPreviewTheme = useCallback(
|
||||
|
|
@ -162,6 +169,7 @@ export function useSettingsState(
|
|||
resetProxyUrls();
|
||||
resetBackendUrl();
|
||||
resetFebboxKey();
|
||||
resetRealDebridKey();
|
||||
resetDeviceName();
|
||||
resetProfile();
|
||||
resetEnableThumbnails();
|
||||
|
|
@ -185,6 +193,7 @@ export function useSettingsState(
|
|||
backendUrlChanged ||
|
||||
proxyUrlsChanged ||
|
||||
febboxKeyChanged ||
|
||||
realDebridKeyChanged ||
|
||||
profileChanged ||
|
||||
enableThumbnailsChanged ||
|
||||
enableAutoplayChanged ||
|
||||
|
|
@ -236,6 +245,11 @@ export function useSettingsState(
|
|||
set: setFebboxKey,
|
||||
changed: febboxKeyChanged,
|
||||
},
|
||||
realDebridKey: {
|
||||
state: realDebridKeyState,
|
||||
set: setRealDebridKey,
|
||||
changed: realDebridKeyChanged,
|
||||
},
|
||||
profile: {
|
||||
state: profileState,
|
||||
set: setProfileState,
|
||||
|
|
|
|||
|
|
@ -134,6 +134,9 @@ export function SettingsPage() {
|
|||
const febboxKey = usePreferencesStore((s) => s.febboxKey);
|
||||
const setFebboxKey = usePreferencesStore((s) => s.setFebboxKey);
|
||||
|
||||
const realDebridKey = usePreferencesStore((s) => s.realDebridKey);
|
||||
const setRealDebridKey = usePreferencesStore((s) => s.setRealDebridKey);
|
||||
|
||||
const enableThumbnails = usePreferencesStore((s) => s.enableThumbnails);
|
||||
const setEnableThumbnails = usePreferencesStore((s) => s.setEnableThumbnails);
|
||||
|
||||
|
|
@ -195,10 +198,13 @@ export function SettingsPage() {
|
|||
if (settings.febboxKey) {
|
||||
setFebboxKey(settings.febboxKey);
|
||||
}
|
||||
if (settings.realDebridKey) {
|
||||
setRealDebridKey(settings.realDebridKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
loadSettings();
|
||||
}, [account, backendUrl, setFebboxKey]);
|
||||
}, [account, backendUrl, setFebboxKey, setRealDebridKey]);
|
||||
|
||||
const state = useSettingsState(
|
||||
activeTheme,
|
||||
|
|
@ -208,6 +214,7 @@ export function SettingsPage() {
|
|||
proxySet,
|
||||
backendUrlSetting,
|
||||
febboxKey,
|
||||
realDebridKey,
|
||||
account ? account.profile : undefined,
|
||||
enableThumbnails,
|
||||
enableAutoplay,
|
||||
|
|
@ -264,6 +271,7 @@ export function SettingsPage() {
|
|||
state.theme.changed ||
|
||||
state.proxyUrls.changed ||
|
||||
state.febboxKey.changed ||
|
||||
state.realDebridKey.changed ||
|
||||
state.enableThumbnails.changed ||
|
||||
state.enableAutoplay.changed ||
|
||||
state.enableSkipCredits.changed ||
|
||||
|
|
@ -281,6 +289,7 @@ export function SettingsPage() {
|
|||
applicationTheme: state.theme.state,
|
||||
proxyUrls: state.proxyUrls.state?.filter((v) => v !== "") ?? null,
|
||||
febboxKey: state.febboxKey.state,
|
||||
realDebridKey: state.realDebridKey.state,
|
||||
enableThumbnails: state.enableThumbnails.state,
|
||||
enableAutoplay: state.enableAutoplay.state,
|
||||
enableSkipCredits: state.enableSkipCredits.state,
|
||||
|
|
@ -325,6 +334,7 @@ export function SettingsPage() {
|
|||
setProxySet(state.proxyUrls.state?.filter((v) => v !== "") ?? null);
|
||||
setEnableSourceOrder(state.enableSourceOrder.state);
|
||||
setFebboxKey(state.febboxKey.state);
|
||||
setRealDebridKey(state.realDebridKey.state);
|
||||
setProxyTmdb(state.proxyTmdb.state);
|
||||
setEnableCarouselView(state.enableCarouselView.state);
|
||||
|
||||
|
|
@ -348,6 +358,7 @@ export function SettingsPage() {
|
|||
backendUrl,
|
||||
setEnableThumbnails,
|
||||
setFebboxKey,
|
||||
setRealDebridKey,
|
||||
state,
|
||||
setEnableAutoplay,
|
||||
setEnableSkipCredits,
|
||||
|
|
@ -448,6 +459,8 @@ export function SettingsPage() {
|
|||
setProxyUrls={state.proxyUrls.set}
|
||||
febboxKey={state.febboxKey.state}
|
||||
setFebboxKey={state.febboxKey.set}
|
||||
realDebridKey={state.realDebridKey.state}
|
||||
setRealDebridKey={state.realDebridKey.set}
|
||||
proxyTmdb={state.proxyTmdb.state}
|
||||
setProxyTmdb={state.proxyTmdb.set}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -41,11 +41,14 @@ import {
|
|||
} from "@/pages/onboarding/utils";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
import { conf } from "@/setup/config";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
import { getProxyUrls } from "@/utils/proxyUrls";
|
||||
|
||||
import { Status, testFebboxKey } from "../parts/settings/SetupPart";
|
||||
import {
|
||||
Status,
|
||||
testFebboxKey,
|
||||
testRealDebridKey,
|
||||
} from "../parts/settings/SetupPart";
|
||||
|
||||
async function getFebboxKeyStatus(febboxKey: string | null) {
|
||||
if (febboxKey) {
|
||||
|
|
@ -218,12 +221,130 @@ export function FEDAPISetup() {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function getRealDebridKeyStatus(realDebridKey: string | null) {
|
||||
if (realDebridKey) {
|
||||
const status: Status = await testRealDebridKey(realDebridKey);
|
||||
return status;
|
||||
}
|
||||
return "unset";
|
||||
}
|
||||
|
||||
export function RealDebridSetup() {
|
||||
const { t } = useTranslation();
|
||||
const realDebridKey = usePreferencesStore((s) => s.realDebridKey);
|
||||
const setRealDebridKey = usePreferencesStore((s) => s.setRealDebridKey);
|
||||
|
||||
// Initialize isExpanded based on whether realDebridKey has a value
|
||||
const [isExpanded, setIsExpanded] = useState(
|
||||
realDebridKey !== null && realDebridKey !== "",
|
||||
);
|
||||
|
||||
// Add a separate effect to set the initial state
|
||||
useEffect(() => {
|
||||
// If we have a valid key, make sure the section is expanded
|
||||
if (realDebridKey && realDebridKey.length > 0) {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
}, [realDebridKey]);
|
||||
|
||||
const [status, setStatus] = useState<Status>("unset");
|
||||
const statusMap: Record<Status, StatusCircleProps["type"]> = {
|
||||
error: "error",
|
||||
success: "success",
|
||||
unset: "noresult",
|
||||
api_down: "error",
|
||||
invalid_token: "error",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const checkTokenStatus = async () => {
|
||||
const result = await getRealDebridKeyStatus(realDebridKey);
|
||||
setStatus(result);
|
||||
};
|
||||
checkTokenStatus();
|
||||
}, [realDebridKey]);
|
||||
|
||||
// Toggle handler that preserves the key
|
||||
const toggleExpanded = () => {
|
||||
if (isExpanded) {
|
||||
// Store the key temporarily instead of setting to null
|
||||
setRealDebridKey("");
|
||||
setIsExpanded(false);
|
||||
} else {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
};
|
||||
|
||||
if (conf().ALLOW_REAL_DEBRID_KEY) {
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<SettingsCard>
|
||||
<div className="flex justify-between items-center gap-4">
|
||||
<div className="my-3">
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.connections.realdebrid.title", "Real Debrid API")}
|
||||
</p>
|
||||
<p className="max-w-[30rem] font-medium">
|
||||
{t(
|
||||
"settings.connections.realdebrid.description",
|
||||
"Enter your Real Debrid API key to access premium sources.",
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle onClick={toggleExpanded} enabled={isExpanded} />
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded ? (
|
||||
<>
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.connections.realdebrid.tokenLabel", "API Key")}
|
||||
</p>
|
||||
<div className="flex items-center w-full">
|
||||
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
|
||||
<AuthInputBox
|
||||
onChange={(newToken) => {
|
||||
setRealDebridKey(newToken);
|
||||
}}
|
||||
value={realDebridKey ?? ""}
|
||||
placeholder="API Key"
|
||||
passwordToggleable
|
||||
className="flex-grow"
|
||||
/>
|
||||
</div>
|
||||
{status === "error" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t(
|
||||
"settings.connections.realdebrid.status.failure",
|
||||
"Failed to connect to Real Debrid. Please check your API key.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{status === "api_down" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t(
|
||||
"settings.connections.realdebrid.status.api_down",
|
||||
"Real Debrid API is currently unavailable. Please try again later.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{status === "invalid_token" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t(
|
||||
"settings.connections.realdebrid.status.invalid_token",
|
||||
"Invalid API key or non-premium account. Real Debrid requires a premium account.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</SettingsCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function Item(props: { title: string; children: React.ReactNode }) {
|
||||
|
|
@ -474,6 +595,7 @@ export function OnboardingPage() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* <RealDebridSetup /> */}
|
||||
<FEDAPISetup />
|
||||
</BiggerCenterContainer>
|
||||
</MinimalPageLayout>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
} from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
import { isExtensionActive } from "@/backend/extension/messaging";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
|
|
@ -23,6 +24,7 @@ import {
|
|||
SetupPart,
|
||||
Status,
|
||||
testFebboxKey,
|
||||
testRealDebridKey,
|
||||
} from "@/pages/parts/settings/SetupPart";
|
||||
import { conf } from "@/setup/config";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
|
@ -45,6 +47,11 @@ interface FebboxKeyProps {
|
|||
setFebboxKey: Dispatch<SetStateAction<string | null>>;
|
||||
}
|
||||
|
||||
interface RealDebridKeyProps {
|
||||
realDebridKey: string | null;
|
||||
setRealDebridKey: Dispatch<SetStateAction<string | null>>;
|
||||
}
|
||||
|
||||
function ProxyEdit({
|
||||
proxyUrls,
|
||||
setProxyUrls,
|
||||
|
|
@ -368,8 +375,134 @@ function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
|
|||
}
|
||||
}
|
||||
|
||||
async function getRealDebridKeyStatus(realDebridKey: string | null) {
|
||||
if (realDebridKey) {
|
||||
const status: Status = await testRealDebridKey(realDebridKey);
|
||||
return status;
|
||||
}
|
||||
return "unset";
|
||||
}
|
||||
|
||||
function RealDebridKeyEdit({
|
||||
realDebridKey,
|
||||
setRealDebridKey,
|
||||
}: RealDebridKeyProps) {
|
||||
const { t } = useTranslation();
|
||||
const user = useAuthStore();
|
||||
const preferences = usePreferencesStore();
|
||||
const [hasExtension, setHasExtension] = useState(false);
|
||||
|
||||
// Check for extension
|
||||
useEffect(() => {
|
||||
isExtensionActive().then(setHasExtension);
|
||||
}, []);
|
||||
|
||||
// Enable Real Debrid token when account is loaded and we have a token
|
||||
useEffect(() => {
|
||||
if (user.account && realDebridKey === null && preferences.realDebridKey) {
|
||||
setRealDebridKey(preferences.realDebridKey);
|
||||
}
|
||||
}, [
|
||||
user.account,
|
||||
realDebridKey,
|
||||
preferences.realDebridKey,
|
||||
setRealDebridKey,
|
||||
]);
|
||||
|
||||
const [status, setStatus] = useState<Status>("unset");
|
||||
const statusMap: Record<Status, StatusCircleProps["type"]> = {
|
||||
error: "error",
|
||||
success: "success",
|
||||
unset: "noresult",
|
||||
api_down: "error",
|
||||
invalid_token: "error",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const checkTokenStatus = async () => {
|
||||
const result = await getRealDebridKeyStatus(realDebridKey);
|
||||
setStatus(result);
|
||||
};
|
||||
checkTokenStatus();
|
||||
}, [realDebridKey]);
|
||||
|
||||
if (conf().ALLOW_REAL_DEBRID_KEY) {
|
||||
return (
|
||||
<SettingsCard>
|
||||
<div className="flex justify-between items-center gap-4">
|
||||
<div className="my-3">
|
||||
<p className="text-white font-bold mb-3">{t("realdebrid.title")}</p>
|
||||
<p className="max-w-[30rem] font-medium">
|
||||
{t("realdebrid.description")}
|
||||
</p>
|
||||
<MwLink>
|
||||
<a
|
||||
href="https://real-debrid.com/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
real-debrid.com
|
||||
</a>
|
||||
</MwLink>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
{!hasExtension && <Icon icon={Icons.UNPLUG} className="text-lg" />}
|
||||
<Toggle
|
||||
onClick={() =>
|
||||
hasExtension
|
||||
? setRealDebridKey((s) => (s === null ? "" : null))
|
||||
: null
|
||||
}
|
||||
enabled={realDebridKey !== null && hasExtension}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{realDebridKey !== null && hasExtension ? (
|
||||
<>
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("realdebrid.tokenLabel")}
|
||||
</p>
|
||||
<div className="flex items-center w-full">
|
||||
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
|
||||
<AuthInputBox
|
||||
onChange={(newToken) => {
|
||||
setRealDebridKey(newToken);
|
||||
}}
|
||||
value={realDebridKey ?? ""}
|
||||
placeholder="ABC123..."
|
||||
passwordToggleable
|
||||
className="flex-grow"
|
||||
/>
|
||||
</div>
|
||||
{status === "error" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t("realdebrid.status.failure")}
|
||||
</p>
|
||||
)}
|
||||
{status === "api_down" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t("realdebrid.status.api_down")}
|
||||
</p>
|
||||
)}
|
||||
{status === "invalid_token" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t("realdebrid.status.invalid_token")}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</SettingsCard>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function ConnectionsPart(
|
||||
props: BackendEditProps & ProxyEditProps & FebboxKeyProps,
|
||||
props: BackendEditProps &
|
||||
ProxyEditProps &
|
||||
FebboxKeyProps &
|
||||
RealDebridKeyProps,
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
|
|
@ -387,6 +520,10 @@ export function ConnectionsPart(
|
|||
backendUrl={props.backendUrl}
|
||||
setBackendUrl={props.setBackendUrl}
|
||||
/>
|
||||
<RealDebridKeyEdit
|
||||
realDebridKey={props.realDebridKey}
|
||||
setRealDebridKey={props.setRealDebridKey}
|
||||
/>
|
||||
<FebboxKeyEdit
|
||||
febboxKey={props.febboxKey}
|
||||
setFebboxKey={props.setFebboxKey}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useNavigate } from "react-router-dom";
|
|||
import { useAsync } from "react-use";
|
||||
|
||||
import { isExtensionActive } from "@/backend/extension/messaging";
|
||||
import { singularProxiedFetch } from "@/backend/helpers/fetch";
|
||||
import { proxiedFetch, singularProxiedFetch } from "@/backend/helpers/fetch";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Loading } from "@/components/layout/Loading";
|
||||
|
|
@ -74,6 +74,7 @@ type SetupData = {
|
|||
proxy: Status;
|
||||
defaultProxy: Status;
|
||||
febboxKeyTest?: Status;
|
||||
realDebridKeyTest?: Status;
|
||||
};
|
||||
|
||||
function testProxy(url: string) {
|
||||
|
|
@ -174,9 +175,59 @@ export async function testFebboxKey(febboxKey: string | null): Promise<Status> {
|
|||
return "api_down";
|
||||
}
|
||||
|
||||
export async function testRealDebridKey(
|
||||
realDebridKey: string | null,
|
||||
): Promise<Status> {
|
||||
if (!realDebridKey) {
|
||||
return "unset";
|
||||
}
|
||||
|
||||
const maxAttempts = 2;
|
||||
let attempts = 0;
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
try {
|
||||
console.log(`RD API attempt ${attempts + 1}`);
|
||||
const data = await proxiedFetch(
|
||||
"https://api.real-debrid.com/rest/1.0/user",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${realDebridKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// If we have data and it indicates premium status, return success immediately
|
||||
if (data && typeof data === "object" && data.type === "premium") {
|
||||
console.log("RD premium status confirmed");
|
||||
return "success";
|
||||
}
|
||||
|
||||
console.log("RD response did not indicate premium status");
|
||||
attempts += 1;
|
||||
if (attempts === maxAttempts) {
|
||||
return "invalid_token";
|
||||
}
|
||||
await sleep(3000);
|
||||
} catch (error) {
|
||||
console.error("RD API error:", error);
|
||||
attempts += 1;
|
||||
if (attempts === maxAttempts) {
|
||||
return "api_down";
|
||||
}
|
||||
await sleep(3000);
|
||||
}
|
||||
}
|
||||
|
||||
return "api_down";
|
||||
}
|
||||
|
||||
function useIsSetup() {
|
||||
const proxyUrls = useAuthStore((s) => s.proxySet);
|
||||
const febboxKey = usePreferencesStore((s) => s.febboxKey);
|
||||
const realDebridKey = usePreferencesStore((s) => s.realDebridKey);
|
||||
const { loading, value } = useAsync(async (): Promise<SetupData> => {
|
||||
const extensionStatus: Status = (await isExtensionActive())
|
||||
? "success"
|
||||
|
|
@ -192,6 +243,7 @@ function useIsSetup() {
|
|||
}
|
||||
|
||||
const febboxKeyStatus: Status = await testFebboxKey(febboxKey);
|
||||
const realDebridKeyStatus: Status = await testRealDebridKey(realDebridKey);
|
||||
|
||||
return {
|
||||
extension: extensionStatus,
|
||||
|
|
@ -200,20 +252,23 @@ function useIsSetup() {
|
|||
...(conf().ALLOW_FEBBOX_KEY && {
|
||||
febboxKeyTest: febboxKeyStatus,
|
||||
}),
|
||||
realDebridKeyTest: realDebridKeyStatus,
|
||||
};
|
||||
}, [proxyUrls, febboxKey]);
|
||||
}, [proxyUrls, febboxKey, realDebridKey]);
|
||||
|
||||
let globalState: Status = "unset";
|
||||
if (
|
||||
value?.extension === "success" ||
|
||||
value?.proxy === "success" ||
|
||||
value?.febboxKeyTest === "success"
|
||||
value?.febboxKeyTest === "success" ||
|
||||
value?.realDebridKeyTest === "success"
|
||||
)
|
||||
globalState = "success";
|
||||
if (
|
||||
value?.proxy === "error" ||
|
||||
value?.extension === "error" ||
|
||||
value?.febboxKeyTest === "error"
|
||||
value?.febboxKeyTest === "error" ||
|
||||
value?.realDebridKeyTest === "error"
|
||||
)
|
||||
globalState = "error";
|
||||
|
||||
|
|
@ -354,6 +409,11 @@ export function SetupPart() {
|
|||
>
|
||||
{t("settings.connections.setup.items.default")}
|
||||
</SetupCheckList>
|
||||
{conf().ALLOW_REAL_DEBRID_KEY && (
|
||||
<SetupCheckList status={setupStates.realDebridKeyTest || "unset"}>
|
||||
Real Debrid token
|
||||
</SetupCheckList>
|
||||
)}
|
||||
{conf().ALLOW_FEBBOX_KEY && (
|
||||
<SetupCheckList status={setupStates.febboxKeyTest || "unset"}>
|
||||
Febbox UI token
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ interface Config {
|
|||
ONBOARDING_PROXY_INSTALL_LINK: string;
|
||||
ALLOW_AUTOPLAY: boolean;
|
||||
ALLOW_FEBBOX_KEY: boolean;
|
||||
ALLOW_REAL_DEBRID_KEY: boolean;
|
||||
SHOW_AD: boolean;
|
||||
AD_CONTENT_URL: string;
|
||||
TRACK_SCRIPT: string;
|
||||
|
|
@ -38,6 +39,7 @@ export interface RuntimeConfig {
|
|||
DMCA_EMAIL: string | null;
|
||||
TWITTER_LINK: string;
|
||||
TMDB_READ_API_KEY: string | null;
|
||||
ALLOW_REAL_DEBRID_KEY: boolean;
|
||||
NORMAL_ROUTER: boolean;
|
||||
PROXY_URLS: string[];
|
||||
M3U8_PROXY_URLS: string[];
|
||||
|
|
@ -79,6 +81,7 @@ const env: Record<keyof Config, undefined | string> = {
|
|||
HAS_ONBOARDING: import.meta.env.VITE_HAS_ONBOARDING,
|
||||
ALLOW_AUTOPLAY: import.meta.env.VITE_ALLOW_AUTOPLAY,
|
||||
ALLOW_FEBBOX_KEY: import.meta.env.VITE_ALLOW_FEBBOX_KEY,
|
||||
ALLOW_REAL_DEBRID_KEY: import.meta.env.VITE_ALLOW_REAL_DEBRID_KEY,
|
||||
SHOW_AD: import.meta.env.VITE_SHOW_AD,
|
||||
AD_CONTENT_URL: import.meta.env.VITE_AD_CONTENT_URL,
|
||||
TRACK_SCRIPT: import.meta.env.VITE_TRACK_SCRIPT,
|
||||
|
|
@ -147,6 +150,7 @@ export function conf(): RuntimeConfig {
|
|||
)
|
||||
.filter((v) => v.length === 2), // The format is <beforeA>:<afterA>,<beforeB>:<afterB>
|
||||
ALLOW_FEBBOX_KEY: getKey("ALLOW_FEBBOX_KEY", "false") === "true",
|
||||
ALLOW_REAL_DEBRID_KEY: getKey("ALLOW_REAL_DEBRID_KEY", "false") === "true",
|
||||
SHOW_AD: getKey("SHOW_AD", "false") === "true",
|
||||
AD_CONTENT_URL: getKey("AD_CONTENT_URL", "")
|
||||
.split(",")
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export interface PreferencesStore {
|
|||
enableSourceOrder: boolean;
|
||||
proxyTmdb: boolean;
|
||||
febboxKey: string | null;
|
||||
realDebridKey: string | null;
|
||||
|
||||
setEnableThumbnails(v: boolean): void;
|
||||
setEnableAutoplay(v: boolean): void;
|
||||
|
|
@ -28,6 +29,7 @@ export interface PreferencesStore {
|
|||
setEnableSourceOrder(v: boolean): void;
|
||||
setProxyTmdb(v: boolean): void;
|
||||
setFebboxKey(v: string | null): void;
|
||||
setRealDebridKey(v: string | null): void;
|
||||
}
|
||||
|
||||
export const usePreferencesStore = create(
|
||||
|
|
@ -45,6 +47,7 @@ export const usePreferencesStore = create(
|
|||
enableSourceOrder: false,
|
||||
proxyTmdb: false,
|
||||
febboxKey: null,
|
||||
realDebridKey: null,
|
||||
setEnableThumbnails(v) {
|
||||
set((s) => {
|
||||
s.enableThumbnails = v;
|
||||
|
|
@ -105,6 +108,11 @@ export const usePreferencesStore = create(
|
|||
s.febboxKey = v;
|
||||
});
|
||||
},
|
||||
setRealDebridKey(v) {
|
||||
set((s) => {
|
||||
s.realDebridKey = v;
|
||||
});
|
||||
},
|
||||
})),
|
||||
{
|
||||
name: "__MW::preferences",
|
||||
|
|
|
|||
Loading…
Reference in a new issue