Download Online Media
When to use
- User provides a URL to a video/audio/image on a social platform and wants to save it locally
- Need to archive a clip from X, YouTube, Reddit, Instagram, TikTok, etc.
- Want to extract just the audio (as MP3) from a video
Tool
yt-dlp— actively maintained fork of youtube-dl, supports 1000+ sites. Usually pre-installed (check withwhich yt-dlporyt-dlp --version).ffmpeg— required for merging HLS streams. X/Twitter videos are HLS with separate video + audio manifests; yt-dlp downloads both and merges via ffmpeg. Verify withwhich ffmpegbefore starting.
Basic usage
yt-dlp "<URL>"
Saves to the current directory with an auto-generated filename (typically includes the platform's post/video ID).
Custom output path / filename
yt-dlp -o "<template>" "<URL>"
%(id)s— platform's post/video ID%(title)s— video title (sanitized for filesystem)%(uploader)s— channel/author%(ext)s— file extension (mp4, webm, mp3, …)- Example:
-o "%(uploader)s_%(title)s_%(id)s.%(ext)s"
Quality
Omit flags and let yt-dlp pick the best by default. Override with:
-f b— best pre-merged single-file format-f worst— smallest file-f "bestvideo+bestaudio"— pick streams then merge (default behavior, no flag needed)
⚠️ Do NOT use -f best on platforms with split HLS streams (X/Twitter, some Instagram reels, Reddit hosted video). -f best selects a single pre-merged file. When the platform only exposes video and audio as separate HLS manifests (X is the canonical case), no pre-merged format exists and yt-dlp will pick a video-only stream — the output has no audio, even though the merge step "succeeds" and the file plays. yt-dlp prints a WARNING: "-f best" selects the best pre-merged format which is often not the best option to flag this.
Correct approach for these platforms: omit -f entirely and let yt-dlp pick bestvideo+bestaudio, download both, then merge via ffmpeg. Always run the ffprobe stream check in the "Always verify" section below — the only reliable way to catch the silent audio-loss is to confirm codec_type=audio exists in the output.
⚠️ Windows MSYS / git-bash pitfall (CRITICAL)
On Windows under git-bash or MSYS, do NOT pass MSYS-style paths to -o.
A path like /c/Users/okya1/Videos/x_video.mp4 will be interpreted by yt-dlp as a literal filename (because of the leading slash), and a file named \c\Users\okya1\Videos\x_video.mp4 will be created in your current working directory — not in Videos/. The download reports success, the exit code is 0, and the file "exists" somewhere, but it is at the wrong location with the wrong name. This is silent and easy to miss.
Always use Windows-style paths with forward slashes:
# CORRECT — Windows-style, leading drive letter, forward slashes
yt-dlp -o "C:/Users/okya1/Downloads/x_video_%(id)s.%(ext)s" "https://x.com/user/status/123"
# WRONG — MSYS-style, will create a file with the literal name in cwd
yt-dlp -o "/c/Users/okya1/Videos/x_video.mp4" "https://x.com/user/status/123"
If the user has a default Downloads folder, prefer it over Videos — easier to find, and the Windows shell opens it reliably.
Always verify before reporting success
After yt-dlp exits 0, do not assume the file is where you think it is. Run a real existence check AND a stream check. This two-step verification is non-negotiable:
# 1. Existence + size (use Windows-style path with forward slashes)
ls -lh "C:/Users/okya1/Downloads/<filename>.mp4"
# 2. Validate it's a real video with audio streams (use ffprobe)
"<ffmpeg-bin>/ffprobe.exe" -v error -show_format -show_streams "<file>"
A valid merged file should report at least:
- one
codec_type=videostream (h264 / hevc / av1 / vp9) - one
codec_type=audiostream (aac / mp3 / opus) ← critical: missing audio = silent loss from-f beston split-HLS platforms (see Quality section) - a plausible
duration=(in seconds) TAG:handler_name=Twitter-vork muxer(or similar) — confirms a real merge happened, not a stub
Gotcha: ls and os.path.exists can disagree
In git-bash / MSYS, ls -lh "/c/Users/okya1/Downloads/foo.mp4" and os.path.exists("C:\\Users\\okya1\\Downloads\\foo.mp4") can give different answers for the SAME file when path semantics mix POSIX and Windows. A search_files (which uses ripgrep) and ls can both return the file, but a follow-up os.path.exists call with the same Windows-style path may still report False if the earlier ls was reading through a different path layer.
Safe pattern — run BOTH:
import os
assert os.path.exists(r"C:\Users\okya1\Downloads\foo.mp4"), "file not where you think"
assert os.path.getsize(r"C:\Users\okya1\Downloads\foo.mp4") > 0
After every yt-dlp run, before claiming success. If os.path.exists returns False, fall back to find / ls in the cwd to discover where the file actually went (likely the MSYS-path pitfall produced a literal-named file there).
If os.path.exists (Python) or ls can't find the file you expected, search the actual cwd — you may have fallen into the MSYS-path pitfall above and produced a literal-named file there.
Cleanup of stray files
If you did fall into the MSYS-path pitfall, the bogus file will be in whatever directory you were in when you ran yt-dlp. Find it with:
ls -la | grep -E '^.*'
and remove it (rm) before retrying with the correct path.
Useful flags
-U— update yt-dlp itself (run when a new site breaks or auth changes)-k— keep intermediate files (don't delete separate video/audio streams after merge)--write-thumbnail— also save the thumbnail-x --audio-format mp3— extract audio only as MP3--write-auto-sub --sub-lang <code>— download subtitles (e.g.ko,en,ja)--cookies-from-browser chrome— needed for region-locked / age-gated YouTube videos
Common platform notes
- X / Twitter — videos are HLS; yt-dlp downloads video + audio manifests and merges. May need retry if X rate-limits (403).
- YouTube — works out of the box; some videos need browser cookies for age/region gates.
- Reddit — works, picks highest quality.
- Instagram / TikTok — occasionally need
yt-dlp -Uif format extraction fails. - Vimeo / direct MP4s — usually single-file, no merge needed.
Quick command template (Windows MSYS)
yt-dlp -o "C:/Users/okya1/Downloads/<name>_%(id)s.%(ext)s" "<URL>"
ls -lh "C:/Users/okya1/Downloads/<name>_*.mp4"