allow to set specific directory for cache + various envs

This commit is contained in:
Emilien 2024-11-01 21:00:30 +01:00
parent fa2fda8b72
commit be1f4bee39
11 changed files with 135 additions and 22 deletions

View file

@ -0,0 +1,72 @@
name: Build and Push Docker Image
# Define when this workflow will run
on:
push:
branches:
- master # Trigger on pushes to master branch
tags:
- '[0-9]+.[0-9]+.[0-9]+' # Trigger on semantic version tags
paths-ignore:
- 'Cargo.lock'
- 'LICENSE'
- 'README.md'
- 'docker-compose.yml'
workflow_dispatch: # Allow manual triggering of the workflow
# Define environment variables used throughout the workflow
env:
REGISTRY: quay.io
IMAGE_NAME: invidious/invidious-companion
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
# Step 1: Check out the repository code
- name: Checkout code
uses: actions/checkout@v3
# Step 2: Set up QEMU for multi-architecture builds
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
# Step 3: Set up Docker Buildx for enhanced build capabilities
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# Step 4: Authenticate with Quay.io registry
- name: Log in to Quay.io
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
# Step 5: Extract metadata for Docker image tagging and labeling
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Define tagging strategy
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
type=sha,prefix={{branch}}-
# Define labels
labels: |
quay.expires-after=12w
# Step 6: Build and push the Docker image
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
platforms: linux/amd64,linux/arm64 # Build for multiple architectures
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View file

@ -26,6 +26,9 @@ COPY --from=builder /app/invidious_companion /app/
COPY ./config/ /app/config/
COPY --from=builder /tini /tini
ENV PORT=8282 \
HOST=0.0.0.0
# Copy passwd file for the non-privileged user from the user-stage
COPY --from=user-stage /etc/passwd /etc/passwd

View file

@ -6,6 +6,9 @@ base_url = "http://localhost:8282"
[cache]
enabled = true
# will get cached in /var/tmp/youtubei.js if you specify /var/tmp
# you need to change the --allow-write from deno run too
directory = "/var/tmp"
[networking]
#proxy = ""

View file

@ -1,7 +1,7 @@
{
"tasks": {
"dev": "deno run --allow-net --allow-env --allow-read --allow-sys=hostname --allow-write=./,/tmp/youtubei.js --watch src/main.ts",
"compile": "deno compile --output invidious_companion --allow-net --allow-env --allow-sys=hostname --allow-read src/main.ts"
"dev": "deno run --allow-net --allow-env --allow-sys=hostname --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"
},
"imports": {
"hono": "jsr:@hono/hono@^4.6.5",
@ -9,9 +9,10 @@
"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",
"estree": "npm:@types/estree",
"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",

View file

@ -740,7 +740,6 @@
"workspace": {
"dependencies": [
"jsr:@hono/hono@^4.6.5",
"npm:@types/estree",
"npm:@willsoto/node-konfig-core@5.0.0",
"npm:@willsoto/node-konfig-file@3.0.0",
"npm:@willsoto/node-konfig-toml-parser@3.0.0"

19
docker-compose.yaml Normal file
View file

@ -0,0 +1,19 @@
version: "3"
services:
invidious_companion:
build:
context: .
dockerfile: Dockerfile
# image: quay.io/invidious/invidious-companion:latest
ports:
- 127.0.0.1:8282:8282
restart: unless-stopped
cap_drop:
- ALL
read_only: true
user: 10001:10001
# cache for youtube library
volumes:
- /var/tmp/youtubei.js:/var/tmp/youtubei.js:rw
security_opt:
- no-new-privileges:true

View file

@ -6,14 +6,14 @@ export const getFetchClient = (konfigStore: Store): {
client: Deno.HttpClient;
}): Promise<Response>;
} => {
if (konfigStore.get("networking.proxy")) {
if (Deno.env.get("PROXY") || konfigStore.get("networking.proxy")) {
return async (
input: RequestInfo | URL,
init?: RequestInit,
) => {
const client = Deno.createHttpClient({
proxy: {
url: konfigStore.get("networking.proxy") as string,
url: Deno.env.get("PROXY") || konfigStore.get("networking.proxy") as string,
},
});
const fetchRes = await fetch(input, {

View file

@ -1,4 +1,5 @@
import { Innertube, YT, ApiResponse } from "youtubei.js";
import { generateRandomString } from "youtubei.js/Utils";
import { compress, decompress } from "https://deno.land/x/brotli@0.1.7/mod.ts";
import { youtubePlayerReq } from "youtubePlayerReq";
import { Store } from "@willsoto/node-konfig-core";
@ -28,7 +29,7 @@ export const youtubePlayerParsing = async (
const video = new YT.VideoInfo(
[youtubePlayerResponse],
innertubeClient.actions,
"",
generateRandomString(16),
);
const streamingData = video.streaming_data;
@ -89,7 +90,7 @@ export const youtubePlayerParsing = async (
videoDetails,
microformat,
invidiousCompanion: {
"baseUrl": konfigStore.get("server.base_url") as string,
"baseUrl": Deno.env.get("SERVER_BASE_URL") || konfigStore.get("server.base_url") as string,
},
}))(videoData);

View file

@ -9,6 +9,7 @@ import { getFetchClient } from "../helpers/getFetchClient.ts";
export const poTokenGenerate = async (
innertubeClient: Innertube,
konfigStore: Store<Record<string, unknown>>,
innertubeClientCache: UniversalCache
): Promise<Innertube> => {
const requestKey = "O43z0dpjhgX20SCx4KAo";
@ -62,7 +63,7 @@ export const poTokenGenerate = async (
po_token: poTokenResult.poToken,
visitor_data: visitorData,
fetch: getFetchClient(konfigStore),
cache: new UniversalCache(true),
cache: innertubeClientCache,
generate_session_locally: true,
}));
};

View file

@ -6,11 +6,9 @@ import { konfigLoader } from "./lib/helpers/konfigLoader.ts";
import { getFetchClient } from "./lib/helpers/getFetchClient.ts";
const app = new Hono();
const konfigStore = await konfigLoader();
let innertubeClient: Innertube;
let innertubeClientUniversalCache = true;
let innertubeClientFetchPlayer = true;
const innertubeClientOauthEnabled = konfigStore.get(
"youtube_session.oauth_enabled",
@ -21,6 +19,12 @@ const innertubeClientJobPoTokenEnabled = konfigStore.get(
const innertubeClientCookies = konfigStore.get(
"jobs.youtube_session.cookies",
) as string;
let innertubeClientCache = new UniversalCache(
true,
konfigStore.get('cache.directory') as string + "/youtubei.js/",
) as UniversalCache;
Deno.env.set('TMPDIR', konfigStore.get("cache.directory") as string)
if (!innertubeClientOauthEnabled) {
if (innertubeClientJobPoTokenEnabled) {
@ -32,29 +36,37 @@ if (!innertubeClientOauthEnabled) {
}
} else if (innertubeClientOauthEnabled) {
// Can't use cache if using OAuth#cacheCredentials
innertubeClientUniversalCache = false;
innertubeClientCache = new UniversalCache(false);
}
innertubeClient = await Innertube.create({
cache: new UniversalCache(innertubeClientUniversalCache),
cache: innertubeClientCache,
retrieve_player: innertubeClientFetchPlayer,
fetch: getFetchClient(konfigStore),
cookie: innertubeClientCookies || undefined
cookie: innertubeClientCookies || undefined,
});
if (!innertubeClientOauthEnabled) {
if (innertubeClientOauthEnabled) {
innertubeClient = await poTokenGenerate(innertubeClient, konfigStore);
innertubeClient = await poTokenGenerate(
innertubeClient,
konfigStore,
innertubeClientCache as UniversalCache,
);
}
Deno.cron(
"regenerate youtube session",
konfigStore.get("jobs.youtube_session.frequency") as string,
async () => {
if (innertubeClientOauthEnabled) {
innertubeClient = await poTokenGenerate(innertubeClient, konfigStore);
innertubeClient = await poTokenGenerate(
innertubeClient,
konfigStore,
innertubeClientCache,
);
} else {
innertubeClient = await Innertube.create({
cache: new UniversalCache(innertubeClientUniversalCache),
cache: innertubeClientCache,
retrieve_player: innertubeClientFetchPlayer,
});
}
@ -62,8 +74,10 @@ if (!innertubeClientOauthEnabled) {
);
} else if (innertubeClientOauthEnabled) {
// Fired when waiting for the user to authorize the sign in attempt.
innertubeClient.session.on('auth-pending', (data) => {
console.log(`Go to ${data.verification_url} in your browser and enter code ${data.user_code} to authenticate.`);
innertubeClient.session.on("auth-pending", (data) => {
console.log(
`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", () => {
@ -91,6 +105,6 @@ app.use("*", async (c, next) => {
routes(app, konfigStore);
Deno.serve({
port: konfigStore.get("server.port") as number,
hostname: 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);

View file

@ -13,7 +13,7 @@ export const routes = (app: Hono, konfigStore: Store<Record<string, unknown>>) =
app.use(
"/youtubei/v1/*",
bearerAuth({
token: konfigStore.get("server.hmac_key") as string,
token: Deno.env.get("SERVER_HMAC_KEY") || konfigStore.get("server.hmac_key") as string,
}),
);