# ytdl-org/youtube-dl — codebase unpack

> Canonical page: https://codevetter.com/unpack/youtube-dl

This is a deterministic Repo Unpack scan of ytdl-org/youtube-dl — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 956b8c585591b401a543e409accb163eeaaa1193 (2025-11-26)
- Last upstream commit: [YouTube] Bug-fix for `c1f5c3274a`
- Generated by codevetter 1.12.0 on 2026-09-22
- 980 files scanned · 6.6 MB

## Languages

- Python: 902 files
- Markdown: 15 files
- Shell: 5 files
- JSON: 2 files
- YAML: 2 files

## Repository structure

- youtube_dl/ — 844 files
- test/ — 70 files
- devscripts/ — 34 files
- .github/ — 14 files
- docs/ — 6 files

Probable source entrypoint: `youtube_dl/__init__.py` (inferred from the tree, not upstream docs)

## Source layout — youtube_dl/

- youtube_dl/downloader/ — 12 files
- youtube_dl/extractor/ — 291 files
- youtube_dl/postprocessor/ — 7 files
- youtube_dl/__init__.py — 1 file
- youtube_dl/aes.py — 1 file
- youtube_dl/cache.py — 1 file
- youtube_dl/compat.py — 1 file
- youtube_dl/options.py — 1 file
- youtube_dl/traversal.py — 1 file
- youtube_dl/update.py — 1 file
- youtube_dl/version.py — 1 file

## Structural health signals

Average score 6.3/10 across 96 files; 55 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 956b8c585591 (2025-11-26) [YouTube] Bug-fix for `c1f5c3274a`
- d5f561166b9d (2025-11-26) [core] Re-work format_note display in format list with abbreviated codec name
- d0283f5385ac (2025-11-20) [YouTube] Revert forcing player JS by default
- 6315f4b1dfaa (2025-11-19) [utils] Support additional codecs and dynamic_range
- aeb1254fcf89 (2025-11-04) [YouTube] Fix playlist thumbnail extraction

## Overview

youtube-dl is a dependency-free Python command-line program (and embeddable library) that downloads video and audio from YouTube and ~1200 other sites. A single YoutubeDL orchestrator class routes each user-supplied URL to the first matching InfoExtractor (regex-matched from a registry of ~810 extractor modules), normalizes the returned 'info dict', selects a format via a small DSL, downloads via a protocol-mapped FileDownloader (native HTTP/HLS/DASH or external tools like ffmpeg/aria2c), and runs a postprocessor chain (ffmpeg muxing, metadata, thumbnails). It still maintains Python 2.6 compatibility through a large compat shim and ships as a pip package, a self-updating single-file zip executable, and a py2exe Windows binary.

## System map

The system is a monolithic Python package `youtube_dl` with a layered pipeline: CLI parsing (options.py) -> orchestrator (YoutubeDL.py) -> site extractors (extractor/*) -> protocol downloaders (downloader/*) -> postprocessors (postprocessor/*). Shared helpers live in an enormous utils.py and a Python 2/3 compat.py shim. Distribution is via setuptools console script, a Makefile-built single-file zipapp `youtube-dl`, and py2exe; self-update is built in via update.py against yt-dl.org. There is no persistent daemon or service: state is limited to a JSON filesystem cache, a Netscape-format cookie jar, and a download-archive text file.
- The CLI has three equivalent entrypoints: `python -m youtube_dl` (youtube_dl/__main__.py calls youtube_dl.main()), the `bin/youtube-dl` wrapper script, and the setuptools console_scripts entry `youtube-dl = youtube_dl:main` in setup.py. — [youtube_dl/__main__.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__main__.py) [bin/youtube-dl](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/bin/youtube-dl) [setup.py#L81-84](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.py#L81-L84)
- All CLI startup logic is `_real_main` in youtube_dl/__init__.py: it calls parseOpts, mutates the global `std_headers` dict for --user-agent/--referer/--add-header, validates option combinations, builds the ~120-key `ydl_opts` dict, then runs `ydl.download(all_urls)` inside a `with YoutubeDL(ydl_opts)` context. — [youtube_dl/__init__.py#L49-75](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L49-L75) [youtube_dl/__init__.py#L319-474](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L319-L474)
- `YoutubeDL` (YoutubeDL.py) is the central orchestrator: it holds `params`, a list `_ies` of InfoExtractors, `_pps` postprocessors, `cookiejar`, `cache`, and `_opener` (a urllib OpenerDirector); its class docstring enumerates the full options contract used by CLI and library consumers. — [youtube_dl/YoutubeDL.py#L148-356](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L148-L356) [youtube_dl/YoutubeDL.py#L378-395](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L378-L395)
- The extractor subsystem is a flat package of ~810 modules under youtube_dl/extractor/, each defining InfoExtractor subclasses; they are aggregated by youtube_dl/extractor/extractors.py into `_ALL_CLASSES` (GenericIE appended last) or, for release builds, by a generated `lazy_extractors.py` module. — [youtube_dl/extractor/__init__.py#L3-23](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/__init__.py#L3-L23) [youtube_dl/extractor/extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/extractors.py) [devscripts/make_lazy_extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/make_lazy_extractors.py)
- The downloader layer maps an info dict's `protocol` field to a FileDownloader subclass via PROTOCOL_MAP (rtmp, m3u8_native->HlsFD, m3u8->FFmpegFD, mms/rtsp->RtspFD, f4m, http_dash_segments, ism, niconico_dmc), defaulting to HttpFD. — [youtube_dl/downloader/__init__.py#L29-67](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L29-L67) [youtube_dl/downloader/common.py#L21-57](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L21-L57)
- The postprocessor layer is a small registry: `get_postprocessor(key)` resolves `key + 'PP'` in the module globals; built-ins include FFmpegExtractAudioPP, FFmpegVideoConvertorPP, FFmpegMetadataPP, FFmpegEmbedSubtitlePP, FFmpegMergerPP, EmbedThumbnailPP, XAttrMetadataPP, MetadataFromTitlePP and ExecAfterDownloadPP. — [youtube_dl/postprocessor/__init__.py#L1-40](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/__init__.py#L1-L40) [youtube_dl/postprocessor/ffmpeg.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/ffmpeg.py)
- youtube_dl/utils.py (6863 lines) is the shared toolbox: it defines `std_headers`, `sanitized_Request`, the custom urllib handlers (YoutubeDLHandler, YoutubeDLRedirectHandler, YoutubeDLCookieProcessor, PerRequestProxyHandler), `YoutubeDLCookieJar`, `sanitize_filename`, `GeoUtils`, `match_filter_func`, exception classes, and `DEFAULT_OUTTMPL`. — [youtube_dl/utils.py#L1685-1698](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L1685-L1698) [youtube_dl/utils.py#L2636-3066](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L2636-L3066) [youtube_dl/utils.py#L4662](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L4662)
- youtube_dl/compat.py (3901 lines) is a hand-rolled Python 2.6-3.x compatibility layer aliasing stdlib names as `compat_*` symbols; setup.py classifiers advertise Python 2.6 through 3.8 plus Jython/PyPy/IronPython. — [youtube_dl/compat.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/compat.py) [setup.py#L122-144](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.py#L122-L144)
- All HTTP(S) traffic goes through `YoutubeDL._setup_opener`, which builds a urllib opener from PerRequestProxyHandler, a params-aware HTTPS handler, YoutubeDLCookieProcessor, YoutubeDLHandler (compression + URL fixups), YoutubeDLRedirectHandler, a DataHandler, and a FileHandler whose `file_open` is stubbed to disable the file:// scheme for security. — [youtube_dl/YoutubeDL.py#L2589-2640](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2589-L2640) [youtube_dl/utils.py#L2636-2755](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L2636-L2755)
- The release build produces a self-contained executable: Makefile target `youtube-dl` copies the package into a zip with a `__main__.py` at the zip root, prepends a python shebang and chmod +x; Windows builds use py2exe options embedded in setup.py. — [Makefile#L60-73](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L60-L73) [setup.py#L27-56](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.py#L27-L56)
- Filesystem cache is implemented by `Cache` in youtube_dl/cache.py storing JSON under `$XDG_CACHE_HOME/youtube-dl` (or --cache-dir), keyed by section/key, versioned per release with a minimum-version invalidation check. — [youtube_dl/cache.py#L27-129](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/cache.py#L27-L129)
- External executables are runtime dependencies probed lazily: ffmpeg/avconv/ffprobe located by FFmpegPostProcessor._determine_executables, rtmpdump via downloader/rtmp.py's rtmpdump_version, and phantomjs via extractor/openload.py's PhantomJSwrapper._version; all three are reported in the verbose debug header. — [youtube_dl/postprocessor/ffmpeg.py#L76-155](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/ffmpeg.py#L76-L155) [youtube_dl/YoutubeDL.py#L2560-2570](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2560-L2570) [youtube_dl/extractor/openload.py#L109-110](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/openload.py#L109-L110)
- Tests and lint are driven by `nosetests` (test/ directory, ~34 test modules) via Makefile `test`/`offlinetest` targets and devscripts/run_tests.sh, plus a `flake8 .` codetest target configured in setup.cfg. — [Makefile#L32-52](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L32-L52) [devscripts/run_tests.sh](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/run_tests.sh) [setup.cfg](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.cfg)

## Feature catalog

User-facing surface = one CLI command `youtube-dl` with ~200 options defined in options.py plus the embeddable YoutubeDL API. Features cluster around: site extraction (~1200 supported sites), format/playlist/subtitle selection, sidecar file output (info JSON, description, annotations, thumbnails), ffmpeg-based postprocessing (audio extraction, recoding, embedding), authentication (username/password, netrc, video passwords, Adobe Pass TV providers), geo-restriction bypass, external downloaders, self-update, and simulation/printing modes for scripting.
- Site support: ~810 extractor modules under youtube_dl/extractor/ back roughly 1225 documented sites in docs/supportedsites.md; `--list-extractors` and `--extractor-descriptions` enumerate them at runtime via list_extractors(). — [youtube_dl/extractor/extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/extractors.py) [docs/supportedsites.md](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/docs/supportedsites.md) [youtube_dl/__init__.py#L101-120](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L101-L120)
- Format selection via `-f/--format` implements a mini-DSL (best/worst, format_id, filters like `[height<=?720]`, merge with `+`, fallback with `/`, groups) parsed by `YoutubeDL.build_format_selector` into selector functions. — [youtube_dl/YoutubeDL.py#L1312-1577](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1312-L1577) [youtube_dl/options.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py)
- Playlist features include --playlist-start/--playlist-end, --playlist-items (comma list/ranges), --playlist-reverse, --playlist-random, --max-downloads, and --flat-playlist (extract_flat), implemented in __process_playlist. — [youtube_dl/YoutubeDL.py#L1108-1223](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1108-L1223) [youtube_dl/options.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py)
- Subtitle support: --write-sub/--write-auto-subs/--all-subs/--list-subs download or enumerate subtitle tracks, with --sub-format and --sub-langs filtering in process_subtitles; --convert-subs converts to srt/ass/vtt/lrc via FFmpegSubtitlesConvertorPP. — [youtube_dl/YoutubeDL.py#L1872-1920](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1872-L1920) [youtube_dl/YoutubeDL.py#L2033-2066](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2033-L2066) [youtube_dl/options.py#L884-887](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py#L884-L887)
- Audio extraction `-x/--extract-audio` appends an FFmpegExtractAudio postprocessor honoring --audio-format (best/aac/flac/mp3/m4a/opus/vorbis/wav) and --audio-quality; recoding via --recode-video maps to FFmpegVideoConvertorPP. — [youtube_dl/__init__.py#L259-270](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L259-L270) [youtube_dl/postprocessor/ffmpeg.py#L40-48](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/ffmpeg.py#L40-L48) [youtube_dl/__init__.py#L207-216](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L207-L216)
- Sidecar outputs: --write-info-json, --write-description, --write-annotations, --write-thumbnail/--write-all-thumbnails, and --xattrs (filesystem extended attributes) are all emitted from process_info/_write_info_json/_write_thumbnails. — [youtube_dl/YoutubeDL.py#L2001-2072](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2001-L2072) [youtube_dl/YoutubeDL.py#L2658-2713](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2658-L2713) [youtube_dl/postprocessor/xattrpp.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/xattrpp.py)
- --download-archive records `extractor_key + ' ' + video_id` lines (via _make_archive_id) into a text file; in_download_archive checks it inside _match_entry to skip already-downloaded videos; writes go through locked_file for interprocess safety. — [youtube_dl/YoutubeDL.py#L2341-2387](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2341-L2387) [youtube_dl/YoutubeDL.py#L823-824](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L823-L824)
- Authentication options cover --username/--password (+ interactive getpass when password omitted), --twofactor, --netrc, --video-password, and Adobe Pass TV-provider login via --ap-mso/--ap-username/--ap-password with --ap-list-mso listing MSO_INFO providers. — [youtube_dl/__init__.py#L121-146](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L121-L146) [youtube_dl/extractor/common.py#L1162-1222](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L1162-L1222) [youtube_dl/extractor/adobepass.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/adobepass.py)
- Self-update: `-U/--update` invokes update_self(), which only applies to the zip/frozen builds, verifies a pinned RSA signature over versions.json, then sha256-checks and replaces the running binary (via a .bat swap on Windows). — [youtube_dl/update.py#L34-176](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/update.py#L34-L176) [youtube_dl/options.py#L139-141](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py#L139-L141)
- Geo-bypass fakes an X-Forwarded-For header with a random IP drawn from per-extractor _GEO_COUNTRIES/_GEO_IP_BLOCKS or --geo-bypass-country/--geo-bypass-ip-block, with automatic retry on GeoRestrictedError inside InfoExtractor.extract. — [youtube_dl/extractor/common.py#L480-602](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L480-L602) [youtube_dl/utils.py#L5629-5888](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L5629-L5888)
- External downloaders: --external-downloader selects among aria2c, aria2p (JSON-RPC library), axel, curl, ffmpeg/avconv, httpie and wget; each ExternalFD subclass builds a CLI via _make_cmd and runs it with subprocess.Popen; --external-downloader-args injects extra args. — [youtube_dl/downloader/external.py#L146-536](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L146-L536) [youtube_dl/downloader/__init__.py#L48-55](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L48-L55)
- Simulation/inspection modes: --simulate, --skip-download, --dump-json/--dump-single-json, --print-json, --get-url/--get-title/--get-id/--get-filename family, --list-formats and --list-thumbnails, plus --load-info-json to reprocess a saved info dict. — [youtube_dl/__init__.py#L248-249](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L248-L249) [youtube_dl/YoutubeDL.py#L1921-1950](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1921-L1950) [youtube_dl/YoutubeDL.py#L2273-2285](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2273-L2285)
- Output templating `-o` supports %(field)s substitution over the info dict (plus `epoch`, `autonumber`), NA placeholders, numeric-field format patching, env-var/`~` expansion, and `outtmpl='-'` to stream media to stdout. — [youtube_dl/YoutubeDL.py#L704-791](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L704-L791) [youtube_dl/utils.py#L4662](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L4662) [youtube_dl/utils.py#L2089-2094](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L2089-L2094)
- --exec CMD registers ExecAfterDownloadPP which substitutes `{}` with the shlex-quoted final filepath and runs the command through the system shell after all other postprocessing. — [youtube_dl/postprocessor/execafterdownload.py#L13-31](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/execafterdownload.py#L13-L31) [youtube_dl/__init__.py#L302-308](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L302-L308)
- Rate/robustness controls: --limit-rate (throttling via FileDownloader.slow_down), --retries/--fragment-retries (incl. 'inf'), --sleep-interval/--max-sleep-interval randomized delays, --http-chunk-size segmented downloading, --buffer-size and --no-resize-buffer adaptive block sizing. — [youtube_dl/downloader/common.py#L178-192](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L178-L192) [youtube_dl/downloader/common.py#L371-392](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L371-L392) [youtube_dl/downloader/http.py#L282-316](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/http.py#L282-L316)

## Data flow

Data moves in one direction through a well-defined pipeline. Inputs: CLI args + config files + batch files produce a URL list; the params dict is the single source of truth shared by all layers. Extractors turn a URL into an 'info dict' (a documented schema with _type discriminators video/url/url_transparent/playlist); process_ie_result resolves indirection recursively; process_video_result normalizes fields and selects formats; process_info emits sidecar files and invokes a protocol-matched FileDownloader that writes .part files and renames on completion; the postprocessor chain mutates/moves the final file; bookkeeping lands in the download archive, cookie jar, and JSON cache.
- URL input boundary: positional args plus lines from --batch-file (or stdin via '-') are merged into all_urls; bare URLs are decoded with the preferred encoding before reaching the extractor loop. — [youtube_dl/__init__.py#L83-99](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L83-L99) [youtube_dl/utils.py#L4279](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L4279)
- Configuration input boundary: parseOpts merges /etc/youtube-dl.conf, user config (XDG_CONFIG_HOME/youtube-dl/config, ~/.config/youtube-dl.conf, %APPDATA% variants, ~/youtube-dl.conf), --config-location file, then argv — later entries override earlier ones; --ignore-config skips them. — [youtube_dl/options.py#L42-90](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py#L42-L90) [youtube_dl/options.py#L904-942](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py#L904-L942)
- The info dict is the canonical intermediate representation: extractor/common.py's class docstring specifies mandatory fields (id, title, and url-or-formats) plus ~50 optional fields and the _type discriminator values (video, playlist, multi_video, url, url_transparent, compat_list). — [youtube_dl/extractor/common.py#L98-417](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L98-L417)
- extract_info iterates self._ies calling ie.suitable(url) (compiled _VALID_URL regexes); the first match's extract() runs initialize() (geo-bypass, login) then _real_extract(url); results are stamped with extractor/webpage_url/extractor_key by add_default_extra_info. — [youtube_dl/YoutubeDL.py#L841-878](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L841-L878) [youtube_dl/extractor/common.py#L436-463](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L436-L463) [youtube_dl/extractor/common.py#L568-587](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L568-L587) [youtube_dl/YoutubeDL.py#L993-999](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L993-L999)
- process_ie_result recursively resolves indirection: 'url'/'url_transparent' results re-enter extract_info (possibly pinned to an ie_key); 'playlist'/'multi_video'/'compat_list' results go to __process_playlist which slices entries, injects playlist_* extra_info, and reprocesses each entry via __process_iterable_entry. — [youtube_dl/YoutubeDL.py#L1001-1107](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1001-L1107) [youtube_dl/YoutubeDL.py#L1108-1223](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1108-L1223)
- process_video_result normalizes a video info dict: forces string/numeric field types, sorts thumbnails, fills common fields, computes requested_subtitles, filters malformed formats, sorts formats with _sort_formats, and runs the parsed format selector (from build_format_selector) to produce formats_to_download or requested_formats for A+V merge. — [youtube_dl/YoutubeDL.py#L1645-1870](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1645-L1870) [youtube_dl/YoutubeDL.py#L1312-1577](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1312-L1577)
- process_info is the output boundary: it computes the filename via prepare_filename, writes .description/.annotations.xml/subtitle/.info.json/thumbnail files first, then calls dl() which instantiates the downloader chosen by get_suitable_downloader and copies http_headers via _calc_headers. — [youtube_dl/YoutubeDL.py#L1952-2095](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1952-L2095) [youtube_dl/downloader/__init__.py#L8-11](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L8-L11)
- HttpFD.real_download streams to `filename + '.part'` opened just-in-time via sanitize_open, honoring resume (Range header + Content-Range validation), retry on 5xx/ECONNRESET/timeout, min/max filesize aborts, then try_rename to the final name and try_utime from Last-Modified. — [youtube_dl/downloader/http.py#L27-362](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/http.py#L27-L362)
- Fragmented downloads (HlsFD, DashSegmentsFD, F4mFD, IsmFD) share FragmentFD, which keeps a `.ytdl` JSON bookkeeping file per incomplete download (extractor/downloader state, current_fragment, fragment_count) enabling resume and consistency checks. — [youtube_dl/downloader/fragment.py#L17-50](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/fragment.py#L17-L50) [youtube_dl/downloader/hls.py#L24-60](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/hls.py#L24-L60)
- Postprocessing output boundary: post_process chains info_dict['__postprocessors'] (e.g. FFmpegMergerPP for A+V merge, fixup PPs) before self._pps; each pp.run returns (files_to_delete, info); originals are deleted unless keepvideo. — [youtube_dl/YoutubeDL.py#L2319-2339](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2319-L2339) [youtube_dl/YoutubeDL.py#L2097-2162](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2097-L2162)
- State owners: the cookie jar (YoutubeDLCookieJar, Netscape format, optionally file-backed via --cookies) is owned by YoutubeDL._setup_opener; extractor/player caches (e.g. YouTube 'sigfuncs') live under the Cache section/key namespace; the download archive is a plain text append log. — [youtube_dl/YoutubeDL.py#L2593-2604](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2593-L2604) [youtube_dl/utils.py#L2935-3063](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L2935-L3063) [youtube_dl/cache.py#L55-129](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/cache.py#L55-L129) [youtube_dl/extractor/youtube.py#L1814-1838](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/youtube.py#L1814-L1838)
- Header/cookie hygiene is enforced at boundaries: FileDownloader.download documents stripping Cookie headers; _remove_cookie_header filters them from http_headers; header-supplied cookies are rescoped per-URL domain by _apply_header_cookies to prevent cross-domain leaks. — [youtube_dl/downloader/common.py#L340-347](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L340-L347) [youtube_dl/YoutubeDL.py#L901-972](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L901-L972)

## Behavior traces

Three core flows were traced end-to-end: (1) CLI startup from argv to download; (2) a single-video download from URL through extraction, format selection, HTTP download, fixup and postprocessing to the archive write; (3) the YouTube signature-deciphering path that downloads player JS and interprets it with the built-in JSInterpreter. A fourth trace covers self-update.
- Startup trace: `main()` -> `_real_main()` -> compat_register_utf8 + setproctitle -> parseOpts (reads /etc/youtube-dl.conf, user config, argv) -> header/batch-file handling -> option validation (netrc/password conflicts, numeric parsing of --limit-rate/--min-filesize, playlist bounds) -> postprocessor list assembly -> ydl_opts dict -> `with YoutubeDL(ydl_opts) as ydl` -> optional update_self / cache.remove -> ydl.download(all_urls) -> sys.exit(retcode). — [youtube_dl/__init__.py#L49-124](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L49-L124) [youtube_dl/__init__.py#L319-488](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L319-L488) [youtube_dl/options.py#L904-942](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py#L904-L942)
- YoutubeDL init trace: __init__ stores params, creates Cache, loads header cookies, warns on deprecated params, optionally spawns bidiv/fribidi for --bidi-workaround, then _setup_opener builds cookie jar (loading --cookies file), proxy handler, HTTPS/HTTP handlers, redirect handler and disables file://; auto_init then prints debug header and registers all extractor classes plus configured postprocessors and progress hooks, finishing with register_socks_protocols. — [youtube_dl/YoutubeDL.py#L378-473](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L378-L473) [youtube_dl/YoutubeDL.py#L2589-2640](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2589-L2640)
- Download dispatch trace: download(url_list) -> extract_info -> ie.suitable(url) scan -> __extract_info (wrapped by __handle_extraction_exceptions) -> ie.extract(url) -> _real_extract -> process_ie_result -> dispatch on _type; for 'video' -> process_video_result -> format selection -> process_info -> dl() -> get_suitable_downloader(info) -> fd.download(name, info) -> real_download. — [youtube_dl/YoutubeDL.py#L841-878](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L841-L878) [youtube_dl/YoutubeDL.py#L973-1108](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L973-L1108) [youtube_dl/YoutubeDL.py#L2074-2095](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2074-L2095) [youtube_dl/downloader/__init__.py#L42-67](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L42-L67)
- Playlist trace: process_ie_result sees _type playlist -> __process_playlist computes entries (list slice, PagedList.getslice, or islice over iterables, honoring --playlist-items) -> optional reverse/shuffle -> per entry: _match_entry(incomplete) filter -> __process_iterable_entry -> process_ie_result (recursion back into the same dispatch). — [youtube_dl/YoutubeDL.py#L1108-1223](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1108-L1223) [youtube_dl/YoutubeDL.py#L793-833](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L793-L833)
- HTTP file download trace: FileDownloader.download checks overwrite/resume preconditions and applies randomized sleep_interval -> HttpFD.real_download -> establish_connection() (sanitized_Request with Range header, Content-Range validation, 416 fallback) -> download() loop: read block -> sanitize_open just-in-time -> stream.write -> slow_down rate limit -> _hook_progress -> loop until data_len -> try_rename .part -> try_utime -> 'finished' hook; errors route through RetryDownload/NextFragment/SucceedDownload control-flow exceptions. — [youtube_dl/downloader/common.py#L340-398](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L340-L398) [youtube_dl/downloader/http.py#L86-196](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/http.py#L86-L196) [youtube_dl/downloader/http.py#L197-362](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/http.py#L197-L362)
- YouTube signature trace: _decrypt_signature -> _cached(_extract_signature_function) -> filesystem cache 'sigfuncs' (keyed by player_url + signature-shape id) -> on miss _load_player downloads player JS -> _parse_sig_js regex-locates the sig function -> JSInterpreter.extract_function_from_code produces a Python callable -> the result is reduced to a char-permutation cache_spec and cached; _decrypt_nsig does the analogous flow for the throttling 'n' parameter. — [youtube_dl/extractor/youtube.py#L1839-1976](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/youtube.py#L1839-L1976) [youtube_dl/extractor/youtube.py#L1983-2128](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/youtube.py#L1983-L2128) [youtube_dl/jsinterp.py#L402](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/jsinterp.py#L402) [youtube_dl/jsinterp.py#L1447-1503](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/jsinterp.py#L1447-L1503)
- Post-download trace: on dl() success, process_info applies fixup policy (FFmpegFixupStretchedPP for stretched_ratio, FFmpegFixupM4aPP for m4a_dash, FFmpegFixupM3u8PP for native HLS AAC) -> post_process runs __postprocessors then self._pps -> each pp.run returns files_to_delete which are removed unless keepvideo -> record_download_archive appends `extractor id` -> MaxDownloadsReached checked. — [youtube_dl/YoutubeDL.py#L2175-2246](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2175-L2246) [youtube_dl/YoutubeDL.py#L2319-2387](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2319-L2387)
- Self-update trace: update_self refuses non-zip/non-frozen installs -> GET https://yt-dl.org/update/LATEST_VERSION -> GET versions.json -> rsa_verify(json, signature, pinned UPDATES_RSA_KEY) -> sha256 the downloaded exe/bin blob -> write alongside the running binary (Windows: write .new + a youtube-dl-updater.bat that moves it after exit). — [youtube_dl/update.py#L34-176](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/update.py#L34-L176)
- Error/abort trace: extraction errors funnel through __handle_extraction_exceptions (GeoRestrictedError gets a VPN hint, ExtractorError is reported, unexpected exceptions re-raise unless --ignore-errors); DownloadError propagates to main() -> sys.exit(1); MaxDownloadsReached exits 101; KeyboardInterrupt exits with an interrupted message. — [youtube_dl/YoutubeDL.py#L879-899](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L879-L899) [youtube_dl/__init__.py#L465-485](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L465-L485)

## Testing signals

Testing is unittest-based, executed by nosetests (pynose on Python >=3.9). Coverage splits into offline unit tests (utils, aes, jsinterp, swfinterp, compat, options, YoutubeDL internals, URL matching) and a large live-download suite generated dynamically from each extractor's embedded _TEST/_TESTS dictionaries. Network-dependent suites are explicitly excluded from 'offlinetest'/'core' runs. CI on GitHub Actions spans CPython 2.6-3.12, PyPy and Jython on Ubuntu and Windows, plus a flake8 lint job; the download test-set is continue-on-error.
- Test runner is nosetests: Makefile `test` runs `nosetests --verbose test` then flake8; devscripts/run_tests.sh selects core vs download sets via -I regex on test module names; tox.ini also drives nosetests with the same exclusion list. — [Makefile#L35-52](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L35-L52) [devscripts/run_tests.sh](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/run_tests.sh) [tox.ini#L9-14](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/tox.ini#L9-L14)
- Extractor test cases are embedded in extractor classes as _TEST/_TESTS dicts; InfoExtractor.get_testcases yields them, test/helper.py's gettestcases aggregates across gen_extractors(), and test_download.py dynamically synthesizes one TestDownload.test_<Name> method per case. — [youtube_dl/extractor/common.py#L3247-3260](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L3247-L3260) [test/helper.py#L106-112](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/helper.py#L106-L112) [test/test_download.py#L279-290](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_download.py#L279-L290)
- Download tests hit the real sites: they call ydl.extract_info on the case URL, retry up to 3 times on network-flavored errors (URLError, socket.timeout, HTTP 503), assert expected info_dict fields via expect_info_dict, verify the downloaded file exists and meets file_minsize, and optionally check an md5. — [test/test_download.py#L163-188](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_download.py#L163-L188) [test/test_download.py#L228-267](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_download.py#L228-L267) [test/parameters.json](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/parameters.json)
- test/parameters.json supplies base params for tests (test=true limiting downloads to _TEST_FILE_SIZE, writeinfojson=true, socket_timeout=20, fixup=never); test/helper.py merges an optional untracked local_parameters.json for credentials. — [test/parameters.json](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/parameters.json) [test/helper.py#L27-39](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/helper.py#L27-L39) [youtube_dl/downloader/common.py#L59](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L59)
- Offline-only coverage is defined by exclusion: Makefile offlinetest and tox defaults exclude test_age_restriction, test_download, test_iqiyi_sdk_interpreter, test_socks, test_subtitles, test_write_annotations, test_youtube_lists and test_youtube_signature — i.e. anything needing network or live sites. — [Makefile#L43-52](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L43-L52) [tox.ini#L9-13](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/tox.ini#L9-L13) [devscripts/run_tests.sh](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/run_tests.sh)
- Unit-level suites cover utils (test_utils.py), JS interpreter (test_jsinterp.py), AES (test_aes.py against testdata/), SWF interpreter (test_swfinterp.py against test/swftests/), URL matching across extractors (test_all_urls.py), YoutubeDL internals (test_YoutubeDL.py), options parsing (test_options.py), netrc, cache, traversal and compat. — [test/test_jsinterp.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_jsinterp.py) [test/test_swfinterp.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_swfinterp.py) [test/test_all_urls.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_all_urls.py) [test/test_YoutubeDL.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_YoutubeDL.py)
- Test doubles exist in helper.py: FakeYDL (a YoutubeDL with auto_init=False that records download() calls and raises on trouble), FakeLogger, and expect_warnings/expect_info_dict assertion helpers that also fail when the extractor produces checkable fields missing from the test definition. — [test/helper.py#L66-104](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/helper.py#L66-L104) [test/helper.py#L209-246](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/helper.py#L209-L246) [test/helper.py#L265-272](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/helper.py#L265-L272)
- CI (.github/workflows/ci.yml) builds a matrix over CPython 2.6 through 3.12 plus pypy and jython, ubuntu-22.04 primary with windows-2022 and jython extras; it includes custom steps to build Python 2.6/2.7/3.next and install nose/pynose per version; download and jython legs are continue-on-error. — [.github/workflows/ci.yml#L3-11](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L3-L11) [.github/workflows/ci.yml#L105-145](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L105-L145) [.github/workflows/ci.yml#L462-481](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L462-L481)
- Lint is flake8 with repo-tuned ignores (E402,E501,E731,E741,W503) and excludes generated/excluded files; it runs as a separate CI job on Python 3.9 and as `make codetest`. — [setup.cfg](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.cfg) [.github/workflows/ci.yml#L469-481](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L469-L481) [Makefile#L32-33](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L32-L33)
- Notable gaps: there is no coverage tooling enabled by default (commented-out --with-coverage), most of the ~800 extractors rely solely on their embedded live tests (marked skip/_WORKING when broken), and legacy interpreters (Python 2.6, Jython) mean modern test runners can't even execute parts of the matrix. (inferred) — [Makefile#L36-37](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L36-L37) [.github/workflows/ci.yml#L462-468](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L462-L468) [test/test_download.py#L113-126](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_download.py#L113-L126)

## Risk map

The highest-risk areas are shell-outs (postprocessor --exec with shell=True, external downloader and ffmpeg command construction), credential handling (cookies, netrc, passwords), the self-update path that replaces the running binary, and the eval-adjacent JS/SWF interpreters. The codebase also carries heavy legacy weight: Python 2.6 compat shims, dead modules (swfinterp is only referenced by tests), and fragile regex-based scraping across ~800 site extractors that break silently when sites change.
- ExecAfterDownloadPP.run executes the user's --exec command with subprocess.call(shell=True); the {} placeholder is shlex-quoted, but the rest of the command string is raw shell — a deliberate but real command-execution surface. — [youtube_dl/postprocessor/execafterdownload.py#L18-30](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/execafterdownload.py#L18-L30)
- External downloaders and ffmpeg are spawned via subprocess.Popen with argv built from info_dict fields (url, http_headers, cookies); cookies are serialized into temp files or -cookies/-headers args, so a malicious extractor result could influence command lines, though lists (not shell strings) are used. — [youtube_dl/downloader/external.py#L127-138](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L127-L138) [youtube_dl/downloader/external.py#L373-490](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L373-L490)
- Self-update replaces the running executable with a network download; it is gated by an RSA signature over versions.json plus a per-file sha256 check, but trusts a hard-coded RSA key and yt-dl.org availability; the Windows path writes and spawns a .bat file that swaps the exe. — [youtube_dl/update.py#L34-176](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/update.py#L34-L176)
- Cookie leak mitigations indicate a history of security issues: _remove_cookie_header strips Cookie from http_headers, _load_cookies scopes header-supplied cookies to the target domain (referencing yt-dlp advisory GHSA-v8mc-9377-rwjj), and YoutubeDLRedirectHandler drops Cookie on redirect; the file:// scheme is explicitly disabled citing issue #8227. — [youtube_dl/YoutubeDL.py#L901-972](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L901-L972) [youtube_dl/utils.py#L3090-3152](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L3090-L3152) [youtube_dl/YoutubeDL.py#L2623-2631](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2623-L2631)
- _UnsafeExtensionError enforces an extension whitelist on output files to prevent path traversal/arbitrary file overwrite (referencing yt-dlp advisory GHSA-79w7-vh3h-8g4j); --no-check-extensions sets the lenient flag to bypass it. — [youtube_dl/utils.py#L6733-6863](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L6733-L6863) [youtube_dl/YoutubeDL.py#L134-145](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L134-L145) [youtube_dl/__init__.py#L177-178](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L177-L178)
- Aria2pFD connects to an aria2 daemon at http://localhost:6800 with an empty RPC secret and trusts the aria2p library being importable — local RPC without authentication. — [youtube_dl/downloader/external.py#L283-340](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L283-L340)
- JSInterpreter is a partial JS engine that executes extracted player code semantics; _extract_sig_fn even splices a regex-extracted 'useful values' snippet into the interpreted function — a YouTube player change silently breaks decryption, and malformed code raises JSInterpreter.Exception. — [youtube_dl/jsinterp.py#L402](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/jsinterp.py#L402) [youtube_dl/extractor/youtube.py#L1905-1952](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/youtube.py#L1905-L1952) [youtube_dl/extractor/youtube.py#L1983-1999](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/youtube.py#L1983-L1999)
- swfinterp.py (834 lines, SWFInterpreter) is effectively dead production code — the only importer in the tree is test/test_swfinterp.py; PhantomJSwrapper in extractor/openload.py survives only as a dependency of pornhub.py and a debug-header version probe. — [youtube_dl/swfinterp.py#L185](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/swfinterp.py#L185) [test/test_swfinterp.py#L18](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/test_swfinterp.py#L18) [youtube_dl/extractor/pornhub.py#L54](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/pornhub.py#L54) [youtube_dl/YoutubeDL.py#L2562](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2562)
- Extractors are regex-fragile by design: _search_regex raises RegexNotFoundError on missing patterns and CONTRIBUTING.md explicitly warns that extractor breakage on site changes is expected; broken extractors are flagged via the _WORKING class attribute rather than removed. — [youtube_dl/extractor/common.py#L1063-1098](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L1063-L1098) [youtube_dl/extractor/common.py#L415-416](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L415-L416) [CONTRIBUTING.md#L174-188](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L174-L188)
- --call-home/--verbose debug path sends requests to https://yt-dl.org/ip and /latest/version, disclosing the user's public IP to the project's own server. — [youtube_dl/YoutubeDL.py#L2578-2587](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2578-L2587)
- Python 2.6 support is still load-bearing: compat.py shims, _workaround_optparse_bug9161, py2exe paths, and CI builds Python 2.6/2.7 from source — code paths that cannot be exercised on modern interpreters and constrain idioms (no f-strings, unicode_literals everywhere). (inferred) — [youtube_dl/compat.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/compat.py) [.github/workflows/ci.yml#L249-314](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L249-L314) [youtube_dl/__init__.py#L53](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L53) [setup.py#L128-135](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.py#L128-L135)
- Passwords entered interactively (compat_getpass) or passed via -p/--password appear in argv and config files; _hide_login_info only scrubs them from verbose debug echoes, not from process listings or config storage. (inferred) — [youtube_dl/options.py#L24-39](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/options.py#L24-L39) [youtube_dl/__init__.py#L143-146](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L143-L146)

## Extension points

The codebase is explicitly designed around plugin points. Primary: site extractors subclass InfoExtractor, define _VALID_URL + _real_extract, embed _TEST dicts, and register via an import line in extractor/extractors.py (plus optional lazy_extractors generation). Secondary: downloaders plug into PROTOCOL_MAP or the external-downloader _BY_NAME registry, postprocessors resolve by the '<key>PP' naming convention, and embedders hook progress_hooks, match_filter, custom logger, and the postprocessors param list.
- New site support follows a documented recipe: create youtube_dl/extractor/<name>.py with an InfoExtractor subclass (class name ending in IE), define _VALID_URL regex and _real_extract, add a _TEST dict, and add one import line to extractor/extractors.py. — [CONTRIBUTING.md#L99-166](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L99-L166) [youtube_dl/extractor/common.py#L383-417](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L383-L417) [youtube_dl/extractor/extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/extractors.py)
- Extractor ordering is semantic: gen_extractor_classes returns _ALL_CLASSES in import order and the first suitable() match wins; GenericIE is appended last as the catch-all, so new extractors must be added before it implicitly by import placement. — [youtube_dl/extractor/__init__.py#L11-30](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/__init__.py#L11-L30) [youtube_dl/YoutubeDL.py#L866-875](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L866-L875)
- Lazy loading is a compile-time extension artifact: devscripts/make_lazy_extractors.py generates youtube_dl/extractor/lazy_extractors.py from _ALL_CLASSES; this constrains extractor authors — overridden suitable() must import its own dependencies and avoid _VALID_URL references (documented in InfoExtractor's docstring). — [devscripts/make_lazy_extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/make_lazy_extractors.py) [youtube_dl/extractor/common.py#L391-395](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L391-L395) [youtube_dl/extractor/__init__.py#L3-8](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/__init__.py#L3-L8) [Makefile#L114-118](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L114-L118)
- SearchInfoExtractor is the extension base for 'keyword' providers (e.g. ytsearch): subclasses set _SEARCH_KEY and implement _real_extract over a query string, producing a playlist of url_results. — [youtube_dl/extractor/common.py#L3365-3406](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L3365-L3406)
- url_result()/playlist_result() are the delegation mechanism: an extractor can emit _type 'url' entries with an ie_key to hand a URL off to another extractor, enabling composite extractors without subclassing. — [youtube_dl/extractor/common.py#L365-381](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L365-L381) [youtube_dl/extractor/common.py#L1031-1061](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L1031-L1061) [youtube_dl/YoutubeDL.py#L1009-1019](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1009-L1019)
- New downloaders subclass FileDownloader and implement real_download(filename, info_dict); protocol-based selection goes through PROTOCOL_MAP in downloader/__init__.py, while external-executable downloaders subclass ExternalFD (_make_cmd) and self-register in _BY_NAME keyed by executable basename. — [youtube_dl/downloader/common.py#L396-398](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L396-L398) [youtube_dl/downloader/__init__.py#L29-39](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L29-L39) [youtube_dl/downloader/external.py#L85-138](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L85-L138) [youtube_dl/downloader/external.py#L520-536](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L520-L536)
- New postprocessors subclass PostProcessor with a run(info)->(files_to_delete, info) contract; registration is by naming convention — a param dict {'key': 'X'} resolves to class XPP via get_postprocessor, and the CLI assembles the list in __init__. — [youtube_dl/postprocessor/common.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/common.py) [youtube_dl/postprocessor/__init__.py#L21-22](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/__init__.py#L21-L22) [youtube_dl/__init__.py#L253-308](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L253-L308) [youtube_dl/YoutubeDL.py#L463-468](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L463-L468)
- Library/embedding hooks: YoutubeDL accepts progress_hooks (status dicts with downloading/error/finished and byte/eta/speed fields), a logger object, match_filter callable, extract_flat mode, and a postprocessors list — the documented embedding API. — [youtube_dl/YoutubeDL.py#L267-290](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L267-L290) [youtube_dl/YoutubeDL.py#L313-317](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L313-L317) [youtube_dl/YoutubeDL.py#L522-525](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L522-L525) [README.md#L1444](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/README.md#L1444)
- Per-request behaviors can be injected through info_dict fields read downstream: http_headers, downloader_options (http_chunk_size), fragments, protocol, stretched_ratio, __postprocessors and __files_to_merge — extractors/downstream code cooperate through these keys. — [youtube_dl/YoutubeDL.py#L2085-2095](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2085-L2095) [youtube_dl/downloader/http.py#L48-50](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/http.py#L48-L50) [youtube_dl/extractor/common.py#L167-219](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L167-L219)
- Geo-bypass is itself an extension surface: extractors declare _GEO_COUNTRIES/_GEO_IP_BLOCKS/_GEO_BYPASS and _initialize_geo_bypass can be invoked mid-extraction with a context dict when restriction info is only known after the first response. — [youtube_dl/extractor/common.py#L400-413](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L400-L413) [youtube_dl/extractor/common.py#L480-567](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L480-L567)

## Contributor handoff

For an agent working in this repo: read CONTRIBUTING.md's developer instructions and extractor/common.py's giant docstring first; the info-dict contract and the 'first suitable() wins' ordering are the two invariants that matter most. Python 2.6-compatible style (unicode_literals, compat_* aliases, no f-strings, %-formatting) is mandatory and enforced by CI. Tests are nosetests; extractor changes get a live _TEST; run flake8 with the repo's setup.cfg ignores. Generated files (lazy_extractors.py, README.md, completions, man page) are produced by Makefile/devscripts — edit sources, not artifacts.
- Read first: youtube_dl/extractor/common.py's InfoExtractor docstring (the entire info-dict schema), CONTRIBUTING.md 'DEVELOPER INSTRUCTIONS' + 'youtube-dl coding conventions', youtube_dl/YoutubeDL.py's options docstring, and youtube_dl/__init__.py _real_main for how params map to CLI flags. — [youtube_dl/extractor/common.py#L98-417](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L98-L417) [CONTRIBUTING.md#L71-188](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L71-L188) [youtube_dl/YoutubeDL.py#L148-356](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L148-L356) [youtube_dl/__init__.py#L49-488](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L49-L488)
- Adding an extractor: new file in youtube_dl/extractor/, class name must end in 'IE', _VALID_URL with a named (?P<id>...) group is conventional, import the class in extractors.py (order = precedence), include a _TEST dict with a real URL; commit style is '[name] Add new extractor'. — [CONTRIBUTING.md#L111-166](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L111-L166) [youtube_dl/extractor/common.py#L386-395](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L386-L395) [youtube_dl/extractor/extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/extractors.py)
- Mandatory info-dict fields are id and title plus either url or formats; everything else must be extracted defensively (helpers: _search_regex with default=, try_get, traverse_obj, int_or_none/float_or_none) because extractors must tolerate missing optional data. — [youtube_dl/extractor/common.py#L113-121](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L113-L121) [CONTRIBUTING.md#L180-188](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L180-L188) [test/helper.py#L209-217](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/test/helper.py#L209-L217)
- Run tests with `python test/test_download.py TestDownload.test_<Name>` for a single extractor; `make offlinetest` (or nosetests with the exclusion list) for network-free checks; full `make test` requires live network access and will fail on sites that changed since the pinned commit. — [CONTRIBUTING.md#L154](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L154) [Makefile#L35-52](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L35-L52) [devscripts/run_tests.sh](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/run_tests.sh)
- Lint with `flake8 .` honoring setup.cfg (ignores E402/E501/E731/E741/W503, excludes generated files); style is %-formatting, `from __future__ import unicode_literals` at top of every file, compat_* imports from youtube_dl/compat.py instead of py3-only stdlib paths. — [setup.cfg](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.cfg) [.github/workflows/ci.yml#L469-481](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/.github/workflows/ci.yml#L469-L481) [youtube_dl/compat.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/compat.py)
- Lazy-extractor constraint is a known trap: if you override suitable() or reference _VALID_URL oddly, devscripts/make_lazy_extractors.py output can break — keep suitable() self-importing and prefer plain _VALID_URL regexes; regenerate via `make lazy-extractors` or `python setup.py build_lazy_extractors`. — [youtube_dl/extractor/common.py#L391-395](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L391-L395) [devscripts/make_lazy_extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/make_lazy_extractors.py) [setup.py#L86-100](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/setup.py#L86-L100) [Makefile#L114-118](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L114-L118)
- GenericIE must remain the last resort: _ALL_CLASSES appends it explicitly and many extractors emit url_result(ie=GenericIE.ie_key()) delegates; do not reorder extractors casually — the first regex match wins. — [youtube_dl/extractor/__init__.py#L11-16](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/__init__.py#L11-L16) [youtube_dl/extractor/generic.py#L137](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/generic.py#L137) [youtube_dl/extractor/generic.py#L3762](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/generic.py#L3762)
- Generated artifacts to not hand-edit: youtube_dl/extractor/lazy_extractors.py (devscripts/make_lazy_extractors.py), README.md/CONTRIBUTING.md (devscripts/make_readme.py/make_contributing.py), docs/supportedsites.md (make_supportedsites.py), completions and man page (Makefile targets). — [Makefile#L75-118](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L75-L118) [devscripts/make_lazy_extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/make_lazy_extractors.py) [devscripts/make_supportedsites.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/make_supportedsites.py)
- Safe edit boundaries: adding a new extractor file + extractors.py import is low-blast-radius; editing extractor/common.py, utils.py, YoutubeDL.py or downloader/common.py affects every site — keep changes additive, preserve py2.6 compatibility, and remember `_real_main` mutates the global std_headers dict and params dicts are shared references. (inferred) — [youtube_dl/__init__.py#L59-75](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L59-L75) [youtube_dl/downloader/__init__.py#L8-11](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L8-L11) [youtube_dl/compat.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/compat.py)
- Debugging support built in: --verbose prints the debug header (version, git HEAD, Python, exe versions, proxy map), --write-pages/--dump-pages dump raw server responses, --print-traffic logs HTTP, and --youtube-print-sig-code prints the extracted signature function — use these before touching extractor code. — [youtube_dl/YoutubeDL.py#L2497-2576](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2497-L2576) [youtube_dl/extractor/youtube.py#L1863-1903](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/youtube.py#L1863-L1903) [CONTRIBUTING.md#L1-40](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L1-L40)

Source repository: https://github.com/ytdl-org/youtube-dl
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/youtube-dl.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
