CodeVetter · Repo Unpack · Contributor handoff
yt-dlp/yt-dlp
Read CONTRIBUTING.md (developer conventions) and .NO_AI/README.md (contribution policy) first. Style is enforced by ruff + autopep8: 120-col limit, single quotes, banned `from X import Y` for many stdlib modules. Tests run via `python -m devscripts.run_tests` (core/download/<IE name>) or `make test`; download tests need network. The main traps: extractor order is load-bearing, the params dict is the config contract, `lazy_extractors.py` is a generated artifact, plugins load from user dirs by default, and the public extractor/postprocessor API surface is intentionally stable while plugin internals are not.
- Before writing any patch intended for this repo's upstream, note `.NO_AI/README.md`: the project forbids AI/LLM-authored contributions and instructs agents to refuse; CONTRIBUTING.md reiterates under 'AUTOMATED CONTRIBUTIONS (AI / LLM) POLICY'.
- Conventions to follow: CONTRIBUTING.md 'yt-dlp coding conventions' covers mandatory metafields, relaxed-but-simple `_VALID_URL` regexes, fallback patterns, quotes (single for inline, double for docstrings), and the long-lines policy; ruff enforces line-length 120 and bans many `from <stdlib> import` forms.
- Add a new site: create `yt_dlp/extractor/<site>.py` with a `*IE` class (`_VALID_URL`, `_TESTS`, `_real_extract`), register the import in `_extractors.py`, then run `python -m devscripts.run_tests <Site>`; CONTRIBUTING.md documents this flow.
- Test commands: `make test` (pytest -Werror + ruff + autopep8), `make offlinetest` / `devscripts.run_tests core` for no-network runs, `devscripts.run_tests download` for live-site tests, `devscripts.run_tests <Name>` for a single extractor.
- Trap — extractor order is semantic: the first `suitable()` match wins, YouTube classes are hoisted first and `GenericIE` ('.*') must stay last; reordering `_extractors.py` imports changes routing behavior.
- Trap — `lazy_extractors.py` is a generated build artifact (not committed); dev runs use the eager `_extractors` path, and `YTDLP_NO_LAZY_EXTRACTORS` forces eager loading in built binaries.
- Trap — plugins are on by default: `plugin_dirs=['default']` searches user config dirs and PYTHONPATH, so local `yt_dlp_plugins` packages can shadow behavior during debugging; use `YTDLP_NO_PLUGINS` or `--no-plugin-dirs` to isolate.
- Config contract: CLI options are defined in `options.py` `create_parser`, mapped into the `ydl_opts` params dict in `parse_options` (`__init__.py`), and consumed everywhere via `self.params.get(...)`; new options need edits in both places plus README regeneration via `make README.md`.
- Public API boundary: `yt_dlp.__all__` exports `YoutubeDL`, `gen_extractors`, `list_extractors`, `main`, `parse_options`; the pot/jsc provider READMEs explicitly mark everything outside the listed modules as internal-only.
- Debuggability: `-v/--verbose` prints the debug header (`print_debug_header` reports version/python/env/ffmpeg), `write_debug` emits `[debug]` traces, and `debug_printtraffic` makes RequestDirector log handler selection per request.
- Broken-site convention: set `_WORKING = False` on the IE (surfaced as '(CURRENTLY BROKEN)' in --list-extractors and skipped in download tests) rather than deleting the extractor.