CoolFace
Datasetpublic

jblast94/aebn-vod-downloader-v2

aebn-vod-downloader v2 Python VOD downloader with a local web UI. v2 keeps the proven native segment engine and rebuilds the service layer around it: pluggable subtitle backends, an optional yt-dlp engine, hardened job lifecycle, and defaults sized for a 32-core / 64 GB node on a high-speed private tailnet. What changed from web-ui (v0.10.1) RunPod is no longer the default or a hard dependency. Subtitle generation is now a pluggable, selectable service: openai… See the full description on the dataset page: https://huggingface.co/datasets/jblast94/aebn-vod-downloader-v2.

sourceHugging Faceupdated 11d agoView on Hugging Face
0likes63downloads
Dataset Card

aebn-vod-downloader v2

Python VOD downloader with a local web UI. v2 keeps the proven native segment engine and rebuilds the service layer around it: pluggable subtitle backends, an optional yt-dlp engine, hardened job lifecycle, and defaults sized for a 32-core / 64 GB node on a high-speed private tailnet.

What changed from web-ui (v0.10.1)

  • —RunPod is no longer the default or a hard dependency. Subtitle generation is now a pluggable, selectable service: openai (Whisper API), gemini (Google Gemini transcription), runpod (serverless Faster-Whisper, optional), or local (faster-whisper on your own CPU). none disables subtitles entirely; nothing limits the downloader when a backend is unconfigured.
  • —Subtitle mode is selectable: off | post (trigger after download) | parallel (auto-starts in a background worker the moment a download finishes, never blocking the download slot).
  • —Stale jobs don't linger: on startup, jobs left queued/running by a previous run are marked cancelled ("Interrupted by restart") and their old logs are cleared. Logs are collapsed by default and fetched incrementally.
  • —Internal player works: /media/... implements HTTP Range streaming so seek/scrub works on large files; .srt tracks attach automatically.
  • —Enterprise defaults: 4 concurrent download jobs, 16 download threads, 2 concurrent subtitle workers (override via env).
  • —yt-dlp engine: select ytdlp per job for generic/URL fallback downloads with concurrent fragments; output paths are captured and playable too.
  • —Reliability: bounded ThreadPoolExecutors replace the old semaphore + unbounded threads, DB write amplification removed, healthcheck endpoint added.

Quickstart (Docker)

cp .env.example .env   # edit keys/volumes
docker compose up -d --build
open http://localhost:8787

Quickstart (host, no Docker)

Requires Python 3.10+, uv, and ffmpeg in PATH.

uv sync
uv run aebndl-web            # binds 127.0.0.1:8787 by default
AEBNDL_HOST=0.0.0.0 uv run aebndl-web

CLI (native engine only): uv run aebndl "<url>" -r 720

Configuration (env)

VariableDefaultPurpose
AEBNDL_HOST / AEBNDL_PORT127.0.0.1 / 8787Bind address
AEBNDL_OUTPUT_DIR / AEBNDL_WORK_DIR./downloads / ./workStorage locations
AEBNDL_DB_PATH<work>/aebndl-jobs.dbSQLite job history
AEBNDL_THREADS16Per-download threads / yt-dlp fragments
AEBNDL_MAX_CONCURRENT_JOBS4Parallel download jobs
AEBNDL_MAX_CONCURRENT_SUBTITLES2Parallel subtitle workers
AEBNDL_JOB_RETENTION_HOURS0 (keep forever)Prune finished history
AEBNDL_SUBTITLE_MODEoffoff \post \parallel
AEBNDL_SUBTITLE_BACKENDnonenone \openai \gemini \runpod \local
AEBNDL_SUBTITLE_LANGUAGE(auto)Hint language for transcription
AEBNDL_SUBTITLE_CHUNK_MINUTES10Audio chunk length for API backends
OPENAI_API_KEYEnables the openai backend (whisper-1)
GEMINI_API_KEYEnables the gemini backend (gemini-2.0-flash)
RUNPOD_API_KEY + AEBNDL_RUNPOD_ENDPOINT_URLEnables the runpod backend
AEBNDL_LOCAL_WHISPER_MODELsmallfaster-whisper model for local backend

local backend needs the extra: uv sync --extra local-whisper.

Network: tailnet + egress

  • —The UI binds to 127.0.0.1 by default. On the tailnet node either set AEBNDL_HOST=0.0.0.0 and AEBNDL_BIND_IP=<tailscale-ip> in compose (port published only on the tailnet interface), or keep loopback and expose with tailscale serve --bg http://127.0.0.1:8787.
  • —Egress allowlist (outbound 443): *.aebn.com / *.aebn.net (metadata + segment CDNs — segment hosts come from the DASH manifest, so allow the CDN domain block), api.openai.com, generativelanguage.googleapis.com, api.runpod.ai (only if used), pypi.org / *.pypi.org (install only).
  • —Inbound: none required; anything that can reach the bound interface on 8787 can use the app — keep it on loopback or the tailnet only.

API (summary)

  • —GET /api/config — effective settings + which backends are usable
  • —GET /api/jobs · POST /api/jobs · POST /api/jobs/{id}/cancel
  • —DELETE /api/jobs/{id}?delete_files= · DELETE /api/jobs (clear finished)
  • —POST /api/jobs/{id}/outputs/{index}/subtitles — generate .srt for one output
  • —GET /api/jobs/{id}/logs?after=N — incremental log fetch
  • —GET /media/{job_id}/{index} — Range-streaming playback
  • —GET /subtitle-files/{job_id}/{index} — serve generated .srt
  • —POST /api/info — metadata preview before download
  • —GET /healthz — health probe for compose/orchestrators