Compare commits
11 commits
6445fb5e82
...
306f2d5f12
Author | SHA1 | Date | |
---|---|---|---|
|
306f2d5f12 | ||
|
c446f337de | ||
|
100e2722a9 | ||
|
f3fff5cc09 | ||
|
57f4da848b | ||
|
10cbeab3dc | ||
|
45003ebabd | ||
|
a4519724e8 | ||
|
5aba65b89e | ||
|
1c1b4cc697 | ||
|
596713c44c |
13 changed files with 2373 additions and 193 deletions
|
@ -1,4 +1,4 @@
|
|||
FROM denoland/deno:debian-1.46.3 AS builder
|
||||
FROM denoland/deno:debian-2.1.3 AS builder
|
||||
|
||||
ARG TINI_VERSION=0.19.0
|
||||
|
||||
|
|
1
compile.env
Normal file
1
compile.env
Normal file
|
@ -0,0 +1 @@
|
|||
DENO_COMPILED=true
|
|
@ -3,6 +3,7 @@ port = 8282
|
|||
host = "127.0.0.1"
|
||||
secret_key = "CHANGE_ME"
|
||||
base_url = "http://localhost:8282"
|
||||
verify_requests = false
|
||||
|
||||
[cache]
|
||||
enabled = true
|
||||
|
|
15
deno.json
15
deno.json
|
@ -1,22 +1,23 @@
|
|||
{
|
||||
"tasks": {
|
||||
"dev": "deno run --allow-net --allow-env --allow-sys=hostname --allow-read --allow-write=/var/tmp/youtubei.js --watch src/main.ts",
|
||||
"compile": "deno compile --output invidious_companion --allow-net --allow-env --allow-read --allow-sys=hostname --allow-write=/var/tmp/youtubei.js src/main.ts"
|
||||
"dev": "deno run --allow-import=github.com:443,jsr.io:443,raw.githubusercontent.com:443,esm.sh:443,deno.land:443 --allow-net --allow-env --allow-sys=hostname --allow-read --allow-write=/var/tmp/youtubei.js --watch src/main.ts",
|
||||
"compile": "deno compile --include ./src/lib/helpers/youtubePlayerReq.ts --include ./src/lib/helpers/getFetchClient.ts --output invidious_companion --allow-import=github.com:443,jsr.io:443,raw.githubusercontent.com:443,esm.sh:443,deno.land:443 --allow-net --allow-env --allow-read --allow-sys=hostname --allow-write=/var/tmp/youtubei.js src/main.ts"
|
||||
},
|
||||
"imports": {
|
||||
"hono": "jsr:@hono/hono@^4.6.5",
|
||||
"hono/logger": "jsr:@hono/hono@^4.6.5/logger",
|
||||
"hono/bearer-auth": "jsr:@hono/hono@^4.6.5/bearer-auth",
|
||||
"youtubei.js": "https://deno.land/x/youtubei@v11.0.1-deno/deno.ts",
|
||||
"youtubei.js/endpoints": "https://deno.land/x/youtubei@v11.0.1-deno/deno/src/core/endpoints/index.ts",
|
||||
"youtubei.js/Utils": "https://deno.land/x/youtubei@v11.0.1-deno/deno/src/utils/Utils.ts",
|
||||
"jsdom": "https://esm.sh/jsdom@25.0.1",
|
||||
"bgutils": "https://esm.sh/bgutils-js@3.0.0",
|
||||
"youtubei.js": "https://raw.githubusercontent.com/LuanRT/YouTube.js/refs/tags/v12.2.0-deno/deno.ts",
|
||||
"youtubei.js/Utils": "https://raw.githubusercontent.com/LuanRT/YouTube.js/refs/tags/v12.2.0-deno/deno/src/utils/Utils.ts",
|
||||
"youtubei.js/NavigationEndpoint": "https://raw.githubusercontent.com/LuanRT/YouTube.js/refs/tags/v12.2.0-deno/deno/src/parser/classes/NavigationEndpoint.ts",
|
||||
"jsdom": "npm:jsdom@25.0.1",
|
||||
"bgutils": "https://esm.sh/bgutils-js@3.1.0",
|
||||
"estree": "https://esm.sh/@types/estree@1.0.6",
|
||||
"@willsoto/node-konfig-core": "npm:@willsoto/node-konfig-core@5.0.0",
|
||||
"@willsoto/node-konfig-file": "npm:@willsoto/node-konfig-file@3.0.0",
|
||||
"@willsoto/node-konfig-toml-parser": "npm:@willsoto/node-konfig-toml-parser@3.0.0",
|
||||
"youtubePlayerReq": "./src/lib/helpers/youtubePlayerReq.ts",
|
||||
"getFetchClient": "./src/lib/helpers/getFetchClient.ts",
|
||||
"googlevideo": "npm:googlevideo@2.0.0"
|
||||
},
|
||||
"unstable": ["cron", "kv", "http"]
|
||||
|
|
41
src/lib/helpers/verifyRequest.ts
Normal file
41
src/lib/helpers/verifyRequest.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { Store } from "@willsoto/node-konfig-core";
|
||||
import { decodeBase64 } from "jsr:@std/encoding/base64";
|
||||
import { Aes } from "https://deno.land/x/crypto@v0.10.1/aes.ts";
|
||||
import {
|
||||
Ecb,
|
||||
Padding,
|
||||
} from "https://deno.land/x/crypto@v0.10.1/block-modes.ts";
|
||||
|
||||
export const verifyRequest = (
|
||||
stringToCheck: string,
|
||||
videoId: string,
|
||||
konfigStore: Store,
|
||||
): boolean => {
|
||||
try {
|
||||
const decipher = new Ecb(
|
||||
Aes,
|
||||
new TextEncoder().encode((
|
||||
Deno.env.get("SERVER_SECRET_KEY") ||
|
||||
konfigStore.get("server.secret_key") as string
|
||||
).substring(0, 16)),
|
||||
Padding.PKCS7,
|
||||
);
|
||||
|
||||
const encryptedData = new TextDecoder().decode(
|
||||
decipher.decrypt(decodeBase64(stringToCheck)),
|
||||
);
|
||||
const [parsedTimestamp, parsedVideoId] = encryptedData.split("|");
|
||||
const parsedTimestampInt = parseInt(parsedTimestamp);
|
||||
const timestampNow = Math.round(+new Date() / 1000);
|
||||
if (parsedVideoId !== videoId) {
|
||||
return false;
|
||||
}
|
||||
// only allow ID to live for 6 hours
|
||||
if ((timestampNow + 6 * 60 * 60) - parsedTimestampInt < 0) {
|
||||
return false;
|
||||
}
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
|
@ -1,10 +1,19 @@
|
|||
import { ApiResponse, Innertube, YT } from "youtubei.js";
|
||||
import { generateRandomString } from "youtubei.js/Utils";
|
||||
import { compress, decompress } from "https://deno.land/x/brotli@0.1.7/mod.ts";
|
||||
const { youtubePlayerReq } = await import(
|
||||
Deno.env.get("YT_PLAYER_REQ_LOCATION") || "./youtubePlayerReq.ts"
|
||||
);
|
||||
import { Store } from "@willsoto/node-konfig-core";
|
||||
let youtubePlayerReqLocation = "youtubePlayerReq";
|
||||
if (Deno.env.get("YT_PLAYER_REQ_LOCATION")) {
|
||||
if (Deno.env.has("DENO_COMPILED")) {
|
||||
youtubePlayerReqLocation = Deno.mainModule.replace("src/main.ts", "") +
|
||||
Deno.env.get("YT_PLAYER_REQ_LOCATION");
|
||||
} else {
|
||||
youtubePlayerReqLocation = Deno.env.get(
|
||||
"YT_PLAYER_REQ_LOCATION",
|
||||
) as string;
|
||||
}
|
||||
}
|
||||
const { youtubePlayerReq } = await import(youtubePlayerReqLocation);
|
||||
|
||||
const kv = await Deno.openKv();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Innertube, ApiResponse } from "youtubei.js";
|
||||
import { PlayerEndpoint } from "youtubei.js/endpoints";
|
||||
import { Store } from "@willsoto/node-konfig-core";
|
||||
import NavigationEndpoint from "youtubei.js/NavigationEndpoint";
|
||||
|
||||
export const youtubePlayerReq = async (innertubeClient: Innertube, videoId: string, konfigStore: Store): Promise<ApiResponse> => {
|
||||
const innertubeClientOauthEnabled = konfigStore.get(
|
||||
|
@ -11,13 +11,20 @@ export const youtubePlayerReq = async (innertubeClient: Innertube, videoId: stri
|
|||
if (innertubeClientOauthEnabled)
|
||||
innertubeClientUsed = "TV";
|
||||
|
||||
return await innertubeClient.actions.execute(
|
||||
PlayerEndpoint.PATH, PlayerEndpoint.build({
|
||||
video_id: videoId,
|
||||
// @ts-ignore Unable to import type InnerTubeClient
|
||||
client: innertubeClientUsed,
|
||||
sts: innertubeClient.session.player?.sts,
|
||||
po_token: innertubeClient.session.po_token
|
||||
})
|
||||
);
|
||||
const watch_endpoint = new NavigationEndpoint({ watchEndpoint: { videoId: videoId } });
|
||||
|
||||
return await watch_endpoint.call(innertubeClient.actions, {
|
||||
playbackContext: {
|
||||
contentPlaybackContext: {
|
||||
vis: 0,
|
||||
splay: false,
|
||||
lactMilliseconds: '-1',
|
||||
signatureTimestamp: innertubeClient.session.player?.sts
|
||||
}
|
||||
},
|
||||
serviceIntegrityDimensions: {
|
||||
poToken: innertubeClient.session.po_token
|
||||
},
|
||||
client: innertubeClientUsed
|
||||
});
|
||||
};
|
||||
|
|
|
@ -3,13 +3,24 @@ import type { BgConfig } from "bgutils";
|
|||
import { JSDOM } from "jsdom";
|
||||
import { Innertube, UniversalCache } from "youtubei.js";
|
||||
import { Store } from "@willsoto/node-konfig-core";
|
||||
const { getFetchClient } = await import(Deno.env.get("GET_FETCH_CLIENT_LOCATION") || "../helpers/getFetchClient.ts");
|
||||
let getFetchClientLocation = "getFetchClient";
|
||||
if (Deno.env.get("GET_FETCH_CLIENT_LOCATION")) {
|
||||
if (Deno.env.has("DENO_COMPILED")) {
|
||||
getFetchClientLocation = Deno.mainModule.replace("src/main.ts", "") +
|
||||
Deno.env.get("GET_FETCH_CLIENT_LOCATION");
|
||||
} else {
|
||||
getFetchClientLocation = Deno.env.get(
|
||||
"GET_FETCH_CLIENT_LOCATION",
|
||||
) as string;
|
||||
}
|
||||
}
|
||||
const { getFetchClient } = await import(getFetchClientLocation);
|
||||
|
||||
// Adapted from https://github.com/LuanRT/BgUtils/blob/main/examples/node/index.ts
|
||||
export const poTokenGenerate = async (
|
||||
innertubeClient: Innertube,
|
||||
konfigStore: Store<Record<string, unknown>>,
|
||||
innertubeClientCache: UniversalCache
|
||||
innertubeClientCache: UniversalCache,
|
||||
): Promise<Innertube> => {
|
||||
const requestKey = "O43z0dpjhgX20SCx4KAo";
|
||||
|
||||
|
@ -57,7 +68,7 @@ export const poTokenGenerate = async (
|
|||
bgConfig,
|
||||
});
|
||||
|
||||
await BG.PoToken.generatePlaceholder(visitorData);;
|
||||
await BG.PoToken.generatePlaceholder(visitorData);
|
||||
|
||||
return (await Innertube.create({
|
||||
po_token: poTokenResult.poToken,
|
||||
|
|
148
src/main.ts
148
src/main.ts
|
@ -3,7 +3,18 @@ import { routes } from "./routes/index.ts";
|
|||
import { Innertube, UniversalCache } from "youtubei.js";
|
||||
import { poTokenGenerate } from "./lib/jobs/potoken.ts";
|
||||
import { konfigLoader } from "./lib/helpers/konfigLoader.ts";
|
||||
const { getFetchClient } = await import(Deno.env.get("GET_FETCH_CLIENT_LOCATION") || "./lib/helpers/getFetchClient.ts");
|
||||
let getFetchClientLocation = "getFetchClient";
|
||||
if (Deno.env.get("GET_FETCH_CLIENT_LOCATION")) {
|
||||
if (Deno.env.has("DENO_COMPILED")) {
|
||||
getFetchClientLocation = Deno.mainModule.replace("src/main.ts", "") +
|
||||
Deno.env.get("GET_FETCH_CLIENT_LOCATION");
|
||||
} else {
|
||||
getFetchClientLocation = Deno.env.get(
|
||||
"GET_FETCH_CLIENT_LOCATION",
|
||||
) as string;
|
||||
}
|
||||
}
|
||||
const { getFetchClient } = await import(getFetchClientLocation);
|
||||
|
||||
const app = new Hono();
|
||||
const konfigStore = await konfigLoader();
|
||||
|
@ -11,100 +22,101 @@ const konfigStore = await konfigLoader();
|
|||
let innertubeClient: Innertube;
|
||||
let innertubeClientFetchPlayer = true;
|
||||
const innertubeClientOauthEnabled = konfigStore.get(
|
||||
"youtube_session.oauth_enabled",
|
||||
"youtube_session.oauth_enabled",
|
||||
) as boolean;
|
||||
const innertubeClientJobPoTokenEnabled = konfigStore.get(
|
||||
"jobs.youtube_session.po_token_enabled",
|
||||
"jobs.youtube_session.po_token_enabled",
|
||||
) as boolean;
|
||||
const innertubeClientCookies = konfigStore.get(
|
||||
"jobs.youtube_session.cookies",
|
||||
"jobs.youtube_session.cookies",
|
||||
) as string;
|
||||
let innertubeClientCache = new UniversalCache(
|
||||
true,
|
||||
konfigStore.get('cache.directory') as string + "/youtubei.js/",
|
||||
true,
|
||||
konfigStore.get("cache.directory") as string + "/youtubei.js/",
|
||||
) as UniversalCache;
|
||||
|
||||
Deno.env.set('TMPDIR', konfigStore.get("cache.directory") as string)
|
||||
Deno.env.set("TMPDIR", konfigStore.get("cache.directory") as string);
|
||||
|
||||
if (!innertubeClientOauthEnabled) {
|
||||
if (innertubeClientJobPoTokenEnabled) {
|
||||
console.log("[INFO] job po_token is active.");
|
||||
// Don't fetch fetch player yet for po_token
|
||||
innertubeClientFetchPlayer = false;
|
||||
} else if (!innertubeClientJobPoTokenEnabled) {
|
||||
console.log("[INFO] job po_token is NOT active.");
|
||||
}
|
||||
if (innertubeClientJobPoTokenEnabled) {
|
||||
console.log("[INFO] job po_token is active.");
|
||||
// Don't fetch fetch player yet for po_token
|
||||
innertubeClientFetchPlayer = false;
|
||||
} else if (!innertubeClientJobPoTokenEnabled) {
|
||||
console.log("[INFO] job po_token is NOT active.");
|
||||
}
|
||||
} else if (innertubeClientOauthEnabled) {
|
||||
// Can't use cache if using OAuth#cacheCredentials
|
||||
innertubeClientCache = new UniversalCache(false);
|
||||
// Can't use cache if using OAuth#cacheCredentials
|
||||
innertubeClientCache = new UniversalCache(false);
|
||||
}
|
||||
|
||||
innertubeClient = await Innertube.create({
|
||||
cache: innertubeClientCache,
|
||||
retrieve_player: innertubeClientFetchPlayer,
|
||||
fetch: getFetchClient(konfigStore),
|
||||
cookie: innertubeClientCookies || undefined,
|
||||
cache: innertubeClientCache,
|
||||
retrieve_player: innertubeClientFetchPlayer,
|
||||
fetch: getFetchClient(konfigStore),
|
||||
cookie: innertubeClientCookies || undefined,
|
||||
});
|
||||
|
||||
if (!innertubeClientOauthEnabled) {
|
||||
if (innertubeClientJobPoTokenEnabled) {
|
||||
innertubeClient = await poTokenGenerate(
|
||||
innertubeClient,
|
||||
konfigStore,
|
||||
innertubeClientCache as UniversalCache,
|
||||
);
|
||||
}
|
||||
Deno.cron(
|
||||
"regenerate youtube session",
|
||||
konfigStore.get("jobs.youtube_session.frequency") as string,
|
||||
async () => {
|
||||
if (innertubeClientJobPoTokenEnabled) {
|
||||
if (innertubeClientJobPoTokenEnabled) {
|
||||
innertubeClient = await poTokenGenerate(
|
||||
innertubeClient,
|
||||
konfigStore,
|
||||
innertubeClientCache,
|
||||
innertubeClient,
|
||||
konfigStore,
|
||||
innertubeClientCache as UniversalCache,
|
||||
);
|
||||
} else {
|
||||
innertubeClient = await Innertube.create({
|
||||
cache: innertubeClientCache,
|
||||
retrieve_player: innertubeClientFetchPlayer,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if (innertubeClientOauthEnabled) {
|
||||
// Fired when waiting for the user to authorize the sign in attempt.
|
||||
innertubeClient.session.on("auth-pending", (data) => {
|
||||
console.log(
|
||||
`[INFO] [OAUTH] Go to ${data.verification_url} in your browser and enter code ${data.user_code} to authenticate.`,
|
||||
}
|
||||
Deno.cron(
|
||||
"regenerate youtube session",
|
||||
konfigStore.get("jobs.youtube_session.frequency") as string,
|
||||
async () => {
|
||||
if (innertubeClientJobPoTokenEnabled) {
|
||||
innertubeClient = await poTokenGenerate(
|
||||
innertubeClient,
|
||||
konfigStore,
|
||||
innertubeClientCache,
|
||||
);
|
||||
} else {
|
||||
innertubeClient = await Innertube.create({
|
||||
cache: innertubeClientCache,
|
||||
retrieve_player: innertubeClientFetchPlayer,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
// Fired when authentication is successful.
|
||||
innertubeClient.session.on("auth", () => {
|
||||
console.log("[INFO] [OAUTH] Sign in successful!");
|
||||
});
|
||||
// Fired when the access token expires.
|
||||
innertubeClient.session.on("update-credentials", async () => {
|
||||
console.log("[INFO] [OAUTH] Credentials updated.");
|
||||
await innertubeClient.session.oauth.cacheCredentials();
|
||||
});
|
||||
} else if (innertubeClientOauthEnabled) {
|
||||
// Fired when waiting for the user to authorize the sign in attempt.
|
||||
innertubeClient.session.on("auth-pending", (data) => {
|
||||
console.log(
|
||||
`[INFO] [OAUTH] Go to ${data.verification_url} in your browser and enter code ${data.user_code} to authenticate.`,
|
||||
);
|
||||
});
|
||||
// Fired when authentication is successful.
|
||||
innertubeClient.session.on("auth", () => {
|
||||
console.log("[INFO] [OAUTH] Sign in successful!");
|
||||
});
|
||||
// Fired when the access token expires.
|
||||
innertubeClient.session.on("update-credentials", async () => {
|
||||
console.log("[INFO] [OAUTH] Credentials updated.");
|
||||
await innertubeClient.session.oauth.cacheCredentials();
|
||||
});
|
||||
|
||||
// Attempt to sign in and then cache the credentials
|
||||
await innertubeClient.session.signIn();
|
||||
await innertubeClient.session.oauth.cacheCredentials();
|
||||
// Attempt to sign in and then cache the credentials
|
||||
await innertubeClient.session.signIn();
|
||||
await innertubeClient.session.oauth.cacheCredentials();
|
||||
}
|
||||
|
||||
app.use("*", async (c, next) => {
|
||||
// @ts-ignore Do not understand how to fix this error.
|
||||
c.set("innertubeClient", innertubeClient);
|
||||
// @ts-ignore Do not understand how to fix this error.
|
||||
c.set("konfigStore", konfigStore);
|
||||
await next();
|
||||
// @ts-ignore Do not understand how to fix this error.
|
||||
c.set("innertubeClient", innertubeClient);
|
||||
// @ts-ignore Do not understand how to fix this error.
|
||||
c.set("konfigStore", konfigStore);
|
||||
await next();
|
||||
});
|
||||
|
||||
routes(app, konfigStore);
|
||||
|
||||
Deno.serve({
|
||||
port: Number(Deno.env.get("PORT")) || konfigStore.get("server.port") as number,
|
||||
hostname: Deno.env.get("HOST") || konfigStore.get("server.host") as string,
|
||||
port: Number(Deno.env.get("PORT")) ||
|
||||
konfigStore.get("server.port") as number,
|
||||
hostname: Deno.env.get("HOST") || konfigStore.get("server.host") as string,
|
||||
}, app.fetch);
|
||||
|
|
|
@ -6,12 +6,16 @@ import {
|
|||
youtubePlayerParsing,
|
||||
youtubeVideoInfo,
|
||||
} from "../../lib/helpers/youtubePlayerHandling.ts";
|
||||
import {
|
||||
verifyRequest
|
||||
} from "../../lib/helpers/verifyRequest.ts";
|
||||
import { HTTPException } from "hono/http-exception";
|
||||
|
||||
const dashManifest = new Hono<{ Variables: HonoVariables }>();
|
||||
|
||||
dashManifest.get("/:videoId", async (c) => {
|
||||
const { videoId } = c.req.param();
|
||||
const { local } = c.req.query();
|
||||
const { check, local } = c.req.query();
|
||||
c.header("access-control-allow-origin", "*");
|
||||
|
||||
const innertubeClient = await c.get("innertubeClient") as Innertube;
|
||||
|
@ -20,6 +24,18 @@ dashManifest.get("/:videoId", async (c) => {
|
|||
Record<string, unknown>
|
||||
>;
|
||||
|
||||
if (konfigStore.get("server.verify_requests") && check == undefined) {
|
||||
throw new HTTPException(400, {
|
||||
res: new Response("No check ID."),
|
||||
});
|
||||
} else if (konfigStore.get("server.verify_requests") && check) {
|
||||
if (verifyRequest(check, videoId, konfigStore) === false) {
|
||||
throw new HTTPException(400, {
|
||||
res: new Response("ID incorrect."),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const youtubePlayerResponseJson = await youtubePlayerParsing(
|
||||
innertubeClient,
|
||||
videoId,
|
||||
|
@ -44,7 +60,12 @@ dashManifest.get("/:videoId", async (c) => {
|
|||
.streaming_data.adaptive_formats
|
||||
.filter((i) => {
|
||||
if (i.mime_type.includes("mp4")) {
|
||||
if (i.has_video) {
|
||||
if (
|
||||
i.has_video &&
|
||||
JSON.stringify(
|
||||
videoInfo.streaming_data?.adaptive_formats,
|
||||
).includes("av01")
|
||||
) {
|
||||
if (i.mime_type.includes("av01")) {
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -7,11 +7,14 @@ import {
|
|||
youtubePlayerParsing,
|
||||
youtubeVideoInfo,
|
||||
} from "../../lib/helpers/youtubePlayerHandling.ts";
|
||||
import {
|
||||
verifyRequest
|
||||
} from "../../lib/helpers/verifyRequest.ts";
|
||||
|
||||
const latestVersion = new Hono<{ Variables: HonoVariables }>();
|
||||
|
||||
latestVersion.get("/", async (c) => {
|
||||
const { itag, id, local } = c.req.query();
|
||||
const { check, itag, id, local } = c.req.query();
|
||||
c.header("access-control-allow-origin", "*");
|
||||
|
||||
if (!id || !itag) {
|
||||
|
@ -26,6 +29,18 @@ latestVersion.get("/", async (c) => {
|
|||
Record<string, unknown>
|
||||
>;
|
||||
|
||||
if (konfigStore.get("server.verify_requests") && check == undefined) {
|
||||
throw new HTTPException(400, {
|
||||
res: new Response("No check ID."),
|
||||
});
|
||||
} else if (konfigStore.get("server.verify_requests") && check) {
|
||||
if (verifyRequest(check, id, konfigStore) === false) {
|
||||
throw new HTTPException(400, {
|
||||
res: new Response("ID incorrect."),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const youtubePlayerResponseJson = await youtubePlayerParsing(
|
||||
innertubeClient,
|
||||
id,
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
import { Hono } from "hono";
|
||||
import { Store } from "@willsoto/node-konfig-core";
|
||||
const { getFetchClient } = await import(Deno.env.get("GET_FETCH_CLIENT_LOCATION") || "../lib/helpers/getFetchClient.ts");
|
||||
import { HTTPException } from "hono/http-exception";
|
||||
let getFetchClientLocation = "getFetchClient";
|
||||
if (Deno.env.get("GET_FETCH_CLIENT_LOCATION")) {
|
||||
if (Deno.env.has("DENO_COMPILED")) {
|
||||
getFetchClientLocation = Deno.mainModule.replace("src/main.ts", "") +
|
||||
Deno.env.get("GET_FETCH_CLIENT_LOCATION");
|
||||
} else {
|
||||
getFetchClientLocation = Deno.env.get(
|
||||
"GET_FETCH_CLIENT_LOCATION",
|
||||
) as string;
|
||||
}
|
||||
}
|
||||
const { getFetchClient } = await import(getFetchClientLocation);
|
||||
|
||||
const videoPlaybackProxy = new Hono();
|
||||
|
||||
|
|
Loading…
Reference in a new issue