| name | media-ytdlp |
| description | Download videos, audio, playlists, and channels from YouTube, Twitch, Twitter/X, TikTok, Instagram, Vimeo, Facebook, and 1000+ other sites using yt-dlp. Use when the user asks to download a YouTube video, rip a playlist, grab a Twitch VOD, download audio as MP3, extract subtitles from a web video, get best-quality stream, download channel uploads, archive web video, or fetch media from any streaming site.
|
| argument-hint | [url] |
Media yt-dlp
Context: $ARGUMENTS
yt-dlp is an actively-maintained fork of youtube-dl. Always prefer it — upstream youtube-dl is effectively dormant and its YouTube extractors break monthly. yt-dlp ships a far larger extractor set (1000+ sites), smarter format selection, throttling work-arounds, SponsorBlock hooks, and native post-processors.
Quick start
- Grab best quality (any codec/container):
yt-dlp -f "bv*+ba/b" URL → Step 3
- Best MP4 (web/Apple friendly):
yt-dlp -f "bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]" URL → Step 3
- Audio only MP3:
yt-dlp -x --audio-format mp3 --audio-quality 0 URL → Step 3
- Cap at 1080p:
yt-dlp -f "bv*[height<=1080]+ba/b[height<=1080]" URL → Step 2
- Playlist / channel / live: → Step 3
- Subtitles, thumbnails, metadata: → Step 4
When to use
- Archiving a single YouTube / Twitch / Vimeo / Twitter / TikTok / Instagram clip.
- Ripping a playlist or entire channel uploads feed.
- Extracting audio (podcast, music, lecture) as MP3 / M4A / FLAC / Opus.
- Downloading a live stream from-the-start (DVR style) while it is still airing.
- Pulling subtitles / auto-generated captions for transcription.
- Feeding downloaded media into another ffmpeg skill (cut/concat, transcode, subtitle burn-in, etc.).
Step 1 — Install and verify
brew install yt-dlp ffmpeg
python3 -m pip install -U yt-dlp
yt-dlp --version
ffmpeg -version | head -1
yt-dlp needs ffmpeg on $PATH whenever a site serves video and audio as separate streams (YouTube almost always does). Without ffmpeg the merge step silently fails and you get a video-only or audio-only file.
Update in-place without reinstalling:
yt-dlp -U
python3 -m pip install -U yt-dlp
Step 2 — Pick a format
yt-dlp -F URL lists every available format (id, ext, resolution, fps, vcodec, acodec, tbr, size). Then build a selector:
| Goal | Selector |
|---|
| Absolute best (any codec) | -f "bv*+ba/b" |
| Best MP4 (H.264+AAC) | -f "bv*[ext=mp4][vcodec^=avc1]+ba[ext=m4a]/b[ext=mp4]" |
| Cap resolution | -f "bv*[height<=1080]+ba/b[height<=1080]" |
| Cap filesize (rough) | -f "b[filesize<500M]" |
| Prefer AV1 → VP9 → H.264 | -f "bv*[vcodec=av01]+ba/bv*[vcodec=vp9]+ba/bv*+ba/b" |
| Audio only | -f "ba/b" |
Selector grammar: bv* = best video (incl. muxed), ba = best audio, b = best single muxed file, / = fallback, + = merge. See references/ytdlp.md for filters and sort keys.
Step 3 — Download
yt-dlp -f "bv*+ba/b" --restrict-filenames \
-o "%(uploader)s - %(title)s [%(id)s].%(ext)s" URL
yt-dlp -o "%(playlist)s/%(playlist_index)03d - %(title)s.%(ext)s" PLAYLIST_URL
yt-dlp 'https://www.youtube.com/@channelname/videos'
yt-dlp -f best 'https://www.twitch.tv/videos/123456789'
yt-dlp --live-from-start URL
yt-dlp -x --audio-format mp3 --audio-quality 0 URL
yt-dlp --download-archive archive.txt -o "%(uploader)s/%(title)s.%(ext)s" URL
Helper script (scripts/ytdlp.py) wraps common subcommands: check, list-formats, download, playlist, live, audio.
python3 ${CLAUDE_SKILL_DIR}/scripts/ytdlp.py check
python3 ${CLAUDE_SKILL_DIR}/scripts/ytdlp.py download --url URL --quality 1080p --subs
python3 ${CLAUDE_SKILL_DIR}/scripts/ytdlp.py playlist --url URL --outdir ./dl --archive ./dl/archive.txt
Step 4 — Post-process
yt-dlp's built-in post-processors handle most cases without shelling out to ffmpeg yourself:
yt-dlp --embed-thumbnail --embed-metadata --embed-chapters URL
yt-dlp --write-subs --write-auto-subs --sub-langs "en.*" \
--convert-subs srt --embed-subs --merge-output-format mkv URL
yt-dlp --write-info-json --write-description --write-thumbnail URL
yt-dlp --split-chapters URL
For anything beyond embedding (trimming around ads, stitching multiple downloads, re-encoding to a specific codec), hand the output off to another skill:
ffmpeg-cut-concat — trim / concat downloaded clips.
ffmpeg-transcode — re-encode to a specific codec / CRF / container.
ffmpeg-subtitles — burn or convert subtitle formats.
media-whisper — re-transcribe when the site's captions are missing or bad.
Available scripts
scripts/ytdlp.py — argparse wrapper around the yt-dlp CLI. Subcommands: check, list-formats, download, playlist, live, audio. Stdlib only, --dry-run and --verbose for safe inspection.
Reference docs
- Read
references/ytdlp.md when you need the full format-selector grammar, the output-template field list, site-specific quirks (YouTube / Twitch / X / TikTok / IG / Vimeo / FB / Reddit / SoundCloud / Bandcamp), cookie strategies, or the recipe gallery.
Gotchas
- Always prefer
yt-dlp over youtube-dl. youtube-dl has not had a usable release cadence in years; yt-dlp is the community fork everyone actually uses.
bv*+ba/b means "best video + best audio, fallback to best muxed". The * matters — without it you only match non-muxed video.
- Merging requires ffmpeg on
$PATH. On macOS that means brew install ffmpeg (Apple Silicon Homebrew lives at /opt/homebrew/bin; Intel at /usr/local/bin). If ffmpeg is missing, fall back to -f b (single muxed file) or accept a video-only download.
- Private / age-restricted / members-only / geo-blocked videos need cookies. Use
--cookies-from-browser chrome (or firefox, safari, edge, brave) — yt-dlp pulls the live session cookie. Manual --cookies cookies.txt also works but the Netscape file format is fiddly.
- Rate-limit for polite scraping.
-r 1M caps throughput at 1 MB/s. --sleep-interval 5 --max-sleep-interval 15 randomizes per-request pauses. On large channels / playlists this avoids 429 throttle bans.
- Live streams. Without
--live-from-start, yt-dlp begins recording at "now" — you lose everything before you hit enter. With it, yt-dlp walks the HLS playlist back to the stream start.
- Playlist index padding.
%(playlist_index)03d sorts correctly alongside shell tools; the bare %(playlist_index)s does not.
- Output templates are Python
%()s formatting. Useful fields: title, uploader, uploader_id, channel, upload_date (YYYYMMDD), id, ext, height, width, fps, vcodec, acodec, playlist, playlist_index, epoch, timestamp.
Examples
Example 1 — Archive a YouTube channel's uploads to MP4, skip already-downloaded
yt-dlp \
--download-archive ./archive.txt \
-f "bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]" \
--merge-output-format mp4 \
--embed-thumbnail --embed-metadata --embed-chapters \
--write-subs --write-auto-subs --sub-langs "en.*" --convert-subs srt \
--restrict-filenames \
-o "%(uploader)s/%(upload_date)s - %(title)s [%(id)s].%(ext)s" \
'https://www.youtube.com/@channelname/videos'
Rerunning the same command is idempotent — archive.txt tracks video IDs already fetched.
Example 2 — Rip a podcast playlist as 320kbps MP3
yt-dlp -x --audio-format mp3 --audio-quality 0 \
--embed-thumbnail --embed-metadata \
-o "%(playlist)s/%(playlist_index)03d - %(title)s.%(ext)s" \
PLAYLIST_URL
Example 3 — Record a live stream from the beginning
yt-dlp --live-from-start \
-f "bv*+ba/b" \
-o "%(uploader)s - %(title)s - %(upload_date)s.%(ext)s" \
URL
Start this as soon as you notice the stream is live; yt-dlp holds the HLS manifest open until the stream ends.
Troubleshooting
Error: ERROR: Requested format is not available
Cause: selector matched zero formats (common after a site restricts a resolution tier or changes codec availability).
Solution: run yt-dlp -F URL to see what's actually offered, then relax the selector — e.g. drop the [ext=mp4] filter, or fall back to -f b.
Error: ERROR: ffprobe/ffmpeg not found
Cause: yt-dlp cannot merge separate video+audio streams, or cannot run an audio-extraction post-processor.
Solution: brew install ffmpeg (macOS) / apt install ffmpeg (Debian) / choco install ffmpeg (Windows). Verify ffmpeg -version on $PATH.
Error: HTTP Error 403: Forbidden or HTTP Error 429: Too Many Requests
Cause: the site is rate-limiting or geo-blocking your IP, or the video requires auth.
Solution: add --sleep-interval 5 --max-sleep-interval 30 -r 500K, pass --cookies-from-browser chrome, or route through a VPN. For YouTube specifically, a logged-in cookie often unlocks throttled streams.
Error: ERROR: Unable to extract ... / extractor tracebacks
Cause: the site changed its page structure; your yt-dlp is out of date.
Solution: yt-dlp -U (binary) or pip install -U yt-dlp. If still broken, check the issue tracker at github.com/yt-dlp/yt-dlp — fixes typically land within days.
Error: live stream saves only the tail, not the full broadcast
Cause: you launched yt-dlp without --live-from-start.
Solution: add --live-from-start. For streams that have already ended, download the VOD instead (YouTube usually publishes one within minutes of end-of-stream).