Video Downloader
Video Downloader: Using yt-dlp to download videos from YouTube, Bilibili, Twitter, and thousands of other sites
Video Downloader#
Download videos from thousands of sites using yt-dlp — the most powerful and actively maintained video downloading tool. This skill covers installation, configuration, format selection, playlist management, and optimization techniques.
Core Principles#
1. Choose the Right Tool#
yt-dlp is the successor to youtube-dl and is actively maintained with support for over 1,000 sites. It handles YouTube, Bilibili, Twitter/X, Instagram, TikTok, Vimeo, Twitch, and countless others through extractors.
2. Understand Format Selection#
Video and audio are often delivered as separate streams (DASH). yt-dlp can merge them automatically with ffmpeg, or you can download them individually. Understanding formats means you get exactly the quality you need without wasting bandwidth.
3. Respect Rate Limits and Servers#
Don't hammer servers with concurrent downloads. Use rate limiting, randomized delays, and reasonable thread counts to avoid IP blocks and maintain access.
4. Handle Authentication Properly#
Some content requires authentication. Use cookies from your browser session rather than passing passwords directly. This is more reliable and avoids credential exposure in command history.
Installation and Setup#
macOS (Homebrew)#
# Install yt-dlp
brew install yt-dlp
# Install ffmpeg for post-processing (merging, conversion)
brew install ffmpegLinux (Ubuntu/Debian)#
# Latest version via pip (recommended)
python3 -m pip install -U yt-dlp
# Or via apt (may be outdated)
sudo apt install yt-dlp ffmpegWindows#
# Via pip (recommended)
python -m pip install -U yt-dlp
# Via winget
winget install yt-dlp
# Download standalone binary
# https://github.com/yt-dlp/yt-dlp/releasesVerify Installation#
yt-dlp --version
yt-dlp --help | head -20Basic Download Commands#
Simple Video Download#
# Download best quality video+audio
yt-dlp "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# Download with specific output template
yt-dlp -o "%(title)s.%(ext)s" "https://youtube.com/watch?v=VIDEO_ID"Format Selection#
# List available formats
yt-dlp -F "https://youtube.com/watch?v=VIDEO_ID"
# Download best video+audio combined
yt-dlp -f "bestvideo+bestaudio" "URL"
# Download specific resolution (e.g., 1080p)
yt-dlp -f "bestvideo[height<=1080]+bestaudio/best[height<=1080]" "URL"
# Download worst quality (for slow connections)
yt-dlp -f "worst" "URL"
# Download only audio (most compatible format)
yt-dlp -f "bestaudio" -x --audio-format mp3 "URL"
# Download a specific format by format code
yt-dlp -f "137+140" "URL" # 137=1080p video, 140=audioOutput Templates#
# Organize by type and ID
yt-dlp -o "%(playlist_title)s/%(playlist_index)s - %(title)s.%(ext)s" "URL"
# Custom directory structure
yt-dlp -o "~/Downloads/YouTube/%(uploader)s/%(title)s.%(ext)s" "URL"
# Include date in filename
yt-dlp -o "%(upload_date>%Y-%m-%d)s - %(title)s.%(ext)s" "URL"Playlist and Channel Downloading#
Download Full Playlists#
# Download entire playlist
yt-dlp "https://youtube.com/playlist?list=PLAYLIST_ID"
# Download specific range
yt-dlp --playlist-start 1 --playlist-end 10 "PLAYLIST_URL"
# Download only liked videos
yt-dlp "https://youtube.com/playlist?list=LL"
# Reverse playlist order
yt-dlp --playlist-reverse "PLAYLIST_URL"Channel Downloads#
# Download all videos from a channel
yt-dlp "https://www.youtube.com/@ChannelName/videos"
# Download only recent videos (last 5)
yt-dlp --max-downloads 5 "https://www.youtube.com/@ChannelName/videos"
# Download with channel-specific folder
yt-dlp -o "%(channel)s/%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s" "URL"Archive File Management#
# Track downloaded videos to avoid re-downloading
yt-dlp --download-archive archive.txt "PLAYLIST_URL"
# Use archive for incremental updates
yt-dlp --download-archive ~/.yt-dlp-archive "CHANNEL_URL"Subtitle Downloading#
Automatic and Manual Subtitles#
# Download all available subtitles
yt-dlp --write-subs --sub-langs all "URL"
# Download specific language subtitles
yt-dlp --write-subs --sub-langs "en,es,fr" "URL"
# Download auto-generated subtitles
yt-dlp --write-auto-subs --sub-langs "en" "URL"
# Embed subtitles into video file
yt-dlp --embed-subs --sub-langs "en" "URL"
# Convert subtitles to SRT format
yt-dlp --write-subs --sub-langs "en" --convert-subs srt "URL"Authentication and Cookies#
Using Browser Cookies#
# Extract cookies from browser (for age-restricted content)
yt-dlp --cookies-from-browser chrome "URL"
# Use specific browser profile
yt-dlp --cookies-from-browser firefox:"~/Library/Application Support/Firefox/Profiles/xxxx.default-release" "URL"
# Save cookies to file for reuse
yt-dlp --cookies-from-browser chrome --cookies cookies.txt "URL"
yt-dlp --cookies cookies.txt "URL"Login Credentials (Less Recommended)#
# Pass username and password
yt-dlp -u "username" -p "password" "URL"
# Use netrc file (~/.netrc)
yt-dlp --netrc "URL"Download Speed and Performance#
Speed Optimization#
# Use multiple threads/fragments for faster downloads
yt-dlp --fragment-retries 10 --concurrent-fragments 5 "URL"
# Limit download speed (500 KB/s)
yt-dlp --limit-rate 500K "URL"
# Retry on failure
yt-dlp --retries 10 --fragment-retries 10 "URL"
# Throttled download detection
yt-dlp --throttled-rate 100K "URL"Proxy Configuration#
# HTTP/HTTPS proxy
yt-dlp --proxy "http://proxy.example.com:8080" "URL"
# SOCKS5 proxy
yt-dlp --proxy "socks5://127.0.0.1:1080" "URL"
# Tor proxy
yt-dlp --proxy "socks5://127.0.0.1:9050" "URL"
# No proxy for specific sites
yt-dlp --proxy "http://proxy.example.com:8080" --no-proxy "https://youtube.com" "URL"Post-Processing with FFmpeg#
Merging and Conversion#
# Automatically merge best video+audio (requires ffmpeg)
yt-dlp -f "bestvideo+bestaudio" --merge-output-format mp4 "URL"
# Convert to specific container
yt-dlp --merge-output-format mkv "URL"
# Extract audio and convert
yt-dlp -x --audio-format mp3 --audio-quality 0 "URL"Custom FFmpeg Options#
# Apply ffmpeg filters
yt-dlp --postprocessor-args "ffmpeg:-vf 'scale=1280:720'" "URL"
# Add metadata
yt-dlp --parse-metadata "%(title)s:%(meta_title)s" "URL"
# Embed thumbnail
yt-dlp --embed-thumbnail "URL"Embedding Metadata#
# Embed all metadata
yt-dlp --embed-metadata --embed-thumbnail "URL"
# Embed chapters
yt-dlp --embed-chapters "URL"
# Write info JSON
yt-dlp --write-info-json "URL"Batch Downloading#
From a File List#
# Create a text file with one URL per line
# urls.txt
# https://youtube.com/watch?v=VIDEO1
# https://youtube.com/watch?v=VIDEO2
# https://vimeo.com/VIDEO3
# Download all URLs from file
yt-dlp --batch-file urls.txt
# Download with filtered list
yt-dlp --batch-file urls.txt --match-filter "duration < 3600"Advanced Batch Processing#
# Download only matching titles
yt-dlp --match-title "tutorial" --batch-file urls.txt
# Skip videos by title pattern
yt-dlp --reject-title "live stream" --batch-file urls.txt
# Download by date range
yt-dlp --dateafter "20240101" --datebefore "20241231" "CHANNEL_URL"
# Minimum and maximum file size
yt-dlp --min-filesize 10M --max-filesize 500M "URL"Python Scripting with yt-dlp#
Basic Python Integration#
import yt_dlp
import json
def download_video(url, output_path="~/Downloads/YouTube"):
"""Download a single video with best quality."""
ydl_opts = {
'format': 'bestvideo+bestaudio/best',
'outtmpl': f'{output_path}/%(title)s.%(ext)s',
'merge_output_format': 'mp4',
'embedmetadata': True,
'embedthumbnail': True,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
return {
'title': info.get('title'),
'duration': info.get('duration'),
'filesize': info.get('filesize'),
'filepath': ydl.prepare_filename(info)
}
# Usage
result = download_video("https://youtube.com/watch?v=dQw4w9WgXcQ")
print(f"Downloaded: {result['title']}")Extracting Info Without Downloading#
import yt_dlp
def get_video_info(url):
"""Get video metadata without downloading."""
ydl_opts = {
'quiet': True,
'no_warnings': True,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=False)
return {
'title': info.get('title'),
'duration': info.get('duration'),
'uploader': info.get('uploader'),
'view_count': info.get('view_count'),
'like_count': info.get('like_count'),
'description': info.get('description')[:500] if info.get('description') else '',
'formats': [
{
'format_id': f.get('format_id'),
'ext': f.get('ext'),
'resolution': f"{f.get('height', '?')}p",
'filesize': f.get('filesize'),
'vcodec': f.get('vcodec'),
'acodec': f.get('acodec'),
}
for f in info.get('formats', [])
if f.get('height') # Only video formats
]
}
info = get_video_info("https://youtube.com/watch?v=dQw4w9WgXcQ")
print(json.dumps(info, indent=2))Playlist Downloader#
import yt_dlp
import os
class PlaylistDownloader:
def __init__(self, output_dir="~/Downloads/Playlists"):
self.output_dir = os.path.expanduser(output_dir)
def download_playlist(self, url, quality="1080"):
"""Download an entire playlist with progress tracking."""
ydl_opts = {
'format': f'bestvideo[height<={quality}]+bestaudio/best[height<={quality}]',
'outtmpl': f'{self.output_dir}/%(playlist_title)s/%(playlist_index)03d - %(title)s.%(ext)s',
'merge_output_format': 'mp4',
'ignoreerrors': True, # Skip unavailable videos
'continuedl': True, # Resume partial downloads
'progress_hooks': [self.progress_hook],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
def progress_hook(self, d):
"""Track download progress."""
if d['status'] == 'downloading':
percent = d.get('_percent_str', '0%').strip()
speed = d.get('_speed_str', '?').strip()
print(f"Downloading: {percent} at {speed}", end='\r')
elif d['status'] == 'finished':
print(f"\n✓ Downloaded: {d['filename']}")
# Usage
dl = PlaylistDownloader()
dl.download_playlist("https://youtube.com/playlist?list=PLAYLIST_ID")Configuration Presets#
import yt_dlp
# Common configuration presets as reusable dictionaries
PRESETS = {
'best': {
'format': 'bestvideo+bestaudio/best',
'merge_output_format': 'mp4',
'embedmetadata': True,
'embedthumbnail': True,
},
'1080p': {
'format': 'bestvideo[height<=1080]+bestaudio/best[height<=1080]',
'merge_output_format': 'mp4',
},
'720p': {
'format': 'bestvideo[height<=720]+bestaudio/best[height<=720]',
'merge_output_format': 'mp4',
},
'audio-only': {
'format': 'bestaudio/best',
'extract_audio': True,
'audio_format': 'mp3',
'audio_quality': 0,
'postprocessor_args': {
'ffmpeg': ['-id3v2_version', '3'],
},
},
'mobile': {
'format': 'worst[ext=mp4]',
'outtmpl': '%(title)s_%(id)s.%(ext)s',
},
}
def download_with_preset(url, preset_name='best'):
"""Download using a named preset."""
if preset_name not in PRESETS:
raise ValueError(f"Unknown preset: {preset_name}. Available: {list(PRESETS.keys())}")
opts = PRESETS[preset_name].copy()
opts['outtmpl'] = '~/Downloads/%(title)s.%(ext)s'
with yt_dlp.YoutubeDL(opts) as ydl:
ydl.download([url])
# Usage
download_with_preset("https://youtube.com/watch?v=VIDEO_ID", "1080p")Quality Presets and Recipes#
Common One-Liners#
# Best quality, embed metadata
alias yt-best='yt-dlp -f "bestvideo+bestaudio/best" --merge-output-format mp4 --embed-metadata --embed-thumbnail'
# 1080p with subtitles
alias yt-1080p='yt-dlp -f "bestvideo[height<=1080]+bestaudio/best[height<=1080]" --merge-output-format mp4 --write-subs --sub-langs en'
# Audio only (MP3 320kbps)
alias yt-audio='yt-dlp -x --audio-format mp3 --audio-quality 0 --embed-thumbnail'
# Playlist in order
alias yt-playlist='yt-dlp -f "bestvideo+bestaudio/best" -o "%(playlist)s/%(playlist_index)03d - %(title)s.%(ext)s"'
# Extract and organize by channel
alias yt-channel='yt-dlp -o "%(uploader)s/%(title)s.%(ext)s" --download-archive archive.txt'Configuration File#
Create ~/.config/yt-dlp/config for persistent options:
# Default options for all downloads
-o ~/Downloads/YouTube/%(uploader)s/%(title)s.%(ext)s
--embed-metadata
--embed-thumbnail
--embed-chapters
# Prefer 1080p or best available
-f bestvideo[height<=1080]+bestaudio/best[height<=1080]
# Merge best formats
--merge-output-format mp4
# Retry settings
--retries 10
--fragment-retries 10
--continuedl
# Thumbnails
--write-thumbnailDownload Only Audio#
# Quick audio extraction
yt-dlp -x --audio-format mp3 --audio-quality 0 "URL"
# With metadata and cover art
yt-dlp -x --audio-format mp3 --audio-quality 0 \
--embed-thumbnail --embed-metadata "URL"
# Best quality audio (opus format)
yt-dlp -f "bestaudio[ext=webm]/bestaudio" \
--extract-audio --audio-format opus "URL"Skill Maturity Model#
| Level | Coverage | Reliability | Automation | Maintenance |
|---|---|---|---|---|
| 1: Basic | Single video downloads | Manual, often fails | None | Never updated |
| 2: Functional | Playlists + formats + subs | Mostly works | Basic archive file | Updated occasionally |
| 3: Efficient | Batch + channels + cookies | Reliable with retries | Config file + aliases | Regular updates |
| 4: Automated | Scheduled + archived + organized | Highly reliable | Cron jobs + scripts | Automated dependency updates |
| 5: Production | Full pipeline + monitoring + library | Fault-tolerant | Full CI/CD pipeline | Always current |
Target: Level 3 for personal use. Level 4 for content archival. Level 5 for media library management.
Common Mistakes#
- Not installing ffmpeg: yt-dlp needs ffmpeg to merge separate video and audio streams. Without it, you'll get either video without audio or audio without video from DASH sources.
- Ignoring format codes: Using
-f bestoften gets you a suboptimal format. Always check available formats with-Ffirst and usebestvideo+bestaudiofor the best quality. - Overly aggressive downloading: Using too many concurrent fragments or no rate limiting can get your IP blocked. Add
--limit-rateand reasonable delays. - Storing passwords in command history: Use
--cookies-from-browserinstead of-u/-p. Passwords in shell history are a security risk. - No archive file for playlists: Without
--download-archive, re-running a playlist download will re-download everything. Always use an archive file for incremental updates. - Downloading copyrighted content without permission: Respect copyright laws and platform terms of service. Only download content you have rights to access offline.
- Using outdated yt-dlp: Sites change their APIs frequently. Keep yt-dlp updated with
pip install -U yt-dlpor your package manager. - Not handling errors gracefully: Use
--ignore-errorsfor batch/playlist downloads and--retriesto handle transient failures. - Poor output template organization: Without a good output template, files end up with unwieldy names in a flat directory. Use
%(playlist)s/%(uploader)s/structure. - Assuming all sites work the same: Different sites have different extractors. Some need cookies, some need specific format strings, some don't support certain features. Test first.
More in Media
View all →Audio Extraction
Audio Extraction: Extracting audio from videos, converting formats, and managing audio collections
Legal Downloading
Legal Downloading: Copyright-aware downloading, content that allows offline access, podcast tools, and compliance best practices
Playlist Archiver
Playlist Archiver: Backup playlists, archive channels, scheduled downloading, and offline media libraries