mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
Clean up extension code
This commit is contained in:
parent
ef85c217f7
commit
f70d13f2c9
9 changed files with 172 additions and 98 deletions
51
src/backend/extension/messaging.ts
Normal file
51
src/backend/extension/messaging.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import {
|
||||
MessagesMetadata,
|
||||
sendToBackgroundViaRelay,
|
||||
} from "@plasmohq/messaging";
|
||||
|
||||
let activeExtension = false;
|
||||
|
||||
export interface ExtensionHello {
|
||||
version: string;
|
||||
}
|
||||
|
||||
function sendMessage<T, Payload>(
|
||||
message: keyof MessagesMetadata,
|
||||
payload: any,
|
||||
timeout: number = -1,
|
||||
) {
|
||||
return new Promise<T | null>((resolve) => {
|
||||
if (timeout >= 0) setTimeout(() => resolve(null), timeout);
|
||||
sendToBackgroundViaRelay<Payload, T>({
|
||||
name: message,
|
||||
body: payload,
|
||||
})
|
||||
.then((res) => {
|
||||
activeExtension = true;
|
||||
resolve(res);
|
||||
})
|
||||
.catch(() => {
|
||||
activeExtension = false;
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function sendExtensionRequest(
|
||||
url: string,
|
||||
ops: any,
|
||||
): Promise<ExtensionHello | null> {
|
||||
return sendMessage("proxy-request", { url, ...ops });
|
||||
}
|
||||
|
||||
export async function extensionInfo(): Promise<ExtensionHello | null> {
|
||||
return sendMessage("hello", null, 300);
|
||||
}
|
||||
|
||||
export function isExtensionActiveCached(): boolean {
|
||||
return activeExtension;
|
||||
}
|
||||
|
||||
export async function isExtensionActive(): Promise<boolean> {
|
||||
return !!(await extensionInfo());
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import "@plasmohq/messaging";
|
||||
|
||||
export interface PlasmoRequestBody {
|
||||
ruleId: number;
|
||||
domain: string;
|
||||
|
@ -8,7 +5,11 @@ export interface PlasmoRequestBody {
|
|||
responseHeaders?: Record<string, string>;
|
||||
}
|
||||
|
||||
export type PlasmoResponseBody =
|
||||
export interface ExtensionHelloReply {
|
||||
version: string;
|
||||
}
|
||||
|
||||
export type ExtensionRequestReply =
|
||||
| {
|
||||
success: true;
|
||||
ruleId: number;
|
||||
|
@ -21,11 +22,15 @@ export type PlasmoResponseBody =
|
|||
interface MmMetadata {
|
||||
"declarative-net-request": {
|
||||
req: PlasmoRequestBody;
|
||||
res: PlasmoResponseBody;
|
||||
res: ExtensionRequestReply;
|
||||
};
|
||||
"proxy-request": {
|
||||
req: PlasmoRequestBody;
|
||||
res: PlasmoResponseBody;
|
||||
res: ExtensionRequestReply;
|
||||
};
|
||||
hello: {
|
||||
req: null;
|
||||
res: ExtensionHelloReply;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { ofetch } from "ofetch";
|
||||
|
||||
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
|
||||
import { getLoadbalancedProxyUrl } from "@/utils/providers";
|
||||
import { getLoadbalancedProxyUrl } from "@/backend/providers/fetchers";
|
||||
|
||||
type P<T> = Parameters<typeof ofetch<T, any>>;
|
||||
type R<T> = ReturnType<typeof ofetch<T, any>>;
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import {
|
||||
Fetcher,
|
||||
ProviderControls,
|
||||
makeProviders,
|
||||
makeSimpleProxyFetcher,
|
||||
makeStandardFetcher,
|
||||
targets,
|
||||
} from "@movie-web/providers";
|
||||
import { Fetcher, makeSimpleProxyFetcher } from "@movie-web/providers";
|
||||
|
||||
import { sendExtensionRequest } from "@/backend/extension/messaging";
|
||||
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
|
||||
import { getProviderApiUrls, getProxyUrls } from "@/utils/proxyUrls";
|
||||
|
||||
|
@ -48,7 +42,7 @@ async function fetchButWithApiTokens(
|
|||
return response;
|
||||
}
|
||||
|
||||
function makeLoadBalancedSimpleProxyFetcher() {
|
||||
export function makeLoadBalancedSimpleProxyFetcher() {
|
||||
const fetcher: Fetcher = async (a, b) => {
|
||||
const currentFetcher = makeSimpleProxyFetcher(
|
||||
getLoadbalancedProxyUrl(),
|
||||
|
@ -59,10 +53,9 @@ function makeLoadBalancedSimpleProxyFetcher() {
|
|||
return fetcher;
|
||||
}
|
||||
|
||||
export const providers = makeProviders({
|
||||
fetcher: makeStandardFetcher(fetch),
|
||||
proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(),
|
||||
// TODO: Add check whether the extension is installed
|
||||
// target: targets.BROWSER,
|
||||
target: targets.BROWSER_EXTENSION,
|
||||
}) as any as ProviderControls;
|
||||
export function makeExtensionFetcher() {
|
||||
const fetcher: Fetcher = async (a, b) => {
|
||||
return sendExtensionRequest(a, b) as any;
|
||||
};
|
||||
return fetcher;
|
||||
}
|
26
src/backend/providers/providers.ts
Normal file
26
src/backend/providers/providers.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import {
|
||||
makeProviders,
|
||||
makeStandardFetcher,
|
||||
targets,
|
||||
} from "@movie-web/providers";
|
||||
|
||||
import { isExtensionActiveCached } from "@/backend/extension/messaging";
|
||||
import {
|
||||
makeExtensionFetcher,
|
||||
makeLoadBalancedSimpleProxyFetcher,
|
||||
} from "@/backend/providers/fetchers";
|
||||
|
||||
export function getProviders() {
|
||||
if (isExtensionActiveCached()) {
|
||||
return makeProviders({
|
||||
fetcher: makeExtensionFetcher(),
|
||||
target: targets.BROWSER_EXTENSION,
|
||||
});
|
||||
}
|
||||
|
||||
return makeProviders({
|
||||
fetcher: makeStandardFetcher(fetch),
|
||||
proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(),
|
||||
target: targets.BROWSER,
|
||||
});
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
import { sendToBackgroundViaRelay } from "@plasmohq/messaging";
|
||||
import fscreen from "fscreen";
|
||||
import Hls, { Level } from "hls.js";
|
||||
|
||||
import { PlasmoRequestBody, PlasmoResponseBody } from "@/@types/plasmo";
|
||||
import {
|
||||
DisplayInterface,
|
||||
DisplayInterfaceEvents,
|
||||
|
@ -43,6 +41,7 @@ function qualityToHlsLevel(quality: SourceQuality): number | null {
|
|||
);
|
||||
return found ? +found[0] : null;
|
||||
}
|
||||
|
||||
function hlsLevelsToQualities(levels: Level[]): SourceQuality[] {
|
||||
return levels
|
||||
.map((v) => hlsLevelToQuality(v))
|
||||
|
@ -103,74 +102,65 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
|
|||
|
||||
function setupSource(vid: HTMLVideoElement, src: LoadableSource) {
|
||||
// TODO: Add check whether the extension is installed
|
||||
sendToBackgroundViaRelay<PlasmoRequestBody, PlasmoResponseBody>({
|
||||
name: "declarative-net-request",
|
||||
body: {
|
||||
ruleId: 1,
|
||||
domain: src.type === "hls" ? new URL(src.url).hostname : src.url,
|
||||
requestHeaders: src.preferredHeaders,
|
||||
},
|
||||
}).then(() => {
|
||||
if (src.type === "hls") {
|
||||
if (canPlayHlsNatively(vid)) {
|
||||
vid.src = processCdnLink(src.url);
|
||||
vid.currentTime = startAt;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Hls.isSupported()) throw new Error("HLS not supported");
|
||||
if (!hls) {
|
||||
hls = new Hls({
|
||||
maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
|
||||
fragLoadPolicy: {
|
||||
default: {
|
||||
maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin
|
||||
maxTimeToFirstByteMs: 30 * 1000,
|
||||
errorRetry: {
|
||||
maxNumRetry: 2,
|
||||
retryDelayMs: 1000,
|
||||
maxRetryDelayMs: 8000,
|
||||
},
|
||||
timeoutRetry: {
|
||||
maxNumRetry: 3,
|
||||
maxRetryDelayMs: 0,
|
||||
retryDelayMs: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
console.error("HLS error", data);
|
||||
if (data.fatal) {
|
||||
emit("error", {
|
||||
message: data.error.message,
|
||||
stackTrace: data.error.stack,
|
||||
errorName: data.error.name,
|
||||
type: "hls",
|
||||
});
|
||||
}
|
||||
});
|
||||
hls.on(Hls.Events.MANIFEST_LOADED, () => {
|
||||
if (!hls) return;
|
||||
reportLevels();
|
||||
setupQualityForHls();
|
||||
});
|
||||
hls.on(Hls.Events.LEVEL_SWITCHED, () => {
|
||||
if (!hls) return;
|
||||
const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]);
|
||||
emit("changedquality", quality);
|
||||
});
|
||||
}
|
||||
|
||||
hls.attachMedia(vid);
|
||||
hls.loadSource(processCdnLink(src.url));
|
||||
if (src.type === "hls") {
|
||||
if (canPlayHlsNatively(vid)) {
|
||||
vid.src = processCdnLink(src.url);
|
||||
vid.currentTime = startAt;
|
||||
return;
|
||||
}
|
||||
|
||||
vid.src = processCdnLink(src.url);
|
||||
if (!Hls.isSupported()) throw new Error("HLS not supported");
|
||||
if (!hls) {
|
||||
hls = new Hls({
|
||||
maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
|
||||
fragLoadPolicy: {
|
||||
default: {
|
||||
maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin
|
||||
maxTimeToFirstByteMs: 30 * 1000,
|
||||
errorRetry: {
|
||||
maxNumRetry: 2,
|
||||
retryDelayMs: 1000,
|
||||
maxRetryDelayMs: 8000,
|
||||
},
|
||||
timeoutRetry: {
|
||||
maxNumRetry: 3,
|
||||
maxRetryDelayMs: 0,
|
||||
retryDelayMs: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
console.error("HLS error", data);
|
||||
if (data.fatal) {
|
||||
emit("error", {
|
||||
message: data.error.message,
|
||||
stackTrace: data.error.stack,
|
||||
errorName: data.error.name,
|
||||
type: "hls",
|
||||
});
|
||||
}
|
||||
});
|
||||
hls.on(Hls.Events.MANIFEST_LOADED, () => {
|
||||
if (!hls) return;
|
||||
reportLevels();
|
||||
setupQualityForHls();
|
||||
});
|
||||
hls.on(Hls.Events.LEVEL_SWITCHED, () => {
|
||||
if (!hls) return;
|
||||
const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]);
|
||||
emit("changedquality", quality);
|
||||
});
|
||||
}
|
||||
|
||||
hls.attachMedia(vid);
|
||||
hls.loadSource(processCdnLink(src.url));
|
||||
vid.currentTime = startAt;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
vid.src = processCdnLink(src.url);
|
||||
vid.currentTime = startAt;
|
||||
}
|
||||
|
||||
function setSource() {
|
||||
|
|
|
@ -13,12 +13,13 @@ 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";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { metaToScrapeMedia } from "@/stores/player/slices/source";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers";
|
||||
|
||||
export function useEmbedScraping(
|
||||
routerId: string,
|
||||
|
@ -47,7 +48,7 @@ export function useEmbedScraping(
|
|||
);
|
||||
result = await conn.promise();
|
||||
} else {
|
||||
result = await providers.runEmbedScraper({
|
||||
result = await getProviders().runEmbedScraper({
|
||||
id: embedId,
|
||||
url,
|
||||
});
|
||||
|
@ -111,7 +112,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
|
|||
);
|
||||
result = await conn.promise();
|
||||
} else {
|
||||
result = await providers.runSourceScraper({
|
||||
result = await getProviders().runSourceScraper({
|
||||
id: sourceId,
|
||||
media: scrapeMedia,
|
||||
});
|
||||
|
@ -155,7 +156,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
|
|||
);
|
||||
embedResult = await conn.promise();
|
||||
} else {
|
||||
embedResult = await providers.runEmbedScraper({
|
||||
embedResult = await getProviders().runEmbedScraper({
|
||||
id: result.embeds[0].embedId,
|
||||
url: result.embeds[0].url,
|
||||
});
|
||||
|
|
|
@ -10,7 +10,8 @@ import {
|
|||
getCachedMetadata,
|
||||
makeProviderUrl,
|
||||
} from "@/backend/helpers/providerApi";
|
||||
import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers";
|
||||
import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
|
||||
import { getProviders } from "@/backend/providers/providers";
|
||||
|
||||
export interface ScrapingItems {
|
||||
id: string;
|
||||
|
@ -172,8 +173,8 @@ export function useScrape() {
|
|||
return getResult(sseOutput === "" ? null : sseOutput);
|
||||
}
|
||||
|
||||
if (!providers) return null;
|
||||
startScrape();
|
||||
const providers = getProviders();
|
||||
const output = await providers.runAll({
|
||||
media,
|
||||
events: {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useNavigate, useParams } from "react-router-dom";
|
|||
import { useAsync } from "react-use";
|
||||
import type { AsyncReturnType } from "type-fest";
|
||||
|
||||
import { isExtensionActive } from "@/backend/extension/messaging";
|
||||
import {
|
||||
fetchMetadata,
|
||||
setCachedMetadata,
|
||||
|
@ -10,6 +11,8 @@ import {
|
|||
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";
|
||||
import { IconPill } from "@/components/layout/IconPill";
|
||||
|
@ -18,7 +21,6 @@ import { Paragraph } from "@/components/text/Paragraph";
|
|||
import { Title } from "@/components/text/Title";
|
||||
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
|
||||
import { conf } from "@/setup/config";
|
||||
import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers";
|
||||
|
||||
export interface MetaPartProps {
|
||||
onGetMeta?: (meta: DetailedMeta, episodeId?: string) => void;
|
||||
|
@ -41,8 +43,12 @@ export function MetaPart(props: MetaPartProps) {
|
|||
const navigate = useNavigate();
|
||||
|
||||
const { error, value, loading } = useAsync(async () => {
|
||||
// check extension
|
||||
const isActive = await isExtensionActive();
|
||||
|
||||
// use api metadata or providers metadata
|
||||
const providerApiUrl = getLoadbalancedProviderApiUrl();
|
||||
if (providerApiUrl) {
|
||||
if (providerApiUrl && !isActive) {
|
||||
try {
|
||||
await fetchMetadata(providerApiUrl);
|
||||
} catch (err) {
|
||||
|
@ -50,11 +56,12 @@ export function MetaPart(props: MetaPartProps) {
|
|||
}
|
||||
} else {
|
||||
setCachedMetadata([
|
||||
...providers.listSources(),
|
||||
...providers.listEmbeds(),
|
||||
...getProviders().listSources(),
|
||||
...getProviders().listEmbeds(),
|
||||
]);
|
||||
}
|
||||
|
||||
// get media meta data
|
||||
let data: ReturnType<typeof decodeTMDBId> = null;
|
||||
try {
|
||||
if (!params.media) throw new Error("no media params");
|
||||
|
|
Loading…
Reference in a new issue