add support for prometheus metrics
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 54s

This commit is contained in:
Fijxu 2024-12-17 21:49:13 -03:00
parent f73ed00b6d
commit 9f579c806a
Signed by: Fijxu
GPG key ID: 32C1DDF333EDA6A4
6 changed files with 101 additions and 4 deletions

View file

@ -7,6 +7,7 @@
"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",
"prom-client": "npm:prom-client@^15.1.3",
"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",

View file

@ -2,6 +2,7 @@ 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";
import { Store } from "@willsoto/node-konfig-core";
import { cachedEntries } from "../../routes/index.ts";
let youtubePlayerReqLocation = "youtubePlayerReq";
if (Deno.env.get("YT_PLAYER_REQ_LOCATION")) {
if (Deno.env.has("DENO_COMPILED")) {
@ -134,6 +135,7 @@ export const youtubePlayerParsing = async (
expireIn: 1000 * 60 * 60,
},
);
cachedEntries.inc()
})();
}

View file

@ -3,6 +3,7 @@ import type { BgConfig } from "bgutils";
import { JSDOM } from "jsdom";
import { Innertube, UniversalCache } from "youtubei.js";
import { Store } from "@willsoto/node-konfig-core";
import { poTokenFail, externalTokenGeneratorFail } from "../../routes/index.ts";
let getFetchClientLocation = "getFetchClient";
if (Deno.env.get("GET_FETCH_CLIENT_LOCATION")) {
if (Deno.env.has("DENO_COMPILED")) {
@ -70,6 +71,7 @@ export const poTokenGenerate = async (
e,
);
console.log("poTokenGenerate: Using built-in token generator");
externalTokenGeneratorFail.inc()
}
}
@ -100,6 +102,7 @@ export const poTokenGenerate = async (
const bgChallenge = await BG.Challenge.create(bgConfig);
if (!bgChallenge) {
poTokenFail.inc()
throw new Error("Could not get challenge");
}
@ -108,7 +111,10 @@ export const poTokenGenerate = async (
if (interpreterJavascript) {
new Function(interpreterJavascript)();
} else throw new Error("Could not load VM");
} else {
poTokenFail.inc()
throw new Error("Could not load VM");
}
const poTokenResult = await BG.PoToken.generate({
program: bgChallenge.program,

View file

@ -2,11 +2,58 @@ import { Hono } from "hono";
import { logger } from "hono/logger";
import { Store } from "@willsoto/node-konfig-core";
import { bearerAuth } from "hono/bearer-auth";
import { Registry, Counter } from "prom-client"
import youtubeApiPlayer from "./youtube_api_routes/player.ts";
import invidiousRouteLatestVersion from "./invidious_routes/latestVersion.ts";
import invidiousRouteDashManifest from "./invidious_routes/dashManifest.ts";
import videoPlaybackProxy from "./videoPlaybackProxy.ts";
import metrics from "./metrics.ts";
const METRICS_PREFIX = "invidious_companion_";
export const register = new Registry();
export const externalTokenGeneratorFail = new Counter({
name: `${METRICS_PREFIX}externaltokengenerator_fail`,
help: 'TODO',
registers: [register]
});
export const cachedEntries = new Counter({
name: `${METRICS_PREFIX}cached_entries`,
help: 'TODO',
registers: [register]
});
export const subreasonProtectCommunity = new Counter({
name: `${METRICS_PREFIX}subreason_protect_community`,
help: 'TODO',
registers: [register]
});
export const poTokenFail = new Counter({
name: `${METRICS_PREFIX}potoken_fail`,
help: 'TODO',
registers: [register]
});
export const reasonBot = new Counter({
name: `${METRICS_PREFIX}reason_bot`,
help: 'TODO',
registers: [register]
});
export const videoUnavailable = new Counter({
name: `${METRICS_PREFIX}video_unavailable`,
help: 'TODO',
registers: [register]
});
export const videoRestricted = new Counter({
name: `${METRICS_PREFIX}video_restricted`,
help: 'TODO',
registers: [register]
});
export const routes = (app: Hono, konfigStore: Store<Record<string, unknown>>) => {
app.use("*", logger());
@ -22,4 +69,5 @@ export const routes = (app: Hono, konfigStore: Store<Record<string, unknown>>) =
app.route("/latest_version", invidiousRouteLatestVersion);
app.route("/api/manifest/dash/id", invidiousRouteDashManifest);
app.route("/videoplayback", videoPlaybackProxy);
app.route("/metrics", metrics)
};

12
src/routes/metrics.ts Normal file
View file

@ -0,0 +1,12 @@
import { Hono } from "hono";
import { register } from "./index.ts";
const metrics = new Hono();
metrics.get("/", async () => {
return new Response(await register.metrics(), {
headers: { "Content-Type": "text/plain" },
});
});
export default metrics;

View file

@ -3,9 +3,33 @@ import { youtubePlayerParsing } from "../../lib/helpers/youtubePlayerHandling.ts
import { HonoVariables } from "../../lib/types/HonoVariables.ts";
import { Innertube } from "youtubei.js";
import { Store } from "@willsoto/node-konfig-core";
import { reasonBot, subreasonProtectCommunity, videoRestricted, videoUnavailable } from "../index.ts";
const player = new Hono<{ Variables: HonoVariables }>();
const errors = [
{
// @ts-ignore: Property 'playabilityStatus' does not exist on type 'object'
check: (yt: object) => yt.playabilityStatus?.reason?.includes("Sign in to confirm youre not a bot"),
action: () => reasonBot.inc(),
},
{
// @ts-ignore: Property 'playabilityStatus' does not exist on type 'object'
check: (yt: object) => yt.playabilityStatus?.errorScreen?.playerErrorMessageRenderer?.subreason?.runs?.[0]?.text?.includes("This helps protect our community"),
action: () => subreasonProtectCommunity.inc(),
},
{
// @ts-ignore: Property 'playabilityStatus' does not exist on type 'object'
check: (yt: object) => yt.playabilityStatus?.errorScreen?.playerErrorMessageRenderer?.subreason?.runs?.[0]?.text?.includes("Video unavailable"),
action: () => videoUnavailable.inc(),
},
{
// @ts-ignore: Property 'playabilityStatus' does not exist on type 'object'
check: (yt: object) => yt.playabilityStatus?.reason?.includes("This video is restricted"),
action: () => videoRestricted.inc(),
},
];
player.post("/player", async (c) => {
const jsonReq = await c.req.json();
const innertubeClient = await c.get("innertubeClient") as Innertube;
@ -14,9 +38,13 @@ player.post("/player", async (c) => {
Record<string, unknown>
>;
if (jsonReq.videoId) {
return c.json(
await youtubePlayerParsing(innertubeClient, jsonReq.videoId, konfigStore)
);
const yt = await youtubePlayerParsing(innertubeClient, jsonReq.videoId, konfigStore)
errors.forEach((error) => {
if (error.check(yt)) {
error.action()
}
})
return c.json(yt);
}
});