| name | video-downloader |
| description | Video Downloader: Using yt-dlp to download videos from YouTube, Bilibili, Twitter, and thousands of other sites |
| metadata | {"author":"cosmicstack-labs","version":"1.0.0","category":"media-download","tags":["video-download","yt-dlp","youtube-downloader","media-download","bilibili"]} |
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)
brew install yt-dlp
brew install ffmpeg
Linux (Ubuntu/Debian)
python3 -m pip install -U yt-dlp
sudo apt install yt-dlp ffmpeg
Windows
# 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/releases
Verify Installation
yt-dlp --version
yt-dlp --help | head -20
Basic Download Commands
Simple Video Download
yt-dlp "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
yt-dlp -o "%(title)s.%(ext)s" "https://youtube.com/watch?v=VIDEO_ID"
Format Selection
yt-dlp -F "https://youtube.com/watch?v=VIDEO_ID"
yt-dlp -f "bestvideo+bestaudio" "URL"
yt-dlp -f "bestvideo[height<=1080]+bestaudio/best[height<=1080]" "URL"
yt-dlp -f "worst" "URL"
yt-dlp -f "bestaudio" -x --audio-format mp3 "URL"
yt-dlp -f "137+140" "URL"
Output Templates
yt-dlp -o "%(playlist_title)s/%(playlist_index)s - %(title)s.%(ext)s" "URL"
yt-dlp -o "~/Downloads/YouTube/%(uploader)s/%(title)s.%(ext)s" "URL"
yt-dlp -o "%(upload_date>%Y-%m-%d)s - %(title)s.%(ext)s" "URL"
Playlist and Channel Downloading
Download Full Playlists
yt-dlp "https://youtube.com/playlist?list=PLAYLIST_ID"
yt-dlp --playlist-start 1 --playlist-end 10 "PLAYLIST_URL"
yt-dlp "https://youtube.com/playlist?list=LL"
yt-dlp --playlist-reverse "PLAYLIST_URL"
Channel Downloads
yt-dlp "https://www.youtube.com/@ChannelName/videos"
yt-dlp --max-downloads 5 "https://www.youtube.com/@ChannelName/videos"
yt-dlp -o "%(channel)s/%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s" "URL"
Archive File Management
yt-dlp --download-archive archive.txt "PLAYLIST_URL"
yt-dlp --download-archive ~/.yt-dlp-archive "CHANNEL_URL"
Subtitle Downloading
Automatic and Manual Subtitles
yt-dlp --write-subs --sub-langs all "URL"
yt-dlp --write-subs --sub-langs "en,es,fr" "URL"
yt-dlp --write-auto-subs --sub-langs "en" "URL"
yt-dlp --embed-subs --sub-langs "en" "URL"
yt-dlp --write-subs --sub-langs "en" --convert-subs srt "URL"
Authentication and Cookies
Using Browser Cookies
yt-dlp --cookies-from-browser chrome "URL"
yt-dlp --cookies-from-browser firefox:"~/Library/Application Support/Firefox/Profiles/xxxx.default-release" "URL"
yt-dlp --cookies-from-browser chrome --cookies cookies.txt "URL"
yt-dlp --cookies cookies.txt "URL"
Login Credentials (Less Recommended)
yt-dlp -u "username" -p "password" "URL"
yt-dlp --netrc "URL"
Download Speed and Performance
Speed Optimization
yt-dlp --fragment-retries 10 --concurrent-fragments 5 "URL"
yt-dlp --limit-rate 500K "URL"
yt-dlp --retries 10 --fragment-retries 10 "URL"
yt-dlp --throttled-rate 100K "URL"
Proxy Configuration
yt-dlp --proxy "http://proxy.example.com:8080" "URL"
yt-dlp --proxy "socks5://127.0.0.1:1080" "URL"
yt-dlp --proxy "socks5://127.0.0.1:9050" "URL"
yt-dlp --proxy "http://proxy.example.com:8080" --no-proxy "https://youtube.com" "URL"
Post-Processing with FFmpeg
Merging and Conversion
yt-dlp -f "bestvideo+bestaudio" --merge-output-format mp4 "URL"
yt-dlp --merge-output-format mkv "URL"
yt-dlp -x --audio-format mp3 --audio-quality 0 "URL"
Custom FFmpeg Options
yt-dlp --postprocessor-args "ffmpeg:-vf 'scale=1280:720'" "URL"
yt-dlp --parse-metadata "%(title)s:%(meta_title)s" "URL"
yt-dlp --embed-thumbnail "URL"
Embedding Metadata
yt-dlp --embed-metadata --embed-thumbnail "URL"
yt-dlp --embed-chapters "URL"
yt-dlp --write-info-json "URL"
Batch Downloading
From a File List
yt-dlp --batch-file urls.txt
yt-dlp --batch-file urls.txt --match-filter "duration < 3600"
Advanced Batch Processing
yt-dlp --match-title "tutorial" --batch-file urls.txt
yt-dlp --reject-title "live stream" --batch-file urls.txt
yt-dlp --dateafter "20240101" --datebefore "20241231" "CHANNEL_URL"
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)
}
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')
]
}
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,
'continuedl': True,
'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']}")
dl = PlaylistDownloader()
dl.download_playlist("https://youtube.com/playlist?list=PLAYLIST_ID")
Configuration Presets
import yt_dlp
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])
download_with_preset("https://youtube.com/watch?v=VIDEO_ID", "1080p")
Quality Presets and Recipes
Common One-Liners
alias yt-best='yt-dlp -f "bestvideo+bestaudio/best" --merge-output-format mp4 --embed-metadata --embed-thumbnail'
alias yt-1080p='yt-dlp -f "bestvideo[height<=1080]+bestaudio/best[height<=1080]" --merge-output-format mp4 --write-subs --sub-langs en'
alias yt-audio='yt-dlp -x --audio-format mp3 --audio-quality 0 --embed-thumbnail'
alias yt-playlist='yt-dlp -f "bestvideo+bestaudio/best" -o "%(playlist)s/%(playlist_index)03d - %(title)s.%(ext)s"'
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-thumbnail
Download Only Audio
yt-dlp -x --audio-format mp3 --audio-quality 0 "URL"
yt-dlp -x --audio-format mp3 --audio-quality 0 \
--embed-thumbnail --embed-metadata "URL"
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 best often gets you a suboptimal format. Always check available formats with -F first and use bestvideo+bestaudio for the best quality.
- Overly aggressive downloading: Using too many concurrent fragments or no rate limiting can get your IP blocked. Add
--limit-rate and reasonable delays.
- Storing passwords in command history: Use
--cookies-from-browser instead 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-dlp or your package manager.
- Not handling errors gracefully: Use
--ignore-errors for batch/playlist downloads and --retries to 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.