add support for prometheus metrics
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 54s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 54s
This commit is contained in:
parent
f73ed00b6d
commit
9f579c806a
6 changed files with 101 additions and 4 deletions
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
})();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
12
src/routes/metrics.ts
Normal 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;
|
|
@ -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 you’re 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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue