pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Clean up extension code

mrjvs f70d13f2 ef85c217

+171 -97
+11 -6
src/@types/plasmo.d.ts src/backend/extension/plasmo.ts
··· 1 - /* eslint-disable @typescript-eslint/ban-types */ 2 - import "@plasmohq/messaging"; 3 - 4 1 export interface PlasmoRequestBody { 5 2 ruleId: number; 6 3 domain: string; ··· 8 5 responseHeaders?: Record<string, string>; 9 6 } 10 7 11 - export type PlasmoResponseBody = 8 + export interface ExtensionHelloReply { 9 + version: string; 10 + } 11 + 12 + export type ExtensionRequestReply = 12 13 | { 13 14 success: true; 14 15 ruleId: number; ··· 21 22 interface MmMetadata { 22 23 "declarative-net-request": { 23 24 req: PlasmoRequestBody; 24 - res: PlasmoResponseBody; 25 + res: ExtensionRequestReply; 25 26 }; 26 27 "proxy-request": { 27 28 req: PlasmoRequestBody; 28 - res: PlasmoResponseBody; 29 + res: ExtensionRequestReply; 30 + }; 31 + hello: { 32 + req: null; 33 + res: ExtensionHelloReply; 29 34 }; 30 35 } 31 36
+51
src/backend/extension/messaging.ts
··· 1 + import { 2 + MessagesMetadata, 3 + sendToBackgroundViaRelay, 4 + } from "@plasmohq/messaging"; 5 + 6 + let activeExtension = false; 7 + 8 + export interface ExtensionHello { 9 + version: string; 10 + } 11 + 12 + function sendMessage<T, Payload>( 13 + message: keyof MessagesMetadata, 14 + payload: any, 15 + timeout: number = -1, 16 + ) { 17 + return new Promise<T | null>((resolve) => { 18 + if (timeout >= 0) setTimeout(() => resolve(null), timeout); 19 + sendToBackgroundViaRelay<Payload, T>({ 20 + name: message, 21 + body: payload, 22 + }) 23 + .then((res) => { 24 + activeExtension = true; 25 + resolve(res); 26 + }) 27 + .catch(() => { 28 + activeExtension = false; 29 + resolve(null); 30 + }); 31 + }); 32 + } 33 + 34 + export async function sendExtensionRequest( 35 + url: string, 36 + ops: any, 37 + ): Promise<ExtensionHello | null> { 38 + return sendMessage("proxy-request", { url, ...ops }); 39 + } 40 + 41 + export async function extensionInfo(): Promise<ExtensionHello | null> { 42 + return sendMessage("hello", null, 300); 43 + } 44 + 45 + export function isExtensionActiveCached(): boolean { 46 + return activeExtension; 47 + } 48 + 49 + export async function isExtensionActive(): Promise<boolean> { 50 + return !!(await extensionInfo()); 51 + }
+1 -1
src/backend/helpers/fetch.ts
··· 1 1 import { ofetch } from "ofetch"; 2 2 3 3 import { getApiToken, setApiToken } from "@/backend/helpers/providerApi"; 4 - import { getLoadbalancedProxyUrl } from "@/utils/providers"; 4 + import { getLoadbalancedProxyUrl } from "@/backend/providers/fetchers"; 5 5 6 6 type P<T> = Parameters<typeof ofetch<T, any>>; 7 7 type R<T> = ReturnType<typeof ofetch<T, any>>;
+26
src/backend/providers/providers.ts
··· 1 + import { 2 + makeProviders, 3 + makeStandardFetcher, 4 + targets, 5 + } from "@movie-web/providers"; 6 + 7 + import { isExtensionActiveCached } from "@/backend/extension/messaging"; 8 + import { 9 + makeExtensionFetcher, 10 + makeLoadBalancedSimpleProxyFetcher, 11 + } from "@/backend/providers/fetchers"; 12 + 13 + export function getProviders() { 14 + if (isExtensionActiveCached()) { 15 + return makeProviders({ 16 + fetcher: makeExtensionFetcher(), 17 + target: targets.BROWSER_EXTENSION, 18 + }); 19 + } 20 + 21 + return makeProviders({ 22 + fetcher: makeStandardFetcher(fetch), 23 + proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(), 24 + target: targets.BROWSER, 25 + }); 26 + }
+54 -64
src/components/player/display/base.ts
··· 1 - import { sendToBackgroundViaRelay } from "@plasmohq/messaging"; 2 1 import fscreen from "fscreen"; 3 2 import Hls, { Level } from "hls.js"; 4 3 5 - import { PlasmoRequestBody, PlasmoResponseBody } from "@/@types/plasmo"; 6 4 import { 7 5 DisplayInterface, 8 6 DisplayInterfaceEvents, ··· 43 41 ); 44 42 return found ? +found[0] : null; 45 43 } 44 + 46 45 function hlsLevelsToQualities(levels: Level[]): SourceQuality[] { 47 46 return levels 48 47 .map((v) => hlsLevelToQuality(v)) ··· 103 102 104 103 function setupSource(vid: HTMLVideoElement, src: LoadableSource) { 105 104 // TODO: Add check whether the extension is installed 106 - sendToBackgroundViaRelay<PlasmoRequestBody, PlasmoResponseBody>({ 107 - name: "declarative-net-request", 108 - body: { 109 - ruleId: 1, 110 - domain: src.type === "hls" ? new URL(src.url).hostname : src.url, 111 - requestHeaders: src.preferredHeaders, 112 - }, 113 - }).then(() => { 114 - if (src.type === "hls") { 115 - if (canPlayHlsNatively(vid)) { 116 - vid.src = processCdnLink(src.url); 117 - vid.currentTime = startAt; 118 - return; 119 - } 105 + if (src.type === "hls") { 106 + if (canPlayHlsNatively(vid)) { 107 + vid.src = processCdnLink(src.url); 108 + vid.currentTime = startAt; 109 + return; 110 + } 120 111 121 - if (!Hls.isSupported()) throw new Error("HLS not supported"); 122 - if (!hls) { 123 - hls = new Hls({ 124 - maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once 125 - fragLoadPolicy: { 126 - default: { 127 - maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin 128 - maxTimeToFirstByteMs: 30 * 1000, 129 - errorRetry: { 130 - maxNumRetry: 2, 131 - retryDelayMs: 1000, 132 - maxRetryDelayMs: 8000, 133 - }, 134 - timeoutRetry: { 135 - maxNumRetry: 3, 136 - maxRetryDelayMs: 0, 137 - retryDelayMs: 0, 138 - }, 112 + if (!Hls.isSupported()) throw new Error("HLS not supported"); 113 + if (!hls) { 114 + hls = new Hls({ 115 + maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once 116 + fragLoadPolicy: { 117 + default: { 118 + maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin 119 + maxTimeToFirstByteMs: 30 * 1000, 120 + errorRetry: { 121 + maxNumRetry: 2, 122 + retryDelayMs: 1000, 123 + maxRetryDelayMs: 8000, 124 + }, 125 + timeoutRetry: { 126 + maxNumRetry: 3, 127 + maxRetryDelayMs: 0, 128 + retryDelayMs: 0, 139 129 }, 140 130 }, 141 - }); 142 - hls.on(Hls.Events.ERROR, (event, data) => { 143 - console.error("HLS error", data); 144 - if (data.fatal) { 145 - emit("error", { 146 - message: data.error.message, 147 - stackTrace: data.error.stack, 148 - errorName: data.error.name, 149 - type: "hls", 150 - }); 151 - } 152 - }); 153 - hls.on(Hls.Events.MANIFEST_LOADED, () => { 154 - if (!hls) return; 155 - reportLevels(); 156 - setupQualityForHls(); 157 - }); 158 - hls.on(Hls.Events.LEVEL_SWITCHED, () => { 159 - if (!hls) return; 160 - const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]); 161 - emit("changedquality", quality); 162 - }); 163 - } 164 - 165 - hls.attachMedia(vid); 166 - hls.loadSource(processCdnLink(src.url)); 167 - vid.currentTime = startAt; 168 - return; 131 + }, 132 + }); 133 + hls.on(Hls.Events.ERROR, (event, data) => { 134 + console.error("HLS error", data); 135 + if (data.fatal) { 136 + emit("error", { 137 + message: data.error.message, 138 + stackTrace: data.error.stack, 139 + errorName: data.error.name, 140 + type: "hls", 141 + }); 142 + } 143 + }); 144 + hls.on(Hls.Events.MANIFEST_LOADED, () => { 145 + if (!hls) return; 146 + reportLevels(); 147 + setupQualityForHls(); 148 + }); 149 + hls.on(Hls.Events.LEVEL_SWITCHED, () => { 150 + if (!hls) return; 151 + const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]); 152 + emit("changedquality", quality); 153 + }); 169 154 } 170 155 171 - vid.src = processCdnLink(src.url); 156 + hls.attachMedia(vid); 157 + hls.loadSource(processCdnLink(src.url)); 172 158 vid.currentTime = startAt; 173 - }); 159 + return; 160 + } 161 + 162 + vid.src = processCdnLink(src.url); 163 + vid.currentTime = startAt; 174 164 } 175 165 176 166 function setSource() {
+5 -4
src/components/player/hooks/useSourceSelection.ts
··· 13 13 scrapeSourceOutputToProviderMetric, 14 14 useReportProviders, 15 15 } from "@/backend/helpers/report"; 16 + import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers"; 17 + import { getProviders } from "@/backend/providers/providers"; 16 18 import { convertProviderCaption } from "@/components/player/utils/captions"; 17 19 import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource"; 18 20 import { useOverlayRouter } from "@/hooks/useOverlayRouter"; 19 21 import { metaToScrapeMedia } from "@/stores/player/slices/source"; 20 22 import { usePlayerStore } from "@/stores/player/store"; 21 - import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers"; 22 23 23 24 export function useEmbedScraping( 24 25 routerId: string, ··· 47 48 ); 48 49 result = await conn.promise(); 49 50 } else { 50 - result = await providers.runEmbedScraper({ 51 + result = await getProviders().runEmbedScraper({ 51 52 id: embedId, 52 53 url, 53 54 }); ··· 111 112 ); 112 113 result = await conn.promise(); 113 114 } else { 114 - result = await providers.runSourceScraper({ 115 + result = await getProviders().runSourceScraper({ 115 116 id: sourceId, 116 117 media: scrapeMedia, 117 118 }); ··· 155 156 ); 156 157 embedResult = await conn.promise(); 157 158 } else { 158 - embedResult = await providers.runEmbedScraper({ 159 + embedResult = await getProviders().runEmbedScraper({ 159 160 id: result.embeds[0].embedId, 160 161 url: result.embeds[0].url, 161 162 });
+3 -2
src/hooks/useProviderScrape.tsx
··· 10 10 getCachedMetadata, 11 11 makeProviderUrl, 12 12 } from "@/backend/helpers/providerApi"; 13 - import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers"; 13 + import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers"; 14 + import { getProviders } from "@/backend/providers/providers"; 14 15 15 16 export interface ScrapingItems { 16 17 id: string; ··· 172 173 return getResult(sseOutput === "" ? null : sseOutput); 173 174 } 174 175 175 - if (!providers) return null; 176 176 startScrape(); 177 + const providers = getProviders(); 177 178 const output = await providers.runAll({ 178 179 media, 179 180 events: {
+11 -4
src/pages/parts/player/MetaPart.tsx
··· 3 3 import { useAsync } from "react-use"; 4 4 import type { AsyncReturnType } from "type-fest"; 5 5 6 + import { isExtensionActive } from "@/backend/extension/messaging"; 6 7 import { 7 8 fetchMetadata, 8 9 setCachedMetadata, ··· 10 11 import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; 11 12 import { decodeTMDBId } from "@/backend/metadata/tmdb"; 12 13 import { MWMediaType } from "@/backend/metadata/types/mw"; 14 + import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers"; 15 + import { getProviders } from "@/backend/providers/providers"; 13 16 import { Button } from "@/components/buttons/Button"; 14 17 import { Icons } from "@/components/Icon"; 15 18 import { IconPill } from "@/components/layout/IconPill"; ··· 18 21 import { Title } from "@/components/text/Title"; 19 22 import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout"; 20 23 import { conf } from "@/setup/config"; 21 - import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers"; 22 24 23 25 export interface MetaPartProps { 24 26 onGetMeta?: (meta: DetailedMeta, episodeId?: string) => void; ··· 41 43 const navigate = useNavigate(); 42 44 43 45 const { error, value, loading } = useAsync(async () => { 46 + // check extension 47 + const isActive = await isExtensionActive(); 48 + 49 + // use api metadata or providers metadata 44 50 const providerApiUrl = getLoadbalancedProviderApiUrl(); 45 - if (providerApiUrl) { 51 + if (providerApiUrl && !isActive) { 46 52 try { 47 53 await fetchMetadata(providerApiUrl); 48 54 } catch (err) { ··· 50 56 } 51 57 } else { 52 58 setCachedMetadata([ 53 - ...providers.listSources(), 54 - ...providers.listEmbeds(), 59 + ...getProviders().listSources(), 60 + ...getProviders().listEmbeds(), 55 61 ]); 56 62 } 57 63 64 + // get media meta data 58 65 let data: ReturnType<typeof decodeTMDBId> = null; 59 66 try { 60 67 if (!params.media) throw new Error("no media params");
+9 -16
src/utils/providers.ts src/backend/providers/fetchers.ts
··· 1 - import { 2 - Fetcher, 3 - ProviderControls, 4 - makeProviders, 5 - makeSimpleProxyFetcher, 6 - makeStandardFetcher, 7 - targets, 8 - } from "@movie-web/providers"; 1 + import { Fetcher, makeSimpleProxyFetcher } from "@movie-web/providers"; 9 2 3 + import { sendExtensionRequest } from "@/backend/extension/messaging"; 10 4 import { getApiToken, setApiToken } from "@/backend/helpers/providerApi"; 11 5 import { getProviderApiUrls, getProxyUrls } from "@/utils/proxyUrls"; 12 6 ··· 48 42 return response; 49 43 } 50 44 51 - function makeLoadBalancedSimpleProxyFetcher() { 45 + export function makeLoadBalancedSimpleProxyFetcher() { 52 46 const fetcher: Fetcher = async (a, b) => { 53 47 const currentFetcher = makeSimpleProxyFetcher( 54 48 getLoadbalancedProxyUrl(), ··· 59 53 return fetcher; 60 54 } 61 55 62 - export const providers = makeProviders({ 63 - fetcher: makeStandardFetcher(fetch), 64 - proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(), 65 - // TODO: Add check whether the extension is installed 66 - // target: targets.BROWSER, 67 - target: targets.BROWSER_EXTENSION, 68 - }) as any as ProviderControls; 56 + export function makeExtensionFetcher() { 57 + const fetcher: Fetcher = async (a, b) => { 58 + return sendExtensionRequest(a, b) as any; 59 + }; 60 + return fetcher; 61 + }