allow to set specific directory for cache + various envs
This commit is contained in:
parent
fa2fda8b72
commit
be1f4bee39
11 changed files with 135 additions and 22 deletions
72
.github/workflows/docker-build-push.yaml
vendored
Normal file
72
.github/workflows/docker-build-push.yaml
vendored
Normal 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 }}
|
|
@ -26,6 +26,9 @@ COPY --from=builder /app/invidious_companion /app/
|
||||||
COPY ./config/ /app/config/
|
COPY ./config/ /app/config/
|
||||||
COPY --from=builder /tini /tini
|
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 passwd file for the non-privileged user from the user-stage
|
||||||
COPY --from=user-stage /etc/passwd /etc/passwd
|
COPY --from=user-stage /etc/passwd /etc/passwd
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ base_url = "http://localhost:8282"
|
||||||
|
|
||||||
[cache]
|
[cache]
|
||||||
enabled = true
|
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]
|
[networking]
|
||||||
#proxy = ""
|
#proxy = ""
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"dev": "deno run --allow-net --allow-env --allow-read --allow-sys=hostname --allow-write=./,/tmp/youtubei.js --watch 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-sys=hostname --allow-read 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": {
|
"imports": {
|
||||||
"hono": "jsr:@hono/hono@^4.6.5",
|
"hono": "jsr:@hono/hono@^4.6.5",
|
||||||
|
@ -9,9 +9,10 @@
|
||||||
"hono/bearer-auth": "jsr:@hono/hono@^4.6.5/bearer-auth",
|
"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": "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/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",
|
"jsdom": "https://esm.sh/jsdom@25.0.1",
|
||||||
"bgutils": "https://esm.sh/bgutils-js@3.0.0",
|
"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-core": "npm:@willsoto/node-konfig-core@5.0.0",
|
||||||
"@willsoto/node-konfig-file": "npm:@willsoto/node-konfig-file@3.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",
|
"@willsoto/node-konfig-toml-parser": "npm:@willsoto/node-konfig-toml-parser@3.0.0",
|
||||||
|
|
|
@ -740,7 +740,6 @@
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"jsr:@hono/hono@^4.6.5",
|
"jsr:@hono/hono@^4.6.5",
|
||||||
"npm:@types/estree",
|
|
||||||
"npm:@willsoto/node-konfig-core@5.0.0",
|
"npm:@willsoto/node-konfig-core@5.0.0",
|
||||||
"npm:@willsoto/node-konfig-file@3.0.0",
|
"npm:@willsoto/node-konfig-file@3.0.0",
|
||||||
"npm:@willsoto/node-konfig-toml-parser@3.0.0"
|
"npm:@willsoto/node-konfig-toml-parser@3.0.0"
|
||||||
|
|
19
docker-compose.yaml
Normal file
19
docker-compose.yaml
Normal 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
|
|
@ -6,14 +6,14 @@ export const getFetchClient = (konfigStore: Store): {
|
||||||
client: Deno.HttpClient;
|
client: Deno.HttpClient;
|
||||||
}): Promise<Response>;
|
}): Promise<Response>;
|
||||||
} => {
|
} => {
|
||||||
if (konfigStore.get("networking.proxy")) {
|
if (Deno.env.get("PROXY") || konfigStore.get("networking.proxy")) {
|
||||||
return async (
|
return async (
|
||||||
input: RequestInfo | URL,
|
input: RequestInfo | URL,
|
||||||
init?: RequestInit,
|
init?: RequestInit,
|
||||||
) => {
|
) => {
|
||||||
const client = Deno.createHttpClient({
|
const client = Deno.createHttpClient({
|
||||||
proxy: {
|
proxy: {
|
||||||
url: konfigStore.get("networking.proxy") as string,
|
url: Deno.env.get("PROXY") || konfigStore.get("networking.proxy") as string,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const fetchRes = await fetch(input, {
|
const fetchRes = await fetch(input, {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Innertube, YT, ApiResponse } from "youtubei.js";
|
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 { compress, decompress } from "https://deno.land/x/brotli@0.1.7/mod.ts";
|
||||||
import { youtubePlayerReq } from "youtubePlayerReq";
|
import { youtubePlayerReq } from "youtubePlayerReq";
|
||||||
import { Store } from "@willsoto/node-konfig-core";
|
import { Store } from "@willsoto/node-konfig-core";
|
||||||
|
@ -28,7 +29,7 @@ export const youtubePlayerParsing = async (
|
||||||
const video = new YT.VideoInfo(
|
const video = new YT.VideoInfo(
|
||||||
[youtubePlayerResponse],
|
[youtubePlayerResponse],
|
||||||
innertubeClient.actions,
|
innertubeClient.actions,
|
||||||
"",
|
generateRandomString(16),
|
||||||
);
|
);
|
||||||
|
|
||||||
const streamingData = video.streaming_data;
|
const streamingData = video.streaming_data;
|
||||||
|
@ -89,7 +90,7 @@ export const youtubePlayerParsing = async (
|
||||||
videoDetails,
|
videoDetails,
|
||||||
microformat,
|
microformat,
|
||||||
invidiousCompanion: {
|
invidiousCompanion: {
|
||||||
"baseUrl": konfigStore.get("server.base_url") as string,
|
"baseUrl": Deno.env.get("SERVER_BASE_URL") || konfigStore.get("server.base_url") as string,
|
||||||
},
|
},
|
||||||
}))(videoData);
|
}))(videoData);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { getFetchClient } from "../helpers/getFetchClient.ts";
|
||||||
export const poTokenGenerate = async (
|
export const poTokenGenerate = async (
|
||||||
innertubeClient: Innertube,
|
innertubeClient: Innertube,
|
||||||
konfigStore: Store<Record<string, unknown>>,
|
konfigStore: Store<Record<string, unknown>>,
|
||||||
|
innertubeClientCache: UniversalCache
|
||||||
): Promise<Innertube> => {
|
): Promise<Innertube> => {
|
||||||
const requestKey = "O43z0dpjhgX20SCx4KAo";
|
const requestKey = "O43z0dpjhgX20SCx4KAo";
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ export const poTokenGenerate = async (
|
||||||
po_token: poTokenResult.poToken,
|
po_token: poTokenResult.poToken,
|
||||||
visitor_data: visitorData,
|
visitor_data: visitorData,
|
||||||
fetch: getFetchClient(konfigStore),
|
fetch: getFetchClient(konfigStore),
|
||||||
cache: new UniversalCache(true),
|
cache: innertubeClientCache,
|
||||||
generate_session_locally: true,
|
generate_session_locally: true,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
38
src/main.ts
38
src/main.ts
|
@ -6,11 +6,9 @@ import { konfigLoader } from "./lib/helpers/konfigLoader.ts";
|
||||||
import { getFetchClient } from "./lib/helpers/getFetchClient.ts";
|
import { getFetchClient } from "./lib/helpers/getFetchClient.ts";
|
||||||
|
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
|
|
||||||
const konfigStore = await konfigLoader();
|
const konfigStore = await konfigLoader();
|
||||||
|
|
||||||
let innertubeClient: Innertube;
|
let innertubeClient: Innertube;
|
||||||
let innertubeClientUniversalCache = true;
|
|
||||||
let innertubeClientFetchPlayer = true;
|
let innertubeClientFetchPlayer = true;
|
||||||
const innertubeClientOauthEnabled = konfigStore.get(
|
const innertubeClientOauthEnabled = konfigStore.get(
|
||||||
"youtube_session.oauth_enabled",
|
"youtube_session.oauth_enabled",
|
||||||
|
@ -21,6 +19,12 @@ const innertubeClientJobPoTokenEnabled = konfigStore.get(
|
||||||
const innertubeClientCookies = konfigStore.get(
|
const innertubeClientCookies = konfigStore.get(
|
||||||
"jobs.youtube_session.cookies",
|
"jobs.youtube_session.cookies",
|
||||||
) as string;
|
) 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 (!innertubeClientOauthEnabled) {
|
||||||
if (innertubeClientJobPoTokenEnabled) {
|
if (innertubeClientJobPoTokenEnabled) {
|
||||||
|
@ -32,29 +36,37 @@ if (!innertubeClientOauthEnabled) {
|
||||||
}
|
}
|
||||||
} else if (innertubeClientOauthEnabled) {
|
} else if (innertubeClientOauthEnabled) {
|
||||||
// Can't use cache if using OAuth#cacheCredentials
|
// Can't use cache if using OAuth#cacheCredentials
|
||||||
innertubeClientUniversalCache = false;
|
innertubeClientCache = new UniversalCache(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
innertubeClient = await Innertube.create({
|
innertubeClient = await Innertube.create({
|
||||||
cache: new UniversalCache(innertubeClientUniversalCache),
|
cache: innertubeClientCache,
|
||||||
retrieve_player: innertubeClientFetchPlayer,
|
retrieve_player: innertubeClientFetchPlayer,
|
||||||
fetch: getFetchClient(konfigStore),
|
fetch: getFetchClient(konfigStore),
|
||||||
cookie: innertubeClientCookies || undefined
|
cookie: innertubeClientCookies || undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!innertubeClientOauthEnabled) {
|
if (!innertubeClientOauthEnabled) {
|
||||||
if (innertubeClientOauthEnabled) {
|
if (innertubeClientOauthEnabled) {
|
||||||
innertubeClient = await poTokenGenerate(innertubeClient, konfigStore);
|
innertubeClient = await poTokenGenerate(
|
||||||
|
innertubeClient,
|
||||||
|
konfigStore,
|
||||||
|
innertubeClientCache as UniversalCache,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Deno.cron(
|
Deno.cron(
|
||||||
"regenerate youtube session",
|
"regenerate youtube session",
|
||||||
konfigStore.get("jobs.youtube_session.frequency") as string,
|
konfigStore.get("jobs.youtube_session.frequency") as string,
|
||||||
async () => {
|
async () => {
|
||||||
if (innertubeClientOauthEnabled) {
|
if (innertubeClientOauthEnabled) {
|
||||||
innertubeClient = await poTokenGenerate(innertubeClient, konfigStore);
|
innertubeClient = await poTokenGenerate(
|
||||||
|
innertubeClient,
|
||||||
|
konfigStore,
|
||||||
|
innertubeClientCache,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
innertubeClient = await Innertube.create({
|
innertubeClient = await Innertube.create({
|
||||||
cache: new UniversalCache(innertubeClientUniversalCache),
|
cache: innertubeClientCache,
|
||||||
retrieve_player: innertubeClientFetchPlayer,
|
retrieve_player: innertubeClientFetchPlayer,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -62,8 +74,10 @@ if (!innertubeClientOauthEnabled) {
|
||||||
);
|
);
|
||||||
} else if (innertubeClientOauthEnabled) {
|
} else if (innertubeClientOauthEnabled) {
|
||||||
// Fired when waiting for the user to authorize the sign in attempt.
|
// Fired when waiting for the user to authorize the sign in attempt.
|
||||||
innertubeClient.session.on('auth-pending', (data) => {
|
innertubeClient.session.on("auth-pending", (data) => {
|
||||||
console.log(`Go to ${data.verification_url} in your browser and enter code ${data.user_code} to authenticate.`);
|
console.log(
|
||||||
|
`Go to ${data.verification_url} in your browser and enter code ${data.user_code} to authenticate.`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
// Fired when authentication is successful.
|
// Fired when authentication is successful.
|
||||||
innertubeClient.session.on("auth", () => {
|
innertubeClient.session.on("auth", () => {
|
||||||
|
@ -91,6 +105,6 @@ app.use("*", async (c, next) => {
|
||||||
routes(app, konfigStore);
|
routes(app, konfigStore);
|
||||||
|
|
||||||
Deno.serve({
|
Deno.serve({
|
||||||
port: konfigStore.get("server.port") as number,
|
port: Number(Deno.env.get("PORT")) || konfigStore.get("server.port") as number,
|
||||||
hostname: konfigStore.get("server.host") as string,
|
hostname: Deno.env.get("HOST") || konfigStore.get("server.host") as string,
|
||||||
}, app.fetch);
|
}, app.fetch);
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const routes = (app: Hono, konfigStore: Store<Record<string, unknown>>) =
|
||||||
app.use(
|
app.use(
|
||||||
"/youtubei/v1/*",
|
"/youtubei/v1/*",
|
||||||
bearerAuth({
|
bearerAuth({
|
||||||
token: konfigStore.get("server.hmac_key") as string,
|
token: Deno.env.get("SERVER_HMAC_KEY") || konfigStore.get("server.hmac_key") as string,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue