yt-dlp Terminal
Skip to: console examples
API methods
-
def use_cors_webextension():- purpose:
-
considerations:
- this is the default behavior
- calling this method is a way to revert this configuration, if it had previously been changed by a call to:
use_cors_proxy - it requires a browser that supports Manifest v2 (mv2) WebExtensions, which was removed from Chrome in version 139
- some Chromium forks have chosen to not remove support for mv2 WebExtensions; my personal favorite is Supermium
-
def use_cors_proxy(api_url=None, api_key=None):-
input:
- [optional]
api_urlis a corsproxy.io compatible API endpoint - [optional]
api_key
- [optional]
-
examples:
-
use the default corsproxy server:
use_cors_proxy()- which is an instance of the Cloudflare Worker:
corsproxy - deployed to: this API URL
- which is an instance of the Cloudflare Worker:
-
use a locally hosted corsproxy server:
use_cors_proxy('http://localhost:8080/')- which is an instance of the Node.js server:
corsproxy - installed by:
npm install --global "@warren-bank/corsproxy" - started by:
corsproxy --port "8080" --req-insecure - and will also require some web browser configuration to ensure that security policies don't get in the way
- which is an instance of the Node.js server:
-
use the free-tier of the official service provider:
use_cors_proxy('https://corsproxy.io/')- which is not recommended, and is abusive of their generosity
-
use the paid-tier of the official service provider:
use_cors_proxy('https://corsproxy.io/', 'my-api-key')- which requires you to have your own subscription, and personal API key
-
use the default corsproxy server:
-
purpose:
- use a CORS proxy with per-request header overrides as an alternative to using the
Simple Modify Headers - ExtendedWebExtension
- use a CORS proxy with per-request header overrides as an alternative to using the
-
considerations:
- when downloading videos, a lot of data will pass through the CORS proxy
- using a mv2 WebExtension is a much more efficient way to modify request and response HTTP headers
- using a locally hosted corsproxy server is the next-best option
-
input:
-
async def mount_native_directory(virtual_dirpath):-
requirements:
- Chrome 86+
(does not work in Firefox)
- Chrome 86+
-
input:
- [required]
virtual_dirpathis a virtual directory path
ex:"/yt-dlp"
- [required]
-
purpose:
- opens a dialog to choose a native directory
- mounts the chosen native directory in Pyodide at the input virtual directory path
-
references:
- Pyodide: experimental native file system
- Javascript:
showDirectoryPicker
-
requirements:
-
async def download_video(video_url, ydl_opts):-
requirements:
- Chrome 86+
(does not work in Firefox)
- Chrome 86+
-
input:
- [required]
video_urlis the URL for a video to download -
[optional]
ydl_optsis a dictionary of options- this user supplied set of options are merged with and override a default set of options that are hard-coded within the method
- [required]
-
purpose:
- opens a dialog to choose a native directory
- downloads the video, and saves files into the native directory
-
examples:
-
download video url that saves separate audio and video files:
# https://tubitv.com/series/2176/mr-bean-the-animated-series await download_video("https://tubitv.com/tv-shows/381933") # result: success! # saved files: # [85.2 MB, video only] S01E01 - In the Wild.fhlsv6-1134.mp4 # [10.9 MB, audio only] S01E01 - In the Wild.fhlsv6-default-audio-group-English-1.mp4 -
bash script to combine these saved files:
#!/usr/bin/env bash video='S01E01 - In the Wild.fhlsv6-1134.mp4' audio='S01E01 - In the Wild.fhlsv6-default-audio-group-English-1.mp4' output='S01E01 - In the Wild.mp4' ffmpeg -i "$video" -i "$audio" -c copy -map 0:v -map 1:a "$output" -
download video url that saves files that don’t require any post-processing:
# override a default option: ydl_opts = {'debug_printtraffic': False} # https://www.pbs.org/show/washington-week/ await download_video( "https://www.pbs.org/video/washington-week-with-the-atlantic-full-episode-41726-hrkufz/", ydl_opts ) # result: success! # saved files: # [1.28 GB, video + audio] Washington Week with The Atlantic - full episode, 4-17-26.mp4 # [46.5 KB, captions only] Washington Week with The Atlantic - full episode, 4-17-26.en.vtt
-
download video url that saves separate audio and video files:
-
requirements:
CORS
Two different strategies are supported that both accomplish the same goal: to allow cross-origin resource sharing (CORS)
-
The Simple Modify Headers - Extended WebExtension serves 2 important needs:
-
All yt-dlp network requests that include HTTP headers which are not CORS safelisted
are silently modified in Pyodide… such that these headers are encoded,
and embedded into "safe" request headers.
This solves 2 problems:- the presence of any "unsafe" request headers triggers a CORS preflight request
- all forbidden request headers are blocked by browser security policy
and rehydrates the original "unsafe" and possibly "forbidden" HTTP request headers. -
By enabling the "allow CORS" rule set,
HTTP response headers are added to all network traffic…
which allows cross-origin requests to succeed.
-
All yt-dlp network requests that include HTTP headers which are not CORS safelisted
-
A corsproxy server can be used to override both HTTP request and response headers as network traffic passes through.
- The desired request headers are converted to querystring parameters.
- This proxy always adds response headers to allow CORS.
Cookies
The extractor for a supported site will sometimes require imported cookie values.
When this occurs:
-
The Simple Modify Headers - Extended WebExtension can be easily configured…
to add values to the "Cookie" header send in requests to a particular site. -
The "download_video(video_url, ydl_opts)" API method is preconfigured
with a default option that reads cookies from a Netscape format "cookies.txt" file…
located in the selected output directory.
Discover the yt-dlp online web console
Please run the samples and/or type your own Python code to learn yt-dlp.
Print the version of yt-dlp
yt_dlp.version.__version__
Use a locally hosted corsproxy HTTP server:
# npm install --global "@warren-bank/corsproxy"
# corsproxy --port "8080" --req-insecure
use_cors_proxy('http://localhost:8080/')
Use a locally hosted corsproxy HTTPS server:
# npm install --global "@warren-bank/corsproxy"
# corsproxy --tls --port "8081" --req-insecure
use_cors_proxy('https://localhost:8081/')
[Chrome 86+] Download a video, and save files into a native directory
clear# https://tubitv.com/series/2176/mr-bean-the-animated-seriesURL = 'https://tubitv.com/tv-shows/381933'ydl_opts = {'debug_printtraffic': False,}await download_video(URL, ydl_opts)
Extracting information
clearURL = 'https://www.cbsnews.com/live/'ydl_opts = {}with yt_dlp.YoutubeDL(ydl_opts) as ydl:info = ydl.extract_info(URL, download=False)print("Video info = " + json.dumps(ydl.sanitize_info(info), indent=4))
Filter videos
clear# https://tubitv.com/series/2176/mr-bean-the-animated-series# duration of episode: 711 secondsURL = 'https://tubitv.com/tv-shows/381933'# minimum duration (in seconds) to pass through filtermin_duration = 712def longer_than_min_duration(info, *, incomplete):# Download videos longer than a minumum duration.# Remove videos with unknown duration.# Remove live streams.duration = info.get('duration')print("Video duration = " + str(duration) + " seconds")if not duration or info.get('is_live') or duration < min_duration:return "Video does not pass filter."ydl_opts = {'match_filter': longer_than_min_duration,}with yt_dlp.YoutubeDL(ydl_opts) as ydl:info = ydl.extract_info(URL, download=False)print("Video info = " + json.dumps(ydl.sanitize_info(info), indent=4))
Use a custom format selector
clear# https://tubitv.com/series/2176/mr-bean-the-animated-seriesURL = 'https://tubitv.com/tv-shows/381933'def format_selector(ctx):# Select the best video and the best audio that won't result in an mkv.# NOTE: This is just an example and does not handle all cases# formats are already sorted worst to bestformats = ctx.get('formats')[::-1]# best video-only formatbest_video = next(f for f in formats if ((('vcodec' in f and f['vcodec'] != 'none') or('video_ext' in f and f['video_ext'] != 'none'))and ('acodec' not in f or f['acodec'] == 'none')and ('audio_ext' not in f or f['audio_ext'] == 'none')))print("Best video format = " + json.dumps(best_video, indent=4))# find compatible audio extensionaudio_exts = {'mp4': ['mp4','m4a'], 'webm': ['webm']}[best_video['ext']]# best audio-only format w/ same file extension as the best video-only formatbest_audio = next(f for f in formats if ((('acodec' in f and f['acodec'] != 'none') or('audio_ext' in f and f['audio_ext'] != 'none'))and ('vcodec' not in f or f['vcodec'] == 'none')and ('video_ext' not in f or f['video_ext'] == 'none')and ('ext' in f and f['ext'] in audio_exts)))print("Best audio format = " + json.dumps(best_audio, indent=4))# These are the minimum required fields for a merged formatyield {'format_id': f'{best_video["format_id"]}+{best_audio["format_id"]}','ext': best_video['ext'],'requested_formats': [best_video, best_audio],# Must be + separated list of protocols'protocol': f'{best_video["protocol"]}+{best_audio["protocol"]}'}ydl_opts = {'format': format_selector,}with yt_dlp.YoutubeDL(ydl_opts) as ydl:info = ydl.extract_info(URL, download=False)print("Video info = " + json.dumps(ydl.sanitize_info(info), indent=4))