diff --git a/src/backend/extension/compatibility.ts b/src/backend/extension/compatibility.ts new file mode 100644 index 00000000..31471d26 --- /dev/null +++ b/src/backend/extension/compatibility.ts @@ -0,0 +1,5 @@ +const allowedExtensionVersion = ["0.0.1"]; + +export function isAllowedExtensionVersion(version: string): boolean { + return allowedExtensionVersion.includes(version); +} diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts index ec0b4bf6..3c5480c1 100644 --- a/src/backend/extension/messaging.ts +++ b/src/backend/extension/messaging.ts @@ -3,6 +3,8 @@ import { sendToBackgroundViaRelay, } from "@plasmohq/messaging"; +import { isAllowedExtensionVersion } from "@/backend/extension/compatibility"; + let activeExtension = false; export interface ExtensionHello { @@ -35,7 +37,14 @@ export async function sendExtensionRequest( url: string, ops: any, ): Promise { - return sendMessage("proxy-request", { url, ...ops }); + return sendMessage("make-request", { url, ...ops }); +} + +export async function setDomainRule( + domains: string[], + headers: Record, +): Promise { + return sendMessage("prepare-stream", { domains, headers }); } export async function extensionInfo(): Promise { @@ -47,5 +56,9 @@ export function isExtensionActiveCached(): boolean { } export async function isExtensionActive(): Promise { - return !!(await extensionInfo()); + const info = await extensionInfo(); + if (!info) return false; + const allowedVersion = isAllowedExtensionVersion(info.version); + if (!allowedVersion) return false; + return true; } diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts index 2e9cacbf..8c0093f0 100644 --- a/src/backend/extension/plasmo.ts +++ b/src/backend/extension/plasmo.ts @@ -20,11 +20,11 @@ export type ExtensionRequestReply = }; interface MmMetadata { - "declarative-net-request": { + "prepare-stream": { req: PlasmoRequestBody; res: ExtensionRequestReply; }; - "proxy-request": { + "make-request": { req: PlasmoRequestBody; res: ExtensionRequestReply; }; diff --git a/src/backend/extension/streams.ts b/src/backend/extension/streams.ts new file mode 100644 index 00000000..8d202992 --- /dev/null +++ b/src/backend/extension/streams.ts @@ -0,0 +1,40 @@ +import { Stream } from "@movie-web/providers"; + +import { setDomainRule } from "@/backend/extension/messaging"; + +function extractDomain(url: string): string { + try { + const u = new URL(url); + return u.hostname; + } catch { + return url; + } +} + +function extractDomainsFromStream(stream: Stream): string[] { + if (stream.type === "hls") { + return [extractDomain(stream.playlist)]; + } + if (stream.type === "file") { + return Object.values(stream.qualities).map((v) => extractDomain(v.url)); + } + return []; +} + +function buildHeadersFromStream(stream: Stream): Record { + const headers: Record = {}; + Object.entries(stream.headers ?? {}).forEach((entry) => { + headers[entry[0]] = entry[1]; + }); + Object.entries(stream.preferredHeaders ?? {}).forEach((entry) => { + headers[entry[0]] = entry[1]; + }); + return headers; +} + +export async function prepareStream(stream: Stream) { + await setDomainRule( + extractDomainsFromStream(stream), + buildHeadersFromStream(stream), + ); +} diff --git a/src/components/player/hooks/useSourceSelection.ts b/src/components/player/hooks/useSourceSelection.ts index bca884f7..b9e167d6 100644 --- a/src/components/player/hooks/useSourceSelection.ts +++ b/src/components/player/hooks/useSourceSelection.ts @@ -5,6 +5,7 @@ import { } from "@movie-web/providers"; import { useAsyncFn } from "react-use"; +import { prepareStream } from "@/backend/extension/streams"; import { connectServerSideEvents, makeProviderUrl, @@ -131,6 +132,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) { ]); if (result.stream) { + await prepareStream(result.stream[0]); setCaption(null); setSource( convertRunoutputToSource({ stream: result.stream[0] }), @@ -187,6 +189,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) { ]); setSourceId(sourceId); setCaption(null); + await prepareStream(embedResult.stream[0]); setSource( convertRunoutputToSource({ stream: embedResult.stream[0] }), convertProviderCaption(embedResult.stream[0].captions), diff --git a/src/hooks/useProviderScrape.tsx b/src/hooks/useProviderScrape.tsx index 21cb985e..d6b48063 100644 --- a/src/hooks/useProviderScrape.tsx +++ b/src/hooks/useProviderScrape.tsx @@ -5,6 +5,7 @@ import { } from "@movie-web/providers"; import { RefObject, useCallback, useEffect, useRef, useState } from "react"; +import { prepareStream } from "@/backend/extension/streams"; import { connectServerSideEvents, getCachedMetadata, @@ -169,6 +170,7 @@ export function useScrape() { conn.on("update", updateEvent); conn.on("discoverEmbeds", discoverEmbedsEvent); const sseOutput = await conn.promise(); + if (sseOutput) await prepareStream(sseOutput.stream); return getResult(sseOutput === "" ? null : sseOutput); } @@ -184,6 +186,7 @@ export function useScrape() { discoverEmbeds: discoverEmbedsEvent, }, }); + if (output) await prepareStream(output.stream); return getResult(output); }, [