diff --git a/Dockerfile b/Dockerfile index 90587a93..13e3db4a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,6 @@ ARG ONBOARDING_CHROME_EXTENSION_INSTALL_LINK ARG ONBOARDING_PROXY_INSTALL_LINK ARG DISALLOWED_IDS ARG CDN_REPLACEMENTS -ARG TURNSTILE_KEY ARG ALLOW_AUTOPLAY="false" 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_DISALLOWED_IDS=${DISALLOWED_IDS} ENV VITE_CDN_REPLACEMENTS=${CDN_REPLACEMENTS} -ENV VITE_TURNSTILE_KEY=${TURNSTILE_KEY} ENV VITE_ALLOW_AUTOPLAY=${ALLOW_AUTOPLAY} COPY . ./ diff --git a/docker-compose.yaml b/docker-compose.yaml index 719b39c5..8147c31d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -19,7 +19,6 @@ services: # ONBOARDING_PROXY_INSTALL_LINK: "" # DISALLOWED_IDS: "" # CDN_REPLACEMENTS: "" - # TURNSTILE_KEY: "" ports: - "80:80" restart: unless-stopped diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json index a0f93d16..dc2236a3 100644 --- a/src/assets/locales/en.json +++ b/src/assets/locales/en.json @@ -947,12 +947,6 @@ "remaining": "{{timeLeft}} left • Finish at {{timeFinished, datetime}}", "shortRegular": "{{timeWatched}}", "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": { diff --git a/src/backend/helpers/providerApi.ts b/src/backend/helpers/providerApi.ts index c0c96db7..ef622777 100644 --- a/src/backend/helpers/providerApi.ts +++ b/src/backend/helpers/providerApi.ts @@ -1,9 +1,6 @@ -import { MetaOutput, NotFoundError, ScrapeMedia } from "@p-stream/providers"; +import { MetaOutput } from "@p-stream/providers"; import { jwtDecode } from "jwt-decode"; -import { mwFetch } from "@/backend/helpers/fetch"; -import { getTurnstileToken, isTurnstileInitialized } from "@/stores/turnstile"; - let metaDataCache: MetaOutput[] | null = null; let token: null | string = null; @@ -31,143 +28,6 @@ function getTokenIfValid(): null | string { return null; } -export async function fetchMetadata(base: string) { - if (metaDataCache) return; - const data = await mwFetch(`${base}/metadata`); - metaDataCache = data.flat(); -} - -function scrapeMediaToQueryMedia(media: ScrapeMedia) { - let extra: Record = {}; - 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) { - 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 { - let apiToken = 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( - 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((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) => { - 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(event: string, cb: (data: Data) => void) { - eventSource.addEventListener(event, (e) => cb(JSON.parse(e.data))); - }, - }; + return getTokenIfValid(); } diff --git a/src/backend/providers/fetchers.ts b/src/backend/providers/fetchers.ts index cd345577..8e645c66 100644 --- a/src/backend/providers/fetchers.ts +++ b/src/backend/providers/fetchers.ts @@ -6,11 +6,7 @@ import { import { sendExtensionRequest } from "@/backend/extension/messaging"; import { getApiToken, setApiToken } from "@/backend/helpers/providerApi"; -import { - getM3U8ProxyUrls, - getProviderApiUrls, - getProxyUrls, -} from "@/utils/proxyUrls"; +import { getM3U8ProxyUrls, getProxyUrls } from "@/utils/proxyUrls"; import { convertBodyToObject, getBodyTypeFromBody } from "../extension/request"; @@ -28,8 +24,6 @@ function makeLoadbalancedList(getter: () => string[]) { } export const getLoadbalancedProxyUrl = makeLoadbalancedList(getProxyUrls); -export const getLoadbalancedProviderApiUrl = - makeLoadbalancedList(getProviderApiUrls); function getEnabledM3U8ProxyUrls() { const allM3U8ProxyUrls = getM3U8ProxyUrls(); const enabledProxies = localStorage.getItem("m3u8-proxy-enabled"); diff --git a/src/components/overlays/OverlayDisplay.tsx b/src/components/overlays/OverlayDisplay.tsx index e7232b3a..f94f0041 100644 --- a/src/components/overlays/OverlayDisplay.tsx +++ b/src/components/overlays/OverlayDisplay.tsx @@ -2,14 +2,12 @@ import classNames from "classnames"; import FocusTrap from "focus-trap-react"; import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; -import { useTranslation } from "react-i18next"; import { Transition } from "@/components/utils/Transition"; import { useInternalOverlayRouter, useRouterAnchorUpdate, } from "@/hooks/useOverlayRouter"; -import { TurnstileProvider, getTurnstile } from "@/stores/turnstile"; export interface OverlayProps { id: string; @@ -17,40 +15,6 @@ export interface OverlayProps { 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 ( -
-
-
-

- {t("player.turnstile.title")} -

-

- {t("player.turnstile.description")} -

-
- setShow(shouldShow)} - /> -
-
- ); -} - export function OverlayDisplay(props: { children: ReactNode }) { const router = useInternalOverlayRouter("hello world :)"); const refRouter = useRef(router); @@ -63,12 +27,7 @@ export function OverlayDisplay(props: { children: ReactNode }) { r.close(); }; }, []); - return ( -
- - {props.children} -
- ); + return
{props.children}
; } export function OverlayPortal(props: { diff --git a/src/components/player/hooks/useSourceSelection.ts b/src/components/player/hooks/useSourceSelection.ts index dde82db0..e2f6f3bc 100644 --- a/src/components/player/hooks/useSourceSelection.ts +++ b/src/components/player/hooks/useSourceSelection.ts @@ -7,15 +7,10 @@ import { useAsyncFn } from "react-use"; import { isExtensionActiveCached } from "@/backend/extension/messaging"; import { prepareStream } from "@/backend/extension/streams"; -import { - connectServerSideEvents, - makeProviderUrl, -} from "@/backend/helpers/providerApi"; import { scrapeSourceOutputToProviderMetric, useReportProviders, } from "@/backend/helpers/report"; -import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers"; import { getProviders } from "@/backend/providers/providers"; import { convertProviderCaption } from "@/components/player/utils/captions"; import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource"; @@ -60,23 +55,13 @@ export function useEmbedScraping( ); const [request, run] = useAsyncFn(async () => { - const providerApiUrl = getLoadbalancedProviderApiUrl(); let result: EmbedOutput | undefined; if (!meta) return; try { - if (providerApiUrl && !isExtensionActiveCached()) { - const baseUrlMaker = makeProviderUrl(providerApiUrl); - const conn = await connectServerSideEvents( - baseUrlMaker.scrapeEmbed(embedId, url), - ["completed", "noOutput"], - ); - result = await conn.promise(); - } else { - result = await getProviders().runEmbedScraper({ - id: embedId, - url, - }); - } + result = await getProviders().runEmbedScraper({ + id: embedId, + url, + }); } catch (err) { console.error(`Failed to scrape ${embedId}`, err); const notFound = err instanceof NotFoundError; @@ -148,23 +133,13 @@ export function useSourceScraping(sourceId: string | null, routerId: string) { if (!sourceId || !meta) return null; setEmbedId(null); const scrapeMedia = metaToScrapeMedia(meta); - const providerApiUrl = getLoadbalancedProviderApiUrl(); let result: SourcererOutput | undefined; try { - if (providerApiUrl && !isExtensionActiveCached()) { - const baseUrlMaker = makeProviderUrl(providerApiUrl); - const conn = await connectServerSideEvents( - baseUrlMaker.scrapeSource(sourceId, scrapeMedia), - ["completed", "noOutput"], - ); - result = await conn.promise(); - } else { - result = await getProviders().runSourceScraper({ - id: sourceId, - media: scrapeMedia, - }); - } + result = await getProviders().runSourceScraper({ + id: sourceId, + media: scrapeMedia, + }); } catch (err) { console.error(`Failed to scrape ${sourceId}`, err); const notFound = err instanceof NotFoundError; @@ -199,22 +174,10 @@ export function useSourceScraping(sourceId: string | null, routerId: string) { let embedResult: EmbedOutput | undefined; if (!meta) return; try { - if (providerApiUrl && !isExtensionActiveCached()) { - const baseUrlMaker = makeProviderUrl(providerApiUrl); - const conn = await connectServerSideEvents( - 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, - }); - } + embedResult = await getProviders().runEmbedScraper({ + id: result.embeds[0].embedId, + url: result.embeds[0].url, + }); } catch (err) { console.error(`Failed to scrape ${result.embeds[0].embedId}`, err); const notFound = err instanceof NotFoundError; diff --git a/src/hooks/useProviderScrape.tsx b/src/hooks/useProviderScrape.tsx index 0ef0ecea..39b2b561 100644 --- a/src/hooks/useProviderScrape.tsx +++ b/src/hooks/useProviderScrape.tsx @@ -3,12 +3,7 @@ import { RefObject, useCallback, useEffect, useRef, useState } from "react"; import { isExtensionActiveCached } from "@/backend/extension/messaging"; import { prepareStream } from "@/backend/extension/streams"; -import { - connectServerSideEvents, - getCachedMetadata, - makeProviderUrl, -} from "@/backend/helpers/providerApi"; -import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers"; +import { getCachedMetadata } from "@/backend/helpers/providerApi"; import { getProviders } from "@/backend/providers/providers"; import { getMediaKey } from "@/stores/player/slices/source"; import { usePlayerStore } from "@/stores/player/store"; @@ -245,29 +240,6 @@ export function useScrape() { ) : undefined; - const providerApiUrl = getLoadbalancedProviderApiUrl(); - if (providerApiUrl && !isExtensionActiveCached()) { - startScrape(); - const baseUrlMaker = makeProviderUrl(providerApiUrl); - const conn = await connectServerSideEvents( - 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(); const providers = getProviders(); const output = await providers.runAll({ diff --git a/src/pages/parts/player/MetaPart.tsx b/src/pages/parts/player/MetaPart.tsx index 67228607..c4c77e2e 100644 --- a/src/pages/parts/player/MetaPart.tsx +++ b/src/pages/parts/player/MetaPart.tsx @@ -5,14 +5,10 @@ import type { AsyncReturnType } from "type-fest"; import { isAllowedExtensionVersion } from "@/backend/extension/compatibility"; import { extensionInfo, sendPage } from "@/backend/extension/messaging"; -import { - fetchMetadata, - setCachedMetadata, -} from "@/backend/helpers/providerApi"; +import { setCachedMetadata } from "@/backend/helpers/providerApi"; import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; import { decodeTMDBId } from "@/backend/metadata/tmdb"; import { MWMediaType } from "@/backend/metadata/types/mw"; -import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers"; import { getProviders } from "@/backend/providers/providers"; import { Button } from "@/components/buttons/Button"; import { Icons } from "@/components/Icon"; @@ -52,20 +48,11 @@ export function MetaPart(props: MetaPartProps) { if (!info.hasPermission) throw new Error("extension-no-permission"); } - // use api metadata or providers metadata - const providerApiUrl = getLoadbalancedProviderApiUrl(); - if (providerApiUrl && !isValidExtension) { - try { - await fetchMetadata(providerApiUrl); - } catch (err) { - throw new Error("failed-api-metadata"); - } - } else { - setCachedMetadata([ - ...getProviders().listSources(), - ...getProviders().listEmbeds(), - ]); - } + // use providers metadata + setCachedMetadata([ + ...getProviders().listSources(), + ...getProviders().listEmbeds(), + ]); // get media meta data let data: ReturnType = null; @@ -160,28 +147,6 @@ export function MetaPart(props: MetaPartProps) { ); } - if (error && error.message === "failed-api-metadata") { - return ( - - - - {t("player.metadata.failed.badge")} - - {t("player.metadata.api.text")} - {t("player.metadata.api.title")} - - - - ); - } - if (error) { return ( diff --git a/src/pages/parts/player/ScrapeErrorPart.tsx b/src/pages/parts/player/ScrapeErrorPart.tsx index 715dee8e..4a4d6f2d 100644 --- a/src/pages/parts/player/ScrapeErrorPart.tsx +++ b/src/pages/parts/player/ScrapeErrorPart.tsx @@ -19,7 +19,6 @@ import { useOnboardingStore } from "@/stores/onboarding"; import { usePreferencesStore } from "@/stores/preferences"; import { getExtensionState } from "@/utils/extension"; import type { ExtensionStatus } from "@/utils/extension"; -import { getProviderApiUrls } from "@/utils/proxyUrls"; import { ErrorCardInModal } from "../errors/ErrorCard"; @@ -42,9 +41,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) { const error = useMemo(() => { const data = props.data; let str = ""; - const apiUrls = getProviderApiUrls(); - str += `URL - ${location.pathname}\n`; - str += `API - ${apiUrls.length > 0}\n\n`; + str += `URL - ${location.pathname}\n\n`; Object.values(data.sources).forEach((v) => { str += `${v.id}: ${v.status}\n`; if (v.reason) str += `${v.reason}\n`; diff --git a/src/pages/parts/player/ScrapingPart.tsx b/src/pages/parts/player/ScrapingPart.tsx index 68f572b5..20df4309 100644 --- a/src/pages/parts/player/ScrapingPart.tsx +++ b/src/pages/parts/player/ScrapingPart.tsx @@ -96,7 +96,7 @@ export function ScrapingPart(props: ScrapingProps) { currentProviderIndex = sourceOrder.length - 1; if (failedStartScrape) - return {t("player.turnstile.error")}; + return {t("player.scraping.items.failure")}; return (
-

{t("player.turnstile.verifyingHumanity")}

+

{t("player.scraping.items.pending")}

) : null}
; HAS_ONBOARDING: boolean; ALLOW_AUTOPLAY: boolean; @@ -88,7 +86,6 @@ const env: Record = { NORMAL_ROUTER: import.meta.env.VITE_NORMAL_ROUTER, BACKEND_URL: import.meta.env.VITE_BACKEND_URL, DISALLOWED_IDS: import.meta.env.VITE_DISALLOWED_IDS, - TURNSTILE_KEY: import.meta.env.VITE_TURNSTILE_KEY, CDN_REPLACEMENTS: import.meta.env.VITE_CDN_REPLACEMENTS, HAS_ONBOARDING: import.meta.env.VITE_HAS_ONBOARDING, ALLOW_AUTOPLAY: import.meta.env.VITE_ALLOW_AUTOPLAY, @@ -153,7 +150,6 @@ export function conf(): RuntimeConfig { NORMAL_ROUTER: getKey("NORMAL_ROUTER", "false") === "true", HAS_ONBOARDING: getKey("HAS_ONBOARDING", "false") === "true", ALLOW_AUTOPLAY: getKey("ALLOW_AUTOPLAY", "false") === "true", - TURNSTILE_KEY: getKey("TURNSTILE_KEY"), DISALLOWED_IDS: getKey("DISALLOWED_IDS", "") .split(",") .map((v) => v.trim()) diff --git a/src/stores/turnstile/index.tsx b/src/stores/turnstile/index.tsx index 67340f10..e6915479 100644 --- a/src/stores/turnstile/index.tsx +++ b/src/stores/turnstile/index.tsx @@ -1,11 +1,7 @@ -import { Turnstile } from "@marsidev/react-turnstile"; -import classNames from "classnames"; -import { useRef } from "react"; import { create } from "zustand"; import { immer } from "zustand/middleware/immer"; import { reportCaptchaSolve } from "@/backend/helpers/report"; -import { conf } from "@/setup/config"; export interface TurnstileStore { isInWidget: boolean; @@ -84,47 +80,3 @@ export async function getTurnstileToken() { throw err; } } - -export function TurnstileProvider(props: { - isInPopout?: boolean; - onUpdateShow?: (show: boolean) => void; -}) { - const siteKey = conf().TURNSTILE_KEY; - const idRef = useRef(null); - const setTurnstile = useTurnstileStore((s) => s.setTurnstile); - const processToken = useTurnstileStore((s) => s.processToken); - if (!siteKey) return null; - return ( -
- { - 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); - }} - /> -
- ); -} diff --git a/src/utils/proxyUrls.ts b/src/utils/proxyUrls.ts index 41573b79..03e82bf0 100644 --- a/src/utils/proxyUrls.ts +++ b/src/utils/proxyUrls.ts @@ -2,7 +2,7 @@ import { conf } from "@/setup/config"; import { useAuthStore } from "@/stores/auth"; const originalUrls = conf().PROXY_URLS; -const types = ["proxy", "api"] as const; +const types = ["proxy"] as const; type ParsedUrlType = (typeof types)[number]; @@ -73,9 +73,3 @@ export function getProxyUrls() { export function getM3U8ProxyUrls(): string[] { return conf().M3U8_PROXY_URLS; } - -export function getProviderApiUrls() { - return getParsedUrls() - .filter((v) => v.type === "api") - .map((v) => v.url); -}