yt-dlp Terminal

Skip to: console examples


API methods

CORS

Two different strategies are supported that both accomplish the same goal: to allow cross-origin resource sharing (CORS)

  1. The Simple Modify Headers - Extended WebExtension serves 2 important needs:
    1. 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:
      1. the presence of any "unsafe" request headers triggers a CORS preflight request
      2. all forbidden request headers are blocked by browser security policy
      The WebExtension recognizes this encoding convention,
      and rehydrates the original "unsafe" and possibly "forbidden" HTTP request headers.
    2. By enabling the "allow CORS" rule set,
      HTTP response headers are added to all network traffic…
      which allows cross-origin requests to succeed.
  2. 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:


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-series
URL = 'https://tubitv.com/tv-shows/381933'

ydl_opts = {
    'debug_printtraffic': False,
}

await download_video(URL, ydl_opts)

Extracting information

clear

URL = '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 seconds
URL = 'https://tubitv.com/tv-shows/381933'

# minimum duration (in seconds) to pass through filter
min_duration = 712

def 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-series
URL = '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 best
    formats = ctx.get('formats')[::-1]

    # best video-only format
    best_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 extension
    audio_exts = {'mp4': ['mp4','m4a'], 'webm': ['webm']}[best_video['ext']]
    # best audio-only format w/ same file extension as the best video-only format
    best_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 format
    yield {
        '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))