remove Provider API logic and OLD turnstile code

This commit is contained in:
Pas 2025-12-27 13:07:32 -07:00
parent eb7659caee
commit ecd5daeaa0
14 changed files with 27 additions and 384 deletions

View file

@ -22,7 +22,6 @@ ARG ONBOARDING_CHROME_EXTENSION_INSTALL_LINK
ARG ONBOARDING_PROXY_INSTALL_LINK ARG ONBOARDING_PROXY_INSTALL_LINK
ARG DISALLOWED_IDS ARG DISALLOWED_IDS
ARG CDN_REPLACEMENTS ARG CDN_REPLACEMENTS
ARG TURNSTILE_KEY
ARG ALLOW_AUTOPLAY="false" ARG ALLOW_AUTOPLAY="false"
ENV VITE_PWA_ENABLED=${PWA_ENABLED} ENV VITE_PWA_ENABLED=${PWA_ENABLED}
@ -39,7 +38,6 @@ ENV VITE_ONBOARDING_CHROME_EXTENSION_INSTALL_LINK=${ONBOARDING_CHROME_EXTENSION_
ENV VITE_ONBOARDING_PROXY_INSTALL_LINK=${ONBOARDING_PROXY_INSTALL_LINK} ENV VITE_ONBOARDING_PROXY_INSTALL_LINK=${ONBOARDING_PROXY_INSTALL_LINK}
ENV VITE_DISALLOWED_IDS=${DISALLOWED_IDS} ENV VITE_DISALLOWED_IDS=${DISALLOWED_IDS}
ENV VITE_CDN_REPLACEMENTS=${CDN_REPLACEMENTS} ENV VITE_CDN_REPLACEMENTS=${CDN_REPLACEMENTS}
ENV VITE_TURNSTILE_KEY=${TURNSTILE_KEY}
ENV VITE_ALLOW_AUTOPLAY=${ALLOW_AUTOPLAY} ENV VITE_ALLOW_AUTOPLAY=${ALLOW_AUTOPLAY}
COPY . ./ COPY . ./

View file

@ -19,7 +19,6 @@ services:
# ONBOARDING_PROXY_INSTALL_LINK: "" # ONBOARDING_PROXY_INSTALL_LINK: ""
# DISALLOWED_IDS: "" # DISALLOWED_IDS: ""
# CDN_REPLACEMENTS: "" # CDN_REPLACEMENTS: ""
# TURNSTILE_KEY: ""
ports: ports:
- "80:80" - "80:80"
restart: unless-stopped restart: unless-stopped

View file

@ -947,12 +947,6 @@
"remaining": "{{timeLeft}} left • Finish at {{timeFinished, datetime}}", "remaining": "{{timeLeft}} left • Finish at {{timeFinished, datetime}}",
"shortRegular": "{{timeWatched}}", "shortRegular": "{{timeWatched}}",
"shortRemaining": "-{{timeLeft}}" "shortRemaining": "-{{timeLeft}}"
},
"turnstile": {
"description": "Please prove your humanity by completing the quick challenge, this is to keep P-Stream safe.",
"error": "Failed to verify your humanity - stream failed to load. Clear your cache and try again, or switch to a different source (tap the gear).",
"title": "Are You a Robot 🤖?",
"verifyingHumanity": "Verifying your humanity... (^▽^)👍"
} }
}, },
"support": { "support": {

View file

@ -1,9 +1,6 @@
import { MetaOutput, NotFoundError, ScrapeMedia } from "@p-stream/providers"; import { MetaOutput } from "@p-stream/providers";
import { jwtDecode } from "jwt-decode"; import { jwtDecode } from "jwt-decode";
import { mwFetch } from "@/backend/helpers/fetch";
import { getTurnstileToken, isTurnstileInitialized } from "@/stores/turnstile";
let metaDataCache: MetaOutput[] | null = null; let metaDataCache: MetaOutput[] | null = null;
let token: null | string = null; let token: null | string = null;
@ -31,143 +28,6 @@ function getTokenIfValid(): null | string {
return null; return null;
} }
export async function fetchMetadata(base: string) {
if (metaDataCache) return;
const data = await mwFetch<MetaOutput[][]>(`${base}/metadata`);
metaDataCache = data.flat();
}
function scrapeMediaToQueryMedia(media: ScrapeMedia) {
let extra: Record<string, string> = {};
if (media.type === "show") {
extra = {
episodeNumber: media.episode.number.toString(),
episodeTmdbId: media.episode.tmdbId,
seasonNumber: media.season.number.toString(),
seasonTmdbId: media.season.tmdbId,
};
}
return {
type: media.type,
releaseYear: media.releaseYear.toString(),
imdbId: media.imdbId,
tmdbId: media.tmdbId,
title: media.title,
...extra,
};
}
function addQueryDataToUrl(url: URL, data: Record<string, string | undefined>) {
Object.entries(data).forEach((entry) => {
if (entry[1]) url.searchParams.set(entry[0], entry[1]);
});
}
export function makeProviderUrl(base: string) {
const makeUrl = (p: string) => new URL(`${base}${p}`);
return {
scrapeSource(sourceId: string, media: ScrapeMedia) {
const url = makeUrl("/scrape/source");
addQueryDataToUrl(url, scrapeMediaToQueryMedia(media));
addQueryDataToUrl(url, { id: sourceId });
return url.toString();
},
scrapeAll(
media: ScrapeMedia,
sourceOrder?: string[],
embedOrder?: string[],
) {
const url = makeUrl("/scrape");
addQueryDataToUrl(url, scrapeMediaToQueryMedia(media));
if (sourceOrder && sourceOrder.length > 0) {
url.searchParams.set("sourceOrder", sourceOrder.join(","));
}
if (embedOrder && embedOrder.length > 0) {
url.searchParams.set("embedOrder", embedOrder.join(","));
}
return url.toString();
},
scrapeEmbed(embedId: string, embedUrl: string) {
const url = makeUrl("/scrape/embed");
addQueryDataToUrl(url, { id: embedId, url: embedUrl });
return url.toString();
},
};
}
export async function getApiToken(): Promise<string | null> { export async function getApiToken(): Promise<string | null> {
let apiToken = getTokenIfValid(); return getTokenIfValid();
if (!apiToken && isTurnstileInitialized()) {
apiToken = `turnstile|${await getTurnstileToken()}`;
}
return apiToken;
}
function parseEventInput(inp: string): any {
if (inp.length === 0) return {};
return JSON.parse(inp);
}
export async function connectServerSideEvents<T>(
url: string,
endEvents: string[],
) {
const apiToken = await getApiToken();
// insert token, if its set
const parsedUrl = new URL(url);
if (apiToken) parsedUrl.searchParams.set("token", apiToken);
const eventSource = new EventSource(parsedUrl.toString());
let promReject: (reason?: any) => void;
let promResolve: (value: T) => void;
const promise = new Promise<T>((resolve, reject) => {
promResolve = resolve;
promReject = reject;
});
endEvents.forEach((evt) => {
eventSource.addEventListener(evt, (e) => {
eventSource.close();
promResolve(parseEventInput(e.data));
});
});
eventSource.addEventListener("token", (e) => {
setApiToken(parseEventInput(e.data));
});
eventSource.addEventListener("error", (err: MessageEvent<any>) => {
eventSource.close();
if (err.data) {
const data = JSON.parse(err.data);
let errObj = new Error("scrape error");
if (data.name === NotFoundError.name)
errObj = new NotFoundError("Notfound from server");
Object.assign(errObj, data);
promReject(errObj);
return;
}
console.error("Failed to connect to SSE", err);
promReject(err);
});
eventSource.addEventListener("message", (ev) => {
if (!ev) {
eventSource.close();
return;
}
setTimeout(() => {
promReject(new Error("SSE closed improperly"));
}, 1000);
});
return {
promise: () => promise,
on<Data>(event: string, cb: (data: Data) => void) {
eventSource.addEventListener(event, (e) => cb(JSON.parse(e.data)));
},
};
} }

View file

@ -6,11 +6,7 @@ import {
import { sendExtensionRequest } from "@/backend/extension/messaging"; import { sendExtensionRequest } from "@/backend/extension/messaging";
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi"; import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
import { import { getM3U8ProxyUrls, getProxyUrls } from "@/utils/proxyUrls";
getM3U8ProxyUrls,
getProviderApiUrls,
getProxyUrls,
} from "@/utils/proxyUrls";
import { convertBodyToObject, getBodyTypeFromBody } from "../extension/request"; import { convertBodyToObject, getBodyTypeFromBody } from "../extension/request";
@ -28,8 +24,6 @@ function makeLoadbalancedList(getter: () => string[]) {
} }
export const getLoadbalancedProxyUrl = makeLoadbalancedList(getProxyUrls); export const getLoadbalancedProxyUrl = makeLoadbalancedList(getProxyUrls);
export const getLoadbalancedProviderApiUrl =
makeLoadbalancedList(getProviderApiUrls);
function getEnabledM3U8ProxyUrls() { function getEnabledM3U8ProxyUrls() {
const allM3U8ProxyUrls = getM3U8ProxyUrls(); const allM3U8ProxyUrls = getM3U8ProxyUrls();
const enabledProxies = localStorage.getItem("m3u8-proxy-enabled"); const enabledProxies = localStorage.getItem("m3u8-proxy-enabled");

View file

@ -2,14 +2,12 @@ import classNames from "classnames";
import FocusTrap from "focus-trap-react"; import FocusTrap from "focus-trap-react";
import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; import { ReactNode, useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { Transition } from "@/components/utils/Transition"; import { Transition } from "@/components/utils/Transition";
import { import {
useInternalOverlayRouter, useInternalOverlayRouter,
useRouterAnchorUpdate, useRouterAnchorUpdate,
} from "@/hooks/useOverlayRouter"; } from "@/hooks/useOverlayRouter";
import { TurnstileProvider, getTurnstile } from "@/stores/turnstile";
export interface OverlayProps { export interface OverlayProps {
id: string; id: string;
@ -17,40 +15,6 @@ export interface OverlayProps {
darken?: boolean; darken?: boolean;
} }
function TurnstileInteractive() {
const { t } = useTranslation();
const [show, setShow] = useState(false);
useEffect(() => {
getTurnstile();
}, []);
// this may not rerender with different dom structure, must be exactly the same always
return (
<div
className={classNames(
"absolute w-full max-w-[43em] max-h-full p-5 md:p-10 rounded-lg bg-dropdown-altBackground select-none z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform overflow-auto",
show ? "" : "hidden",
)}
>
<div className="w-full h-full grid lg:grid-cols-[1fr,auto] gap-6 md:gap-7 items-center">
<div className="text-left">
<h2 className="text-type-emphasis font-bold text-lg md:text-xl mb-4 md:mb-6">
{t("player.turnstile.title")}
</h2>
<p className="text-type-emphasis">
{t("player.turnstile.description")}
</p>
</div>
<TurnstileProvider
isInPopout
onUpdateShow={(shouldShow) => setShow(shouldShow)}
/>
</div>
</div>
);
}
export function OverlayDisplay(props: { children: ReactNode }) { export function OverlayDisplay(props: { children: ReactNode }) {
const router = useInternalOverlayRouter("hello world :)"); const router = useInternalOverlayRouter("hello world :)");
const refRouter = useRef(router); const refRouter = useRef(router);
@ -63,12 +27,7 @@ export function OverlayDisplay(props: { children: ReactNode }) {
r.close(); r.close();
}; };
}, []); }, []);
return ( return <div className="popout-location">{props.children}</div>;
<div className="popout-location">
<TurnstileInteractive />
{props.children}
</div>
);
} }
export function OverlayPortal(props: { export function OverlayPortal(props: {

View file

@ -7,15 +7,10 @@ import { useAsyncFn } from "react-use";
import { isExtensionActiveCached } from "@/backend/extension/messaging"; import { isExtensionActiveCached } from "@/backend/extension/messaging";
import { prepareStream } from "@/backend/extension/streams"; import { prepareStream } from "@/backend/extension/streams";
import {
connectServerSideEvents,
makeProviderUrl,
} from "@/backend/helpers/providerApi";
import { import {
scrapeSourceOutputToProviderMetric, scrapeSourceOutputToProviderMetric,
useReportProviders, useReportProviders,
} from "@/backend/helpers/report"; } from "@/backend/helpers/report";
import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
import { getProviders } from "@/backend/providers/providers"; import { getProviders } from "@/backend/providers/providers";
import { convertProviderCaption } from "@/components/player/utils/captions"; import { convertProviderCaption } from "@/components/player/utils/captions";
import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource"; import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource";
@ -60,23 +55,13 @@ export function useEmbedScraping(
); );
const [request, run] = useAsyncFn(async () => { const [request, run] = useAsyncFn(async () => {
const providerApiUrl = getLoadbalancedProviderApiUrl();
let result: EmbedOutput | undefined; let result: EmbedOutput | undefined;
if (!meta) return; if (!meta) return;
try { try {
if (providerApiUrl && !isExtensionActiveCached()) { result = await getProviders().runEmbedScraper({
const baseUrlMaker = makeProviderUrl(providerApiUrl); id: embedId,
const conn = await connectServerSideEvents<EmbedOutput>( url,
baseUrlMaker.scrapeEmbed(embedId, url), });
["completed", "noOutput"],
);
result = await conn.promise();
} else {
result = await getProviders().runEmbedScraper({
id: embedId,
url,
});
}
} catch (err) { } catch (err) {
console.error(`Failed to scrape ${embedId}`, err); console.error(`Failed to scrape ${embedId}`, err);
const notFound = err instanceof NotFoundError; const notFound = err instanceof NotFoundError;
@ -148,23 +133,13 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
if (!sourceId || !meta) return null; if (!sourceId || !meta) return null;
setEmbedId(null); setEmbedId(null);
const scrapeMedia = metaToScrapeMedia(meta); const scrapeMedia = metaToScrapeMedia(meta);
const providerApiUrl = getLoadbalancedProviderApiUrl();
let result: SourcererOutput | undefined; let result: SourcererOutput | undefined;
try { try {
if (providerApiUrl && !isExtensionActiveCached()) { result = await getProviders().runSourceScraper({
const baseUrlMaker = makeProviderUrl(providerApiUrl); id: sourceId,
const conn = await connectServerSideEvents<SourcererOutput>( media: scrapeMedia,
baseUrlMaker.scrapeSource(sourceId, scrapeMedia), });
["completed", "noOutput"],
);
result = await conn.promise();
} else {
result = await getProviders().runSourceScraper({
id: sourceId,
media: scrapeMedia,
});
}
} catch (err) { } catch (err) {
console.error(`Failed to scrape ${sourceId}`, err); console.error(`Failed to scrape ${sourceId}`, err);
const notFound = err instanceof NotFoundError; const notFound = err instanceof NotFoundError;
@ -199,22 +174,10 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
let embedResult: EmbedOutput | undefined; let embedResult: EmbedOutput | undefined;
if (!meta) return; if (!meta) return;
try { try {
if (providerApiUrl && !isExtensionActiveCached()) { embedResult = await getProviders().runEmbedScraper({
const baseUrlMaker = makeProviderUrl(providerApiUrl); id: result.embeds[0].embedId,
const conn = await connectServerSideEvents<EmbedOutput>( url: result.embeds[0].url,
baseUrlMaker.scrapeEmbed( });
result.embeds[0].embedId,
result.embeds[0].url,
),
["completed", "noOutput"],
);
embedResult = await conn.promise();
} else {
embedResult = await getProviders().runEmbedScraper({
id: result.embeds[0].embedId,
url: result.embeds[0].url,
});
}
} catch (err) { } catch (err) {
console.error(`Failed to scrape ${result.embeds[0].embedId}`, err); console.error(`Failed to scrape ${result.embeds[0].embedId}`, err);
const notFound = err instanceof NotFoundError; const notFound = err instanceof NotFoundError;

View file

@ -3,12 +3,7 @@ import { RefObject, useCallback, useEffect, useRef, useState } from "react";
import { isExtensionActiveCached } from "@/backend/extension/messaging"; import { isExtensionActiveCached } from "@/backend/extension/messaging";
import { prepareStream } from "@/backend/extension/streams"; import { prepareStream } from "@/backend/extension/streams";
import { import { getCachedMetadata } from "@/backend/helpers/providerApi";
connectServerSideEvents,
getCachedMetadata,
makeProviderUrl,
} from "@/backend/helpers/providerApi";
import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
import { getProviders } from "@/backend/providers/providers"; import { getProviders } from "@/backend/providers/providers";
import { getMediaKey } from "@/stores/player/slices/source"; import { getMediaKey } from "@/stores/player/slices/source";
import { usePlayerStore } from "@/stores/player/store"; import { usePlayerStore } from "@/stores/player/store";
@ -245,29 +240,6 @@ export function useScrape() {
) )
: undefined; : undefined;
const providerApiUrl = getLoadbalancedProviderApiUrl();
if (providerApiUrl && !isExtensionActiveCached()) {
startScrape();
const baseUrlMaker = makeProviderUrl(providerApiUrl);
const conn = await connectServerSideEvents<RunOutput | "">(
baseUrlMaker.scrapeAll(
media,
filteredSourceOrder,
filteredEmbedOrder,
),
["completed", "noOutput"],
);
conn.on("init", initEvent);
conn.on("start", startEvent);
conn.on("update", updateEvent);
conn.on("discoverEmbeds", discoverEmbedsEvent);
const sseOutput = await conn.promise();
if (sseOutput && isExtensionActiveCached())
await prepareStream(sseOutput.stream);
return getResult(sseOutput === "" ? null : sseOutput);
}
startScrape(); startScrape();
const providers = getProviders(); const providers = getProviders();
const output = await providers.runAll({ const output = await providers.runAll({

View file

@ -5,14 +5,10 @@ import type { AsyncReturnType } from "type-fest";
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility"; import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
import { extensionInfo, sendPage } from "@/backend/extension/messaging"; import { extensionInfo, sendPage } from "@/backend/extension/messaging";
import { import { setCachedMetadata } from "@/backend/helpers/providerApi";
fetchMetadata,
setCachedMetadata,
} from "@/backend/helpers/providerApi";
import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta";
import { decodeTMDBId } from "@/backend/metadata/tmdb"; import { decodeTMDBId } from "@/backend/metadata/tmdb";
import { MWMediaType } from "@/backend/metadata/types/mw"; import { MWMediaType } from "@/backend/metadata/types/mw";
import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
import { getProviders } from "@/backend/providers/providers"; import { getProviders } from "@/backend/providers/providers";
import { Button } from "@/components/buttons/Button"; import { Button } from "@/components/buttons/Button";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
@ -52,20 +48,11 @@ export function MetaPart(props: MetaPartProps) {
if (!info.hasPermission) throw new Error("extension-no-permission"); if (!info.hasPermission) throw new Error("extension-no-permission");
} }
// use api metadata or providers metadata // use providers metadata
const providerApiUrl = getLoadbalancedProviderApiUrl(); setCachedMetadata([
if (providerApiUrl && !isValidExtension) { ...getProviders().listSources(),
try { ...getProviders().listEmbeds(),
await fetchMetadata(providerApiUrl); ]);
} catch (err) {
throw new Error("failed-api-metadata");
}
} else {
setCachedMetadata([
...getProviders().listSources(),
...getProviders().listEmbeds(),
]);
}
// get media meta data // get media meta data
let data: ReturnType<typeof decodeTMDBId> = null; let data: ReturnType<typeof decodeTMDBId> = null;
@ -160,28 +147,6 @@ export function MetaPart(props: MetaPartProps) {
); );
} }
if (error && error.message === "failed-api-metadata") {
return (
<ErrorLayout>
<ErrorContainer>
<IconPill icon={Icons.WAND}>
{t("player.metadata.failed.badge")}
</IconPill>
<Title>{t("player.metadata.api.text")}</Title>
<Paragraph>{t("player.metadata.api.title")}</Paragraph>
<Button
href="/"
theme="purple"
padding="md:px-12 p-2.5"
className="mt-6"
>
{t("player.metadata.failed.homeButton")}
</Button>
</ErrorContainer>
</ErrorLayout>
);
}
if (error) { if (error) {
return ( return (
<ErrorLayout> <ErrorLayout>

View file

@ -19,7 +19,6 @@ import { useOnboardingStore } from "@/stores/onboarding";
import { usePreferencesStore } from "@/stores/preferences"; import { usePreferencesStore } from "@/stores/preferences";
import { getExtensionState } from "@/utils/extension"; import { getExtensionState } from "@/utils/extension";
import type { ExtensionStatus } from "@/utils/extension"; import type { ExtensionStatus } from "@/utils/extension";
import { getProviderApiUrls } from "@/utils/proxyUrls";
import { ErrorCardInModal } from "../errors/ErrorCard"; import { ErrorCardInModal } from "../errors/ErrorCard";
@ -42,9 +41,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
const error = useMemo(() => { const error = useMemo(() => {
const data = props.data; const data = props.data;
let str = ""; let str = "";
const apiUrls = getProviderApiUrls(); str += `URL - ${location.pathname}\n\n`;
str += `URL - ${location.pathname}\n`;
str += `API - ${apiUrls.length > 0}\n\n`;
Object.values(data.sources).forEach((v) => { Object.values(data.sources).forEach((v) => {
str += `${v.id}: ${v.status}\n`; str += `${v.id}: ${v.status}\n`;
if (v.reason) str += `${v.reason}\n`; if (v.reason) str += `${v.reason}\n`;

View file

@ -96,7 +96,7 @@ export function ScrapingPart(props: ScrapingProps) {
currentProviderIndex = sourceOrder.length - 1; currentProviderIndex = sourceOrder.length - 1;
if (failedStartScrape) if (failedStartScrape)
return <WarningPart>{t("player.turnstile.error")}</WarningPart>; return <WarningPart>{t("player.scraping.items.failure")}</WarningPart>;
return ( return (
<div <div
@ -106,7 +106,7 @@ export function ScrapingPart(props: ScrapingProps) {
{!sourceOrder || sourceOrder.length === 0 ? ( {!sourceOrder || sourceOrder.length === 0 ? (
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-center flex flex-col justify-center z-0"> <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-center flex flex-col justify-center z-0">
<Loading className="mb-8" /> <Loading className="mb-8" />
<p>{t("player.turnstile.verifyingHumanity")}</p> <p>{t("player.scraping.items.pending")}</p>
</div> </div>
) : null} ) : null}
<div <div

View file

@ -18,7 +18,6 @@ interface Config {
NORMAL_ROUTER: boolean; NORMAL_ROUTER: boolean;
BACKEND_URL: string; BACKEND_URL: string;
DISALLOWED_IDS: string; DISALLOWED_IDS: string;
TURNSTILE_KEY: string;
CDN_REPLACEMENTS: string; CDN_REPLACEMENTS: string;
HAS_ONBOARDING: string; HAS_ONBOARDING: string;
ONBOARDING_CHROME_EXTENSION_INSTALL_LINK: string; ONBOARDING_CHROME_EXTENSION_INSTALL_LINK: string;
@ -51,7 +50,6 @@ export interface RuntimeConfig {
M3U8_PROXY_URLS: string[]; M3U8_PROXY_URLS: string[];
BACKEND_URL: string | null; BACKEND_URL: string | null;
DISALLOWED_IDS: string[]; DISALLOWED_IDS: string[];
TURNSTILE_KEY: string | null;
CDN_REPLACEMENTS: Array<string[]>; CDN_REPLACEMENTS: Array<string[]>;
HAS_ONBOARDING: boolean; HAS_ONBOARDING: boolean;
ALLOW_AUTOPLAY: boolean; ALLOW_AUTOPLAY: boolean;
@ -88,7 +86,6 @@ const env: Record<keyof Config, undefined | string> = {
NORMAL_ROUTER: import.meta.env.VITE_NORMAL_ROUTER, NORMAL_ROUTER: import.meta.env.VITE_NORMAL_ROUTER,
BACKEND_URL: import.meta.env.VITE_BACKEND_URL, BACKEND_URL: import.meta.env.VITE_BACKEND_URL,
DISALLOWED_IDS: import.meta.env.VITE_DISALLOWED_IDS, DISALLOWED_IDS: import.meta.env.VITE_DISALLOWED_IDS,
TURNSTILE_KEY: import.meta.env.VITE_TURNSTILE_KEY,
CDN_REPLACEMENTS: import.meta.env.VITE_CDN_REPLACEMENTS, CDN_REPLACEMENTS: import.meta.env.VITE_CDN_REPLACEMENTS,
HAS_ONBOARDING: import.meta.env.VITE_HAS_ONBOARDING, HAS_ONBOARDING: import.meta.env.VITE_HAS_ONBOARDING,
ALLOW_AUTOPLAY: import.meta.env.VITE_ALLOW_AUTOPLAY, ALLOW_AUTOPLAY: import.meta.env.VITE_ALLOW_AUTOPLAY,
@ -153,7 +150,6 @@ export function conf(): RuntimeConfig {
NORMAL_ROUTER: getKey("NORMAL_ROUTER", "false") === "true", NORMAL_ROUTER: getKey("NORMAL_ROUTER", "false") === "true",
HAS_ONBOARDING: getKey("HAS_ONBOARDING", "false") === "true", HAS_ONBOARDING: getKey("HAS_ONBOARDING", "false") === "true",
ALLOW_AUTOPLAY: getKey("ALLOW_AUTOPLAY", "false") === "true", ALLOW_AUTOPLAY: getKey("ALLOW_AUTOPLAY", "false") === "true",
TURNSTILE_KEY: getKey("TURNSTILE_KEY"),
DISALLOWED_IDS: getKey("DISALLOWED_IDS", "") DISALLOWED_IDS: getKey("DISALLOWED_IDS", "")
.split(",") .split(",")
.map((v) => v.trim()) .map((v) => v.trim())

View file

@ -1,11 +1,7 @@
import { Turnstile } from "@marsidev/react-turnstile";
import classNames from "classnames";
import { useRef } from "react";
import { create } from "zustand"; import { create } from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
import { reportCaptchaSolve } from "@/backend/helpers/report"; import { reportCaptchaSolve } from "@/backend/helpers/report";
import { conf } from "@/setup/config";
export interface TurnstileStore { export interface TurnstileStore {
isInWidget: boolean; isInWidget: boolean;
@ -84,47 +80,3 @@ export async function getTurnstileToken() {
throw err; throw err;
} }
} }
export function TurnstileProvider(props: {
isInPopout?: boolean;
onUpdateShow?: (show: boolean) => void;
}) {
const siteKey = conf().TURNSTILE_KEY;
const idRef = useRef<string | null>(null);
const setTurnstile = useTurnstileStore((s) => s.setTurnstile);
const processToken = useTurnstileStore((s) => s.processToken);
if (!siteKey) return null;
return (
<div
className={classNames({
hidden: !props.isInPopout,
})}
>
<Turnstile
siteKey={siteKey}
options={{
refreshExpired: "never",
theme: "light",
}}
onWidgetLoad={(widgetId) => {
idRef.current = widgetId;
setTurnstile(widgetId, "mwturnstile", !!props.isInPopout);
}}
onError={() => {
const id = idRef.current;
if (!id) return;
processToken(null, id);
}}
onSuccess={(token) => {
const id = idRef.current;
if (!id) return;
processToken(token, id);
props.onUpdateShow?.(false);
}}
onBeforeInteractive={() => {
props.onUpdateShow?.(true);
}}
/>
</div>
);
}

View file

@ -2,7 +2,7 @@ import { conf } from "@/setup/config";
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
const originalUrls = conf().PROXY_URLS; const originalUrls = conf().PROXY_URLS;
const types = ["proxy", "api"] as const; const types = ["proxy"] as const;
type ParsedUrlType = (typeof types)[number]; type ParsedUrlType = (typeof types)[number];
@ -73,9 +73,3 @@ export function getProxyUrls() {
export function getM3U8ProxyUrls(): string[] { export function getM3U8ProxyUrls(): string[] {
return conf().M3U8_PROXY_URLS; return conf().M3U8_PROXY_URLS;
} }
export function getProviderApiUrls() {
return getParsedUrls()
.filter((v) => v.type === "api")
.map((v) => v.url);
}