From 21c55088897f583820c535346df649092215e88e Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 3 Jul 2026 22:46:32 +0200 Subject: [PATCH] feat(downloads): Deno JS runtime + web/android clients to complete the POT setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The web player clients need two things beyond the PO token: (1) a JavaScript runtime for YouTube's 'n' signature challenge — install Deno (v2.9.1) + yt-dlp[default] (bundles yt-dlp-ejs solver scripts); auto-detected on PATH. (2) an audio source — the web clients only expose video-only DASH, so add the 'android' client (also PO-token-backed) for audio/muxed formats. Player clients: web_safari,web,android (dropped tv — it falsely reports normal videos as DRM). End-to-end verified in the worker: extraction (POT + Deno n-challenge) + download completes, no bot/DRM/format errors. Full YouTube stack now: force-ipv4 + bgutil POT sidecar + Deno. --- Dockerfile | 12 +++++++++--- backend/app/config.py | 2 +- backend/requirements.txt | 9 +++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 188bd05..08f9839 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,10 +34,16 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ WORKDIR /app -# ffmpeg is required by the download center (yt-dlp) to merge separate video+audio streams -# and run postprocessing (audio extract, embed thumbnail/chapters/subs, SponsorBlock). +# ffmpeg: merge separate video+audio streams + postprocessing. Deno: the JavaScript runtime +# yt-dlp uses to solve YouTube's "n" signature challenge for the web player clients (required +# alongside the PO token, else only storyboards are offered). yt-dlp auto-detects deno on PATH. +ARG DENO_VERSION=v2.9.1 RUN apt-get update \ - && apt-get install -y --no-install-recommends ffmpeg \ + && apt-get install -y --no-install-recommends ffmpeg unzip curl ca-certificates \ + && curl -fsSL "https://github.com/denoland/deno/releases/download/${DENO_VERSION}/deno-x86_64-unknown-linux-gnu.zip" -o /tmp/deno.zip \ + && unzip -o /tmp/deno.zip -d /usr/local/bin \ + && chmod +x /usr/local/bin/deno \ + && rm /tmp/deno.zip \ && rm -rf /var/lib/apt/lists/* COPY backend/requirements.txt . diff --git a/backend/app/config.py b/backend/app/config.py index 2e99e35..6a39add 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -145,7 +145,7 @@ class Settings(BaseSettings): # yt-dlp player clients to use (comma-separated). POT-capable clients (web_safari/web) must # be used for the PO token to actually apply; the default clients (android_vr) don't request # one. Empty = yt-dlp's own default. Admin-tunable when YouTube shifts what works. - download_player_clients: str = "web_safari,web,tv" + download_player_clients: str = "web_safari,web,android" @property def player_client_list(self) -> list[str]: diff --git a/backend/requirements.txt b/backend/requirements.txt index 2e9563c..2a8cf38 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -13,10 +13,11 @@ py3langid>=0.3,<1.0 itsdangerous>=2.1,<3.0 cryptography>=46.0.7,<47 argon2-cffi>=23.1,<26 -# Download center: yt-dlp does the extraction/download; ffmpeg (installed at the OS level in -# the Dockerfile) does the merge + postprocessing. yt-dlp is release-often (YouTube changes), -# so keep the floor loose and bump it when extraction breaks. -yt-dlp>=2025.5.22 +# Download center: yt-dlp does the extraction/download; ffmpeg (OS-level in the Dockerfile) +# does the merge + postprocessing. The [default] extra pulls yt-dlp-ejs (the challenge-solver +# scripts Deno runs for YouTube's n-signature). yt-dlp is release-often (YouTube changes), so +# keep the floor loose and bump it when extraction breaks. +yt-dlp[default]>=2025.5.22 # PO Token provider plugin: talks to the bgutil sidecar (brainicism/bgutil-ytdlp-pot-provider) # to mint YouTube Proof-of-Origin tokens on demand, bypassing "confirm you're not a bot" and # unlocking high-quality formats. Pin to match the sidecar image tag (versions must align).