yt-dlp image and script wrapper to download youtube content for local consumption
1.3K
Containerized yt-dlp with aria2 acceleration and an opinionated wrapper script at /opt/scripts/yt-dlp.sh.
Defaults favour playlist/file mode using /media/channel_list.txt and run in foreground for logs.
Create a host directory (i.e. /path/on/host) and a channel_list.txt file with one URL per line:
https://www.youtube.com/@royalsociety/videos
https://www.youtube.com/@GreatBigStory/videos
Generate cookies.txt (on a laptop or desktop with a browser logged into youtube):
yt-dlp --cookies-from-browser brave --cookies cookies.txt
Copy cookies.txt to your '/path/on/host' folder.
Run the container and mount your directory to /media:
docker run --rm -it \
-v /path/on/host:/media \
haven/yt-dlp:latest
This will run /opt/scripts/yt-dlp.sh --foreground by default and read URLs from /media/channel_list.txt. By default it downloads items from the last 7 days; see env vars below to change this.
If you get 403 returns when downloading you likely need to re-generate the cookies.txt and try again.
Pass a URL via --input-source and enable --oneshot (downloads all unless you also set a date filter):
docker run --rm -it \
-v /path/on/host:/media \
haven/yt-dlp:latest \
--oneshot --input-source "https://www.youtube.com/@royalsociety/videos"
All key runtime settings can be overridden via Docker env vars or CLI parameters:
| Environment Variable | CLI Parameter | Default Value | Example Values | Description |
|---|---|---|---|---|
YTDLP_DOWNLOAD_DIR | --dir | /media | /srv/youtube, /downloads | Download directory inside the container |
YTDLP_INPUT_SOURCE | --input-source | ${YTDLP_DOWNLOAD_DIR}/channel_list.txt | /media/my_channels.txt, https://youtube.com/@user/videos | File path or direct URL |
YTDLP_DAYS | --days | 7 | 14, 30, 1 | Number of days to look back for downloads |
YTDLP_ONESHOT | --oneshot | false | true, false | Enable one-shot URL mode (bypasses file reading) |
YTDLP_SUBTITLE_LANGS | --subtitle-langs | en | en,es, en,de,fr | Comma-separated subtitle languages |
YTDLP_MIN_FREE_SPACE | --min-free-space | 5 | 10, 20 | Minimum free space required (GB) |
YTDLP_CODEC | --codec | mp4 | mp4, vp9, av1 | Video codec preference with intelligent fallbacks |
YTDLP_FOREGROUND | --foreground | false | true, false | Console logging vs. log file (container CMD uses --foreground) |
YTDLP_DEBUG | --debug | false | true, false | Enable verbose yt-dlp output |
YTDLP_DRY_RUN | --dry-run | false | true, false | Simulate downloads without downloading |
YTDLP_USER_AGENT | (built-in) | Chrome UA | "Mozilla/5.0..." | Custom User-Agent string |
YTDLP_PLAYLIST_END | (built-in) | 10 | 5, 25, 50 | Limit playlist items processed |
YTDLP_DOWNLOADER_ARGS | (built-in) | aria2c:-c -j 3 -s 3 -x 3 -k 1M... | aria2c:-j 5 -x 5 | aria2c tuning parameters |
YTDLP_FORCE_IPV4 | (built-in) | true | true, false | Force IPv4 connections |
Examples:
docker run --rm -it \
-v /srv/youtube:/media \
-e YTDLP_DAYS=14 \
-e YTDLP_CODEC=vp9 \
-e YTDLP_SUBTITLE_LANGS="en,es" \
haven/yt-dlp:latest
AV1 example (CPU encode, WebM output):
docker run --rm -it \
-v /srv/youtube:/media \
-e YTDLP_CODEC=av1 \
haven/yt-dlp:latest
You can select the preferred codec via --codec {mp4|vp9|av1} or -e YTDLP_CODEC=.... The script will fall back smartly when the exact choice is not available.
| Option | Container | Video codec | Audio (typical) | HW decode support | 4K readiness | Compression efficiency | CPU decode cost | Compatibility | When to choose |
|---|---|---|---|---|---|---|---|---|---|
| mp4 | MP4 | H.264 (x264) | AAC (m4a) | Excellent (nearly universal) | Good | Lowest of the three | Lowest | Excellent (devices, TVs, editors) | Max compatibility, easiest playback/editing |
| vp9 | WebM | VP9 | Opus | Good on modern hardware (newer CPUs/GPUs) | Very good | ~30–50% better than H.264 | Medium | Good on modern players/browsers | Balance of quality and size, modern playback |
| av1 | WebM | AV1 (SVT-AV1 encode, dav1d decode) | Opus | Limited to newest GPUs/SoCs; software decode heavy | Excellent (4K/8K) | Best (often 20–30% better than VP9) | High | Best on latest players/browsers | Archival or bandwidth-sensitive use, modern environments |
Notes:
--codec is set.The image declares VOLUME ["/media"]. Mount your host directory there.
Container runs as user 1000:1000 by default. Ensure the mounted host directory is writable by this UID/GID, or override at runtime:
docker run --rm -it \
--user $(id -u):$(id -g) \
-v /path/on/host:/media \
haven/yt-dlp:latest
The image declares VOLUME ["/media"]. Mount your host directory there.
Container runs as user 1000:1000 by default. Ensure the mounted host directory is writable by this UID/GID, or override at runtime:
docker run --rm -it \
--user $(id -u):$(id -g) \
-v /path/on/host:/media \
haven/yt-dlp:latest
If a cookies.txt file exists at ${YTDLP_DOWNLOAD_DIR}/cookies.txt (default /media/cookies.txt), it will be used automatically. This is useful for authenticated or age-restricted content.
Files are written under ${YTDLP_DOWNLOAD_DIR} into folders by uploader and playlist, with metadata, description, info
JSON, and embedded thumbnails/subtitles by default.
Date filtering (via YTDLP_DAYS) uses the container timezone. Set it explicitly if you need a specific zone:
docker run --rm -it \
-e TZ=Europe/London \
-v /path/on/host:/media \
haven/yt-dlp:latest
YTDLP_DAYS days in playlist mode. Set a different value with -e YTDLP_DAYS=30 or disable date filtering by using --oneshot for direct URLs./opt/scripts/yt-dlp.sh, yt-dlp on PATH, and writa
bility of /media.Content type
Image
Digest
sha256:5dffcc5f1…
Size
188.9 MB
Last updated
4 months ago
docker pull haven/yt-dlp