feat(downloads): Deno JS runtime + web/android clients to complete the POT setup

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.
This commit is contained in:
npeter83 2026-07-03 22:46:32 +02:00
parent 03a1865aa8
commit 21c5508889
3 changed files with 15 additions and 8 deletions

View file

@ -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 .

View file

@ -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]:

View file

@ -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).