yb.download.requirements

Preflight for downloading: does yt-dlp have what YouTube now demands?

YouTube makes yt-dlp solve a JavaScript “n challenge”. Without a solver it fails late and cryptically (No video formats found!). Solving needs two things:

  • yt-dlp’s challenge-solver scripts, shipped by yt-dlp[default] (the yt-dlp-ejs package), which yb[download] depends on;

  • a JavaScript runtime. Deno is the one yt-dlp enables by default, and the one that works.

Deno’s installer puts it in ~/.deno/bin and only adds that to PATH for interactive shells, so a cron job or service often can’t see it. This module also looks there, and yt_dlp_runtime_opts() hands yt-dlp the explicit path, so downloads work without touching PATH.

>>> from yb.download import check_requirements
>>> problems = check_requirements()
>>> print("\n\n".join(problems) or "ready")

Nothing here raises: missing pieces are reported (and, by default, warned) with the command that fixes them.

Module Attributes

DENO

The JavaScript runtime yt-dlp enables by default, and the one that works.

DENO_INSTALL_CMD

Deno's official installer.

DENO_INSTALL_ENV

Env var Deno's installer honours for its install root (binary in <root>/bin).

YT_DLP_MODULE

yt-dlp's import name.

EJS_MODULE

Module that carries yt-dlp's challenge-solver scripts (from yt-dlp[default]).

DENO_UPGRADE_CMD

Command that brings an installed Deno up to date.

DENO_MIN_VERSION_FALLBACK

Fallback for Deno's minimum version when yt-dlp can't be asked (not importable, or too old to say).

DENO_VERSION_TIMEOUT

Seconds to wait for deno --version.

EJS_WIKI_URL

yt-dlp's notes on the JavaScript challenge.

JS_RUNTIMES_OPT

The yt-dlp option naming JS runtimes ({"deno": {"path": ...}}).

Functions

check_requirements(*[, warn, which, ...])

Check what YouTube downloads need, and say how to fix what's missing.

deno_search_dirs()

Where Deno lives when it isn't on PATH.

deno_version(runtime, *[, run])

Ask runtime for its version (deno --version); None if unknown.

find_js_runtime(*[, which, search_dirs])

Find Deno on PATH, else in its standard install location.

has_ejs_scripts(*[, find_spec])

Whether yt-dlp's challenge-solver scripts (yt-dlp-ejs) are installed.

has_module(name, *[, find_spec])

Whether module name is importable, without importing it.

min_deno_version(*[, import_module])

The oldest Deno yt-dlp supports, as a version tuple.

with_runtime_opts(opts)

opts plus the preflight's runtime path, unless opts names runtimes.

yt_dlp_runtime_opts(runtime)

yt-dlp options pointing at runtime when yt-dlp can't find it alone.

Classes

JsRuntime(name, path, on_path)

A JavaScript runtime found for yt-dlp.

Exceptions

DownloadRequirementWarning

A download prerequisite (JS runtime, solver scripts) looks missing.

yb.download.requirements.DENO = 'deno'

The JavaScript runtime yt-dlp enables by default, and the one that works.

yb.download.requirements.DENO_INSTALL_CMD = 'curl -fsSL https://deno.land/install.sh | sh'

Deno’s official installer.

yb.download.requirements.DENO_INSTALL_ENV = 'DENO_INSTALL'

Env var Deno’s installer honours for its install root (binary in <root>/bin).

yb.download.requirements.DENO_MIN_VERSION_FALLBACK = (2, 3, 0)

Fallback for Deno’s minimum version when yt-dlp can’t be asked (not importable, or too old to say). yt-dlp’s own value wins: see min_deno_version().

yb.download.requirements.DENO_UPGRADE_CMD = 'deno upgrade'

Command that brings an installed Deno up to date.

yb.download.requirements.DENO_VERSION_TIMEOUT = 10

Seconds to wait for deno --version.

exception yb.download.requirements.DownloadRequirementWarning[source]

Bases: UserWarning

A download prerequisite (JS runtime, solver scripts) looks missing.

yb.download.requirements.EJS_MODULE = 'yt_dlp_ejs'

Module that carries yt-dlp’s challenge-solver scripts (from yt-dlp[default]).

yb.download.requirements.EJS_WIKI_URL = 'https://github.com/yt-dlp/yt-dlp/wiki/EJS'

yt-dlp’s notes on the JavaScript challenge.

yb.download.requirements.JS_RUNTIMES_OPT = 'js_runtimes'

The yt-dlp option naming JS runtimes ({"deno": {"path": ...}}).

class yb.download.requirements.JsRuntime(name, path, on_path)[source]

Bases: object

A JavaScript runtime found for yt-dlp.

name

yt-dlp’s key for the runtime (e.g. "deno").

path

The executable.

on_path

Whether yt-dlp would find it by name on PATH unaided.

yb.download.requirements.YT_DLP_MODULE = 'yt_dlp'

yt-dlp’s import name.

yb.download.requirements.check_requirements(*, warn=True, which=<function which>, search_dirs=None, find_spec=<function find_spec>, run=<function run>, import_module=<function import_module>, check_deno_version=True)[source]

Check what YouTube downloads need, and say how to fix what’s missing.

Never raises. Each problem is a message ending with the fix.

Parameters:
Return type:

list[str]

Returns:

The problems found; empty when downloads should work.

yb.download.requirements.deno_search_dirs()[source]

Where Deno lives when it isn’t on PATH.

This Python’s scripts dir and its interpreter’s dir (a pip-installed Deno, e.g. yt-dlp[deno], in a venv that isn’t activated: yt-dlp looks there too), then the installer’s $DENO_INSTALL/bin and ~/.deno/bin.

Return type:

tuple[Path, ...]

yb.download.requirements.deno_version(runtime, *, run=<function run>)[source]

Ask runtime for its version (deno --version); None if unknown.

Never raises: a runtime that can’t be run, or prints something unexpected, has an unknown version (which check_requirements() doesn’t flag).

Return type:

tuple[int, ...] | None

yb.download.requirements.find_js_runtime(*, which=<function which>, search_dirs=None)[source]

Find Deno on PATH, else in its standard install location.

Parameters:
Return type:

JsRuntime | None

Returns:

The runtime found, or None.

yb.download.requirements.has_ejs_scripts(*, find_spec=<function find_spec>)[source]

Whether yt-dlp’s challenge-solver scripts (yt-dlp-ejs) are installed.

Return type:

bool

yb.download.requirements.has_module(name, *, find_spec=<function find_spec>)[source]

Whether module name is importable, without importing it.

Return type:

bool

yb.download.requirements.min_deno_version(*, import_module=<function import_module>)[source]

The oldest Deno yt-dlp supports, as a version tuple.

Read from yt-dlp (DenoJsRuntime.MIN_SUPPORTED_VERSION) so it follows yt-dlp’s upgrades; DENO_MIN_VERSION_FALLBACK when yt-dlp isn’t importable or doesn’t say.

Return type:

tuple[int, ...]

yb.download.requirements.with_runtime_opts(opts)[source]

opts plus the preflight’s runtime path, unless opts names runtimes.

The first call per process runs check_requirements() (warning, never raising). An explicit js_runtimes in opts always wins, and skips the check: the caller has chosen a runtime.

Return type:

dict

yb.download.requirements.yt_dlp_runtime_opts(runtime)[source]

yt-dlp options pointing at runtime when yt-dlp can’t find it alone.

Empty when there’s nothing to add (no runtime, or it’s already on PATH).

Return type:

dict[str, dict[str, dict[str, str]]]