mirror of
https://git.nerdvpn.de/NerdVPN.de/invidious
synced 2026-02-14 22:51:42 +01:00
291 lines
10 KiB
Diff
291 lines
10 KiB
Diff
From 6953eed8bd7dfb68244947dbdd274a23ad501743 Mon Sep 17 00:00:00 2001
|
|
From: Fijxu <fijxu@nadeko.net>, weidenwiesel <webmaster@nerdvpn.de>
|
|
Date: Mon, 13 Oct 2025 10:26:32 +0200
|
|
Subject: [PATCH 4/4] [Patch] 004 - store companion status
|
|
|
|
---
|
|
src/constants.ts | 3 +++
|
|
src/lib/helpers/companionStatus.ts | 33 +++++++++++++++++++++++++
|
|
src/lib/jobs/potoken.ts | 7 ++++++
|
|
src/lib/types/HonoVariables.ts | 2 ++
|
|
src/main.ts | 6 +++++
|
|
src/routes/index.ts | 2 ++
|
|
src/routes/status.ts | 26 +++++++++++++++++++
|
|
src/routes/youtube_api_routes/player.ts | 25 ++++++++++++++++++-
|
|
8 files changed, 103 insertions(+), 1 deletion(-)
|
|
create mode 100644 src/lib/helpers/companionStatus.ts
|
|
create mode 100644 src/routes/status.ts
|
|
|
|
diff --git a/src/constants.ts b/src/constants.ts
|
|
index 973d1a1..5c14d06 100644
|
|
--- a/src/constants.ts
|
|
+++ b/src/constants.ts
|
|
@@ -8,4 +8,6 @@ export const PLAYER_ID = undefined;
|
|
|
|
// Error message shown when tokenMinter is not yet ready
|
|
export const TOKEN_MINTER_NOT_READY_MESSAGE =
|
|
- "Companion is starting. Please wait until a valid potoken is found. If this process takes too long, please consult: https://docs.invidious.io/youtube-errors-explained/#po-token-initialization-taking-too-much-time-to-complete";
|
|
+ "This backend is still starting and not yet available. Please wait for a short time or use another backend.";
|
|
+export const COMPANION_BLOCKED_MESSAGE =
|
|
+ "This backend is blocked by Youtube. Please wait until it has refreshed itself or switch to another backend."
|
|
diff --git a/src/lib/jobs/potoken.ts b/src/lib/jobs/potoken.ts
|
|
index a2616da..718eedd 100644
|
|
--- a/src/lib/jobs/potoken.ts
|
|
+++ b/src/lib/jobs/potoken.ts
|
|
@@ -20,6 +20,7 @@ const { getFetchClient } = await import(getFetchClientLocation);
|
|
|
|
import { InputMessage, OutputMessageSchema } from "./worker.ts";
|
|
import { PLAYER_ID } from "../../constants.ts";
|
|
+import { CompanionStatus } from "../helpers/companionStatus.ts";
|
|
|
|
interface TokenGeneratorWorker extends Omit<Worker, "postMessage"> {
|
|
postMessage(message: InputMessage): void;
|
|
@@ -61,6 +62,7 @@ export type TokenMinter = ReturnType<typeof createMinter>;
|
|
export const poTokenGenerate = (
|
|
config: Config,
|
|
metrics: Metrics | undefined,
|
|
+ companionStatus: CompanionStatus,
|
|
): Promise<{ innertubeClient: Innertube; tokenMinter: TokenMinter }> => {
|
|
const { promise, resolve, reject } = Promise.withResolvers<
|
|
Awaited<ReturnType<typeof poTokenGenerate>>
|
|
@@ -111,6 +113,7 @@ export const poTokenGenerate = (
|
|
config,
|
|
integrityTokenBasedMinter: minter,
|
|
metrics,
|
|
+ companionStatus,
|
|
});
|
|
console.log("[INFO] Successfully generated PO token");
|
|
const numberToKill = workers.length - 1;
|
|
@@ -118,11 +121,13 @@ export const poTokenGenerate = (
|
|
const workerToKill = workers.shift();
|
|
workerToKill?.terminate();
|
|
}
|
|
+ companionStatus.setStatusOK();
|
|
return resolve({
|
|
innertubeClient: instantiatedInnertubeClient,
|
|
tokenMinter: minter,
|
|
});
|
|
} catch (err) {
|
|
+ companionStatus.setStatusBlocked();
|
|
console.log("[WARN] Failed to get valid PO token, will retry", {
|
|
err,
|
|
});
|
|
@@ -140,11 +145,13 @@ async function checkToken({
|
|
config,
|
|
integrityTokenBasedMinter,
|
|
metrics,
|
|
+ companionStatus,
|
|
}: {
|
|
instantiatedInnertubeClient: Innertube;
|
|
config: Config;
|
|
integrityTokenBasedMinter: TokenMinter;
|
|
metrics: Metrics | undefined;
|
|
+ companionStatus: CompanionStatus;
|
|
}) {
|
|
const fetchImpl = getFetchClient(config);
|
|
|
|
diff --git a/src/lib/types/HonoVariables.ts b/src/lib/types/HonoVariables.ts
|
|
index f1e64d5..8b5c6a1 100644
|
|
--- a/src/lib/types/HonoVariables.ts
|
|
+++ b/src/lib/types/HonoVariables.ts
|
|
@@ -2,10 +2,12 @@ import { Innertube } from "youtubei.js";
|
|
import type { TokenMinter } from "../jobs/potoken.ts";
|
|
import type { Config } from "../helpers/config.ts";
|
|
import { Metrics } from "../helpers/metrics.ts";
|
|
+import { CompanionStatus } from "../helpers/companionStatus.ts";
|
|
|
|
export type HonoVariables = {
|
|
innertubeClient: Innertube;
|
|
config: Config;
|
|
tokenMinter: TokenMinter | undefined;
|
|
metrics: Metrics | undefined;
|
|
+ companionStatus: CompanionStatus;
|
|
};
|
|
diff --git a/src/main.ts b/src/main.ts
|
|
index 7bbe819..5dee6b6 100644
|
|
--- a/src/main.ts
|
|
+++ b/src/main.ts
|
|
@@ -13,6 +13,7 @@ const config = await parseConfig();
|
|
import { Metrics } from "./lib/helpers/metrics.ts";
|
|
import { PLAYER_ID } from "./constants.ts";
|
|
import { jsInterpreter } from "./lib/helpers/jsInterpreter.ts";
|
|
+import { CompanionStatus } from "./lib/helpers/companionStatus.ts";
|
|
|
|
const args = parseArgs(Deno.args);
|
|
|
|
@@ -46,6 +47,7 @@ const companionApp = new Hono({
|
|
getPath: (req) => new URL(req.url).pathname,
|
|
}).basePath(config.server.base_path);
|
|
const metrics = config.server.enable_metrics ? new Metrics() : undefined;
|
|
+const companionStatus = new CompanionStatus();
|
|
|
|
let tokenMinter: TokenMinter | undefined;
|
|
let innertubeClient: Innertube;
|
|
@@ -91,6 +93,7 @@ if (!innertubeClientOauthEnabled) {
|
|
poTokenGenerate,
|
|
config,
|
|
metrics,
|
|
+ companionStatus,
|
|
),
|
|
{ minTimeout: 1_000, maxTimeout: 60_000, multiplier: 5, jitter: 0 },
|
|
).then((result) => {
|
|
@@ -116,6 +119,7 @@ if (!innertubeClientOauthEnabled) {
|
|
({ innertubeClient, tokenMinter } = await poTokenGenerate(
|
|
config,
|
|
metrics,
|
|
+ companionStatus,
|
|
));
|
|
} catch (err) {
|
|
metrics?.potokenGenerationFailure.inc();
|
|
@@ -162,6 +166,7 @@ companionApp.use("*", async (c, next) => {
|
|
c.set("tokenMinter", tokenMinter);
|
|
c.set("config", config);
|
|
c.set("metrics", metrics);
|
|
+ c.set("companionStatus", companionStatus);
|
|
await next();
|
|
});
|
|
companionRoutes(companionApp, config);
|
|
diff --git a/src/routes/index.ts b/src/routes/index.ts
|
|
index 09cd4ff..5113811 100644
|
|
--- a/src/routes/index.ts
|
|
+++ b/src/routes/index.ts
|
|
@@ -11,6 +11,7 @@ import videoPlaybackProxy from "./videoPlaybackProxy.ts";
|
|
import type { Config } from "../lib/helpers/config.ts";
|
|
import metrics from "./metrics.ts";
|
|
import health from "./health.ts";
|
|
+import status from "./status.ts";
|
|
|
|
export const customLogger = () => {
|
|
return;
|
|
@@ -53,6 +54,7 @@ export const miscRoutes = (
|
|
config: Config,
|
|
) => {
|
|
app.route("/healthz", health);
|
|
+ app.route("/status", status);
|
|
if (config.server.enable_metrics) {
|
|
app.route("/metrics", metrics);
|
|
}
|
|
diff --git a/src/routes/youtube_api_routes/player.ts b/src/routes/youtube_api_routes/player.ts
|
|
index f416fa6..c8d5d0d 100644
|
|
--- a/src/routes/youtube_api_routes/player.ts
|
|
+++ b/src/routes/youtube_api_routes/player.ts
|
|
@@ -2,7 +2,10 @@ import { Hono } from "hono";
|
|
import { youtubePlayerParsing } from "../../lib/helpers/youtubePlayerHandling.ts";
|
|
import { HTTPException } from "hono/http-exception";
|
|
import { validateVideoId } from "../../lib/helpers/validateVideoId.ts";
|
|
-import { TOKEN_MINTER_NOT_READY_MESSAGE } from "../../constants.ts";
|
|
+import {
|
|
+ COMPANION_BLOCKED_MESSAGE,
|
|
+ TOKEN_MINTER_NOT_READY_MESSAGE,
|
|
+} from "../../constants.ts";
|
|
|
|
const player = new Hono();
|
|
|
|
@@ -12,6 +15,7 @@ player.post("/player", async (c) => {
|
|
const config = c.get("config");
|
|
const metrics = c.get("metrics");
|
|
const tokenMinter = c.get("tokenMinter");
|
|
+ const companionStatus = c.get("companionStatus");
|
|
|
|
// Check if tokenMinter is ready (only needed when PO token is enabled)
|
|
if (config.jobs.youtube_session.po_token_enabled && !tokenMinter) {
|
|
@@ -33,6 +37,25 @@ player.post("/player", async (c) => {
|
|
});
|
|
}
|
|
|
|
+ if (companionStatus.isBlocked()) {
|
|
+ return c.json({
|
|
+ playabilityStatus: {
|
|
+ status: "ERROR",
|
|
+ reason: COMPANION_BLOCKED_MESSAGE,
|
|
+ errorScreen: {
|
|
+ playerErrorMessageRenderer: {
|
|
+ reason: {
|
|
+ simpleText: COMPANION_BLOCKED_MESSAGE,
|
|
+ },
|
|
+ subreason: {
|
|
+ simpleText: COMPANION_BLOCKED_MESSAGE,
|
|
+ },
|
|
+ },
|
|
+ },
|
|
+ },
|
|
+ });
|
|
+ }
|
|
+
|
|
if (jsonReq.videoId) {
|
|
if (!validateVideoId(jsonReq.videoId)) {
|
|
throw new HTTPException(400, {
|
|
diff --git a/src/lib/helpers/companionStatus.ts b/src/lib/helpers/companionStatus.ts
|
|
new file mode 100644
|
|
index 0000000..cf01fe5
|
|
--- /dev/null
|
|
+++ b/src/lib/helpers/companionStatus.ts
|
|
@@ -0,0 +1,33 @@
|
|
+enum Status {
|
|
+ Blocked,
|
|
+ OK,
|
|
+}
|
|
+
|
|
+export class CompanionStatus {
|
|
+ private currentStatus: Status = Status.OK;
|
|
+ private _blockedCount: number = 0;
|
|
+
|
|
+ public getBlockedCount(): number {
|
|
+ return this._blockedCount;
|
|
+ }
|
|
+
|
|
+ public isBlocked(): boolean {
|
|
+ if (this.currentStatus == Status.Blocked) {
|
|
+ return true;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public setStatusOK(): void {
|
|
+ console.log("[INFO] status set to OK");
|
|
+ this._blockedCount = 0;
|
|
+ this.currentStatus = Status.OK;
|
|
+ }
|
|
+
|
|
+ public setStatusBlocked(): void {
|
|
+ console.log("[INFO] status set to BLOCKED");
|
|
+ this._blockedCount++;
|
|
+ this.currentStatus = Status.Blocked;
|
|
+ }
|
|
+}
|
|
diff --git a/src/routes/status.ts b/src/routes/status.ts
|
|
new file mode 100644
|
|
index 0000000..61149b9
|
|
--- /dev/null
|
|
+++ b/src/routes/status.ts
|
|
@@ -0,0 +1,26 @@
|
|
+import { Hono } from "hono";
|
|
+
|
|
+const status = new Hono();
|
|
+
|
|
+interface Data {
|
|
+ blocked: boolean;
|
|
+ blockedCount: number;
|
|
+}
|
|
+
|
|
+status.get("/", (c) => {
|
|
+ const companionStatus = c.get("companionStatus");
|
|
+
|
|
+ const data: Data = {
|
|
+ blocked: companionStatus.isBlocked(),
|
|
+ blockedCount: companionStatus.getBlockedCount(),
|
|
+ };
|
|
+
|
|
+ const responseBody = JSON.stringify(data);
|
|
+
|
|
+ return new Response(responseBody, {
|
|
+ status: 200,
|
|
+ headers: { "Content-Type": "application/json" },
|
|
+ });
|
|
+});
|
|
+
|
|
+export default status;
|
|
--
|
|
2.52.0
|