mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-26 17:11:50 +01:00
first mvp extension
This commit is contained in:
parent
fbb5ef7115
commit
ef85c217f7
@ -31,6 +31,7 @@
|
||||
"@ladjs/country-language": "^1.0.3",
|
||||
"@movie-web/providers": "^2.0.5",
|
||||
"@noble/hashes": "^1.3.3",
|
||||
"@plasmohq/messaging": "^0.6.1",
|
||||
"@react-spring/web": "^9.7.3",
|
||||
"@scure/bip39": "^1.2.2",
|
||||
"@sozialhelden/ietf-language-tags": "^5.4.2",
|
||||
|
21
pnpm-lock.yaml
generated
21
pnpm-lock.yaml
generated
@ -27,6 +27,9 @@ dependencies:
|
||||
'@noble/hashes':
|
||||
specifier: ^1.3.3
|
||||
version: 1.3.3
|
||||
'@plasmohq/messaging':
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1(react@18.2.0)
|
||||
'@react-spring/web':
|
||||
specifier: ^9.7.3
|
||||
version: 9.7.3(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -1980,6 +1983,18 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/@plasmohq/messaging@0.6.1(react@18.2.0):
|
||||
resolution: {integrity: sha512-/nn1k8SG5z++o/NnZu+byHWcC9MhPLxfmvj+AP3buqMn7uwfYDcYWURLuMW2Knw08HBg+wku2v1Ltt4evN0nzA==}
|
||||
peerDependencies:
|
||||
react: ^16.8.6 || ^17 || ^18
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
dependencies:
|
||||
nanoid: 5.0.3
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@react-spring/animated@9.7.3(react@18.2.0):
|
||||
resolution: {integrity: sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==}
|
||||
peerDependencies:
|
||||
@ -5156,6 +5171,12 @@ packages:
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
/nanoid@5.0.3:
|
||||
resolution: {integrity: sha512-I7X2b22cxA4LIHXPSqbBCEQSL+1wv8TuoefejsX4HFWyC6jc5JG7CEaxOltiKjc1M+YCS2YkrZZcj4+dytw9GA==}
|
||||
engines: {node: ^18 || >=20}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/nanoid@5.0.4:
|
||||
resolution: {integrity: sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==}
|
||||
engines: {node: ^18 || >=20}
|
||||
|
37
src/@types/plasmo.d.ts
vendored
Normal file
37
src/@types/plasmo.d.ts
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import "@plasmohq/messaging";
|
||||
|
||||
export interface PlasmoRequestBody {
|
||||
ruleId: number;
|
||||
domain: string;
|
||||
requestHeaders?: Record<string, string>;
|
||||
responseHeaders?: Record<string, string>;
|
||||
}
|
||||
|
||||
export type PlasmoResponseBody =
|
||||
| {
|
||||
success: true;
|
||||
ruleId: number;
|
||||
}
|
||||
| {
|
||||
success: false;
|
||||
error: string;
|
||||
};
|
||||
|
||||
interface MmMetadata {
|
||||
"declarative-net-request": {
|
||||
req: PlasmoRequestBody;
|
||||
res: PlasmoResponseBody;
|
||||
};
|
||||
"proxy-request": {
|
||||
req: PlasmoRequestBody;
|
||||
res: PlasmoResponseBody;
|
||||
};
|
||||
}
|
||||
|
||||
interface MpMetadata {}
|
||||
|
||||
declare module "@plasmohq/messaging" {
|
||||
interface MessagesMetadata extends MmMetadata {}
|
||||
interface PortsMetadata extends MpMetadata {}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import { sendToBackgroundViaRelay } from "@plasmohq/messaging";
|
||||
import fscreen from "fscreen";
|
||||
import Hls, { Level } from "hls.js";
|
||||
|
||||
import { PlasmoRequestBody, PlasmoResponseBody } from "@/@types/plasmo";
|
||||
import {
|
||||
DisplayInterface,
|
||||
DisplayInterfaceEvents,
|
||||
@ -100,65 +102,75 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
|
||||
}
|
||||
|
||||
function setupSource(vid: HTMLVideoElement, src: LoadableSource) {
|
||||
if (src.type === "hls") {
|
||||
if (canPlayHlsNatively(vid)) {
|
||||
vid.src = processCdnLink(src.url);
|
||||
// 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));
|
||||
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));
|
||||
vid.src = processCdnLink(src.url);
|
||||
vid.currentTime = startAt;
|
||||
return;
|
||||
}
|
||||
|
||||
vid.src = processCdnLink(src.url);
|
||||
vid.currentTime = startAt;
|
||||
});
|
||||
}
|
||||
|
||||
function setSource() {
|
||||
|
@ -28,6 +28,7 @@ export function convertRunoutputToSource(out: {
|
||||
return {
|
||||
type: "hls",
|
||||
url: out.stream.playlist,
|
||||
preferredHeaders: out.stream.preferredHeaders,
|
||||
};
|
||||
}
|
||||
if (out.stream.type === "file") {
|
||||
@ -49,6 +50,7 @@ export function convertRunoutputToSource(out: {
|
||||
return {
|
||||
type: "file",
|
||||
qualities,
|
||||
preferredHeaders: out.stream.preferredHeaders,
|
||||
};
|
||||
}
|
||||
throw new Error("unrecognized type");
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Qualities } from "@movie-web/providers";
|
||||
import { Qualities, Stream } from "@movie-web/providers";
|
||||
|
||||
import { QualityStore } from "@/stores/quality";
|
||||
|
||||
@ -14,16 +14,19 @@ export type SourceFileStream = {
|
||||
export type LoadableSource = {
|
||||
type: StreamType;
|
||||
url: string;
|
||||
preferredHeaders?: Stream["preferredHeaders"];
|
||||
};
|
||||
|
||||
export type SourceSliceSource =
|
||||
| {
|
||||
type: "file";
|
||||
qualities: Partial<Record<SourceQuality, SourceFileStream>>;
|
||||
preferredHeaders?: Stream["preferredHeaders"];
|
||||
}
|
||||
| {
|
||||
type: "hls";
|
||||
url: string;
|
||||
preferredHeaders?: Stream["preferredHeaders"];
|
||||
};
|
||||
|
||||
const qualitySorting: Record<SourceQuality, number> = {
|
||||
|
@ -62,5 +62,7 @@ function makeLoadBalancedSimpleProxyFetcher() {
|
||||
export const providers = makeProviders({
|
||||
fetcher: makeStandardFetcher(fetch),
|
||||
proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(),
|
||||
target: targets.BROWSER,
|
||||
// TODO: Add check whether the extension is installed
|
||||
// target: targets.BROWSER,
|
||||
target: targets.BROWSER_EXTENSION,
|
||||
}) as any as ProviderControls;
|
||||
|
Loading…
Reference in New Issue
Block a user