
Handles YouTube downloads and HLS streams using yt-dlp and ffmpeg, with built-in workarounds for the bot detection and format availability issues that break…
$ npx -y skills add daymade/claude-code-skills --skill youtube-downloader --agent claude-codeInstalls into .claude/skills of the current project.
Sponsors
Handles YouTube downloads and HLS streams using yt-dlp and ffmpeg, with built-in workarounds for the bot detection and format availability issues that break basic yt-dlp usage. Sets up PO token providers automatically (tries Docker, falls back to browser-based), extracts cookies from Chrome when needed, and defaults to a non-technical UX where you just ask for a URL and get a file. The SOP is particularly solid on the failure modes: quotes URLs for zsh, rewrites localhost proxies for Docker, treats "only images available" as a token failure, keeps browser windows open during WPC minting. Useful when you need reliable high-quality downloads without debugging yt-dlp's increasingly fragile YouTube support yourself.
Enable reliable video and audio downloads from YouTube and HLS streaming platforms (Mux, Vimeo, etc.) using yt-dlp and ffmpeg. This skill provides workflows for:
Before downloading anything, classify the request:
references/text-first.md FIRST: existing archived transcripts → platform transcript APIs → yt-dlp subtitle-only → authorized audio track + ASR. Do not download the full video just to obtain text.The text-first route never blocks a file request: when the user wants the file, download it with the unchanged flow below.
Assume the user is non-technical. Do not ask them to run commands. Execute everything yourself and report progress in plain language. Avoid mentioning tooling unless the user asks.
Default flow:
Offer choices in user-friendly terms:
Always render the thumbnail when available:
.Ask before doing extra work:
Legal/Safety reminder (brief):
Response template (use plain language, no commands):

Title: …
Channel: …
Duration: …
I can help you:
1) Download the video (best quality, MP4)
2) Download audio only (MP3)
3) Pick a specific quality (1080p/720p/480p/360p)
4) Include subtitles (if available)
Where should I save it? (Default: Downloads folder)
If the user says “just download”:
Read the download SOP before retrying a failure. Start with the current yt-dlp default clients and the existing network configuration. Do not require a provider, switch to Android, or extract browser cookies merely to begin a download.
scripts/download_video.py URL --info for metadata. It never starts a provider; its oEmbed fallback supplies limited fields when extraction fails.--js-runtimes node when yt-dlp needs it; runtime installation still follows dependency authorization.-F output. An absent requested format, images-only output, 403 or low resolution alone does not establish a token problem.--auto-po-token and finish the original download; do not stop at giving the user a command. This option attempts the native route first, then permits a bounded provider retry and WPC recovery.ffprobe and report its path, size and actual resolution or audio properties. Provider health or a format listing alone is not a completed download.This skill should be invoked when users:
which yt-dlp
yt-dlp --version
If missing or a current extraction diagnostic requires an update, obtain any missing install/upgrade authorization, then use the existing installation owner:
brew upgrade yt-dlp # macOS
# or
pip install --upgrade yt-dlp # Cross-platform
Check the current EJS setup guide for the JavaScript runtime and challenge-solver requirements of the installed distribution. An installed Node binary may need explicit --js-runtimes node; do not treat an EJS/nsig failure as a PO Token failure.
Before downloading, check available formats:
yt-dlp -F "https://youtu.be/VIDEO_ID"
Compare the listed media streams with the requested quality. If only a low-resolution format appears, inspect extraction/runtime warnings and the source availability before choosing recovery.
Keep player_client unset unless there is a specific diagnostic or explicit request. The official extractor guide describes yt-dlp's default attempt with clients that do not require tokens. Available formats depend on the video, account, client, network and current YouTube enforcement.
# Download best quality up to 1080p
scripts/download_video.py "VIDEO_URL" --quality 1080p
# Download best available quality
scripts/download_video.py "VIDEO_URL"
# After an explicit token requirement, with setup already authorized
scripts/download_video.py "VIDEO_URL" --auto-po-token
For installation and provider-specific recovery, load PO Token setup. Do not infer a provider requirement from resolution alone.
# Check video resolution
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,codec_name -of default=noprint_wrappers=1 video.mp4
Expected output for 1080p:
codec_name=vp9
width=1920
height=1080
Use cookies when the content requires the authorized account or a bot check persists, after cookie permission is granted. Cookies authenticate a session; they do not replace a missing PO Token:
# Firefox
yt-dlp --cookies-from-browser firefox -f "bestvideo[height<=1080]+bestaudio/best" "VIDEO_URL"
# Chrome
yt-dlp --cookies-from-browser chrome -f "bestvideo[height<=1080]+bestaudio/best" "VIDEO_URL"
Benefits: Access to age-restricted and members-only content. Requirements:
web_safari only as a targeted retry. Do not combine account cookies with Android/iOS clients that do not support them.Extract audio as MP3:
yt-dlp -x --audio-format mp3 "VIDEO_URL"
yt-dlp -P ~/Downloads/YouTube "VIDEO_URL"
yt-dlp --write-subs --sub-lang en "VIDEO_URL"
yt-dlp -f "bestvideo[height<=1080]+bestaudio/best" "PLAYLIST_URL"
YouTube high-quality downloads often use WebM format (VP9 codec). Convert to MP4 for wider compatibility:
# Check if ffmpeg is installed
which ffmpeg || brew install ffmpeg # macOS
# Convert WebM to MP4 with good quality settings
ffmpeg -i "video.webm" -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k "video.mp4"
Parameters explained:
-c:v libx264: Use H.264 video codec (widely compatible)-preset medium: Balance between encoding speed and file size-crf 23: Constant Rate Factor for quality (18-28 range, lower = better quality)-c:a aac: Use AAC audio codec-b:a 128k: Audio bitrate 128 kbpsTip: Conversion maintains 1080p resolution and provides ~6x encoding speed on modern hardware.
Inspect -F, the selected format expression, current yt-dlp/EJS/runtime warnings and source availability. These messages have multiple causes. Enter provider setup only when a failed extraction or media request also names a missing/required PO Token. Do not install a provider because a requested height or format ID is absent.
Check that the intended proxy/network is in use. If the challenge persists and cookies are needed, obtain cookie authorization, retain that session, and retry. Stop with the exact authorization gap if it is unavailable; do not silently read browser cookies.
Check the installed yt-dlp version and the EJS runtime and solver instructions. Repair the diagnosed prerequisite within authorization. Android or AndroidVR can be selected explicitly for a bounded diagnostic, but neither is the default recovery or a guaranteed solution.
Distinguish a media 403 from TLS, timeout, proxy and provider-health errors. A generic 403 does not prove a Token requirement. Check the network path first for SSL/timeout failures; retry only after a relevant change. The wrapper's single progressive retry applies to 403/fragment failures with quality presets, and may reduce quality.
For users in China or behind restrictive proxies:
WARNING: android client https formats require a GVS PO Token
Action: A successful, verified download needs no repair for an unused-client warning. On failure, read the full diagnostic and actual formats before choosing a token branch.
Use this wrapper for native-client downloads and bounded diagnostic recovery. It does not install/start providers or read cookies by default. Execute it yourself and report the verified file.
Basic usage:
scripts/download_video.py "VIDEO_URL"
Arguments:
url - YouTube video URL (required)-o, --output-dir - Output directory--output-template - Output filename template (yt-dlp syntax)-f, --format - Format specification-q, --quality - Quality preset (best, 1080p, 720p, 480p, 360p, worst). Default: best (skipped for --audio-only)-a, --audio-only - Extract audio as MP3--subtitles - Download subtitles if available--sub-lang - Subtitle languages (comma-separated, default: en)--cookies-from-browser - Load cookies from a browser (e.g., chrome, firefox)--cookies-file - Load cookies from a cookies.txt file--player-client - Use a specific YouTube player client (e.g., web_safari)--auto-po-token - Authorize provider setup after a failed explicit missing/required-token diagnostic; try native clients first, then Docker bgutil or browser WPC--no-auto-po-token - Disable provider setup (default); does not disable already-installed yt-dlp plugins--proxy - Proxy URL for yt-dlp and the PO Token provider (e.g., http://127.0.0.1:1082)--wpc-browser-path - Browser executable path for WPC provider-F, --list-formats - List available formats--merge-format - Merge output container (e.g., mp4, mkv). Default: mp4--playlist - Allow playlist downloads (default: single video only)--info - Print title/uploader/duration/thumbnail and exit--no-android-client - Retained compatibility option; the wrapper already leaves native client selection unchanged--js-runtimes - Pass an installed runtime to yt-dlp, e.g. node or node:/path/to/nodeDo not promise a resolution based on a provider/client/cookie combination. Request the desired quality, inspect available formats, and verify the actual downloaded file. A successful high-resolution download without new provider setup proves only that input and environment; installed plugins or configuration may still contribute. A provider cannot create a resolution absent from the source.
For streaming platforms like Mux, Vimeo, and other HLS-based services, use ffmpeg as the primary tool. These streams often require authentication headers that yt-dlp may not handle correctly.
HLS streams use .m3u8 playlist files:
Get the m3u8 URL from the video source. For protected streams:
Many CDNs require authentication headers:
https://maven.com/)Check the Network tab to see which headers the browser sends.
Use ffmpeg with the -headers flag for protected streams:
ffmpeg -headers "Referer: https://example.com/" \
-protocol_whitelist file,http,https,tcp,tls,crypto,httpproxy \
-i "https://cdn.example.com/path/rendition.m3u8?params" \
-c copy -bsf:a aac_adtstoasc \
output.mp4
Key parameters:
-headers: Set HTTP headers (critical for authentication)-protocol_whitelist: Enable required protocols for HLS-c copy: Stream copy (no re-encoding, faster)-bsf:a aac_adtstoasc: Fix AAC audio compatibilityCommon header patterns:
# Single header
-headers "Referer: https://example.com/"
# Multiple headers
-headers "Referer: https://example.com/" \
-headers "User-Agent: Mozilla/5.0..."
# Alternative syntax
-headers $'Referer: https://example.com/\r\nUser-Agent: Mozilla/5.0...'
Some platforms (like Mux) deliver audio and video separately:
ffmpeg -headers "Referer: https://example.com/" \
-protocol_whitelist file,http,https,tcp,tls,crypto,httpproxy \
-i "https://cdn.example.com/audio/rendition.m3u8" \
-c copy audio.m4a
ffmpeg -headers "Referer: https://example.com/" \
-protocol_whitelist file,http,https,tcp,tls,crypto,httpproxy \
-i "https://cdn.example.com/video/rendition.m3u8" \
-c copy video.mp4
ffmpeg -i video.mp4 -i audio.m4a -c copy merged.mp4
Cause: Missing or incorrect authentication headers.
Solution:
Symptom: Extracting cookies from chrome hangs indefinitely.
Solution: Use ffmpeg directly instead of yt-dlp for HLS streams.
Error: Protocol 'https' not on whitelist 'file,crypto,data'
Solution: Add -protocol_whitelist file,http,https,tcp,tls,crypto,httpproxy
Cause: Expired signatures in the m3u8 URLs.
Solution:
-c copy (fastest)references/po-token-setup.md for detailed installation and troubleshootingreferences/internal-sop.md — the short list of yt-dlp failures that look like something else (URLs unquoted in zsh, proxy not reaching the PO Token provider). Read it first when a download fails for no obvious reasonTwo situations, two routes:
references/text-first.md (existing archived transcripts → platform transcript APIs → yt-dlp subtitle-only → authorized audio track + ASR).Download complete: [filename]
If you need the spoken content as text, I can transcribe it for you.
Options:
A) Transcribe with /daymade-audio:asr-transcribe-to-text (Recommended for speech-to-text)
B) No thanks — I just needed the video file