yb.download

Media download (yt-dlp) — fetch videos, audio, and their metadata.

A separate, optionally-installed module (pip install 'yb[download]'). Common use:

>>> from yb.download import download_youtube_video
>>> result = download_youtube_video("https://youtu.be/PRa9ciOe-us")
>>> print(result.path, result.video_id)

For audio only — e.g. to feed a transcription or podcast workflow — use download_youtube_audio(), which keeps the source format by default and converts only when you ask it to (conversion needs ffmpeg):

>>> from yb.download import download_youtube_audio
>>> ep = download_youtube_audio(url, audio_format="mp3")

For sound or clip sourcing, fetch just a span (seconds or "mm:ss"; needs ffmpeg, see yb.download.ranges). The span is recorded in result.info["download_range"] for provenance:

>>> clip = download_youtube_audio(url, start="0:07.9", end="0:08.75")

YouTube downloads need a JavaScript runtime (Deno) and yt-dlp’s solver scripts; check_requirements() (or yb check) says what’s missing and how to install it. The first download in a process runs it and warns.

Functions

download_youtube_video(url, *[, ...])

Download a YouTube video to download_dir (default ~/Downloads).

download_youtube_audio(url, *[, ...])

Download only a video's audio (no video stream).

youtube_video_info(url, *[, extra_opts, ...])

Fetch a video's metadata without downloading it.

download_youtube_playlist(url, *[, ...])

Download all (or a selected subset of) a YouTube playlist's videos.

youtube_playlist_info(url, *[, ...])

Fetch a playlist's per-video metadata without downloading.

default_download_dir()

Resolve the default download directory ($YB_DOWNLOAD_DIR or ~/Downloads).

convert_audio(src, audio_format, *[, ...])

Convert src to audio_format, returning the resulting path.

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

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

find_js_runtime(*[, which, search_dirs])

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

parse_timestamp(value)

Seconds from a number or a "[[h:]m:]s[.fraction]" string.

Classes

DownloadResult(path, info[, sidecars])

Outcome of a download.

JsRuntime(name, path, on_path)

A JavaScript runtime found for yt-dlp.

TimeRange([start, end])

A span of a video, in seconds.

Exceptions

AudioConversionError

Raised when audio could not be converted to the requested format.

DownloadRequirementWarning

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

exception yb.download.AudioConversionError[source]

Bases: RuntimeError

Raised when audio could not be converted to the requested format.

exception yb.download.DownloadRequirementWarning[source]

Bases: UserWarning

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

class yb.download.DownloadResult(path, info, sidecars=<factory>)[source]

Bases: object

Outcome of a download.

path

The downloaded media file.

info

A trimmed metadata dict (see _INFO_FIELDS).

sidecars

Map of extra artifacts written (info_json, thumbnail, description, subtitles → path(s)).

property video_id: str

The YouTube video id.

class yb.download.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.

class yb.download.TimeRange(start=0.0, end=None)[source]

Bases: object

A span of a video, in seconds. end=None means “to the end”.

as_info()[source]

The span as recorded on a result’s info (for provenance).

Return type:

dict[str, float | None]

property label: str

"7.9-8.75" or "30-end".

Type:

Compact, filename-safe form

classmethod of(*, start=None, end=None)[source]

Build from user input; None when neither bound is given.

Raises:

ValueError – On a bad timestamp, or end not after start.

Return type:

TimeRange | None

yb.download.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.convert_audio(src, audio_format, *, output=None, bitrate=None, overwrite=True, extra_ffmpeg_args=())[source]

Convert src to audio_format, returning the resulting path.

Parameters:
  • src (str | Path) – The audio file to convert.

  • audio_format (str) – Target format as an extension ("mp3", ".wav", …).

  • output (str | Path | None) – Destination path. Defaults to src with the new extension.

  • bitrate (str | None) – Target bitrate for lossy formats (e.g. "320k"). Defaults to DEFAULT_LOSSY_BITRATE; ignored for LOSSLESS_FORMATS.

  • overwrite (bool) – Overwrite output if it already exists.

  • extra_ffmpeg_args (Iterable[str]) – Raw ffmpeg arguments, appended last so they win.

Return type:

Path

Returns:

The converted file’s path — or src unchanged when it is already in the target format (no pointless re-encode, no generation loss).

Raises:
yb.download.default_download_dir()[source]

Resolve the default download directory ($YB_DOWNLOAD_DIR or ~/Downloads).

Return type:

Path

yb.download.download_youtube_audio(url, *, download_dir=None, audio_format=None, bitrate=None, keep_original=False, on_error='raise', fmt='bestaudio/best', filename_template='%(title)s (%(id)s).%(ext)s', write_info_json=False, write_thumbnail=False, write_description=False, write_subtitles=False, write_auto_subtitles=False, subtitle_langs=('en',), quiet=True, extra_opts=None, start=None, end=None, precise_cuts=False, cookies_file=None)[source]

Download only a video’s audio (no video stream).

Simplest use: download_youtube_audio(url) → the best audio stream, kept in whatever format the source offers (YouTube’s is usually Opus in a .webm container), named Title (video_id).webm in ~/Downloads.

Pass audio_format to get a specific format instead:

>>> download_youtube_audio(url, audio_format="mp3")
Parameters:
  • url (str) – The video URL (or id).

  • download_dir (str | Path | None) – Destination directory. Defaults to default_download_dir().

  • audio_format (str | None) – Target format as an extension ("mp3", ".wav", …). The default None means no conversion — keep the downloaded bytes exactly as they came, which needs no ffmpeg and avoids re-encoding a lossy stream into another lossy format.

  • bitrate (str | None) – Bitrate for lossy targets (e.g. "320k"). Ignored when audio_format is lossless or None.

  • keep_original (bool) – When converting, also keep the originally downloaded file (by default it is removed once converted).

  • on_error (Literal['raise', 'warn']) – What to do when conversion fails (ffmpeg missing or erroring). "raise" (default) propagates AudioConversionError; "warn" emits a warning and returns the unconverted download. Either way the downloaded audio is left on disk — a failed conversion never costs you the download.

  • fmt (str) – yt-dlp format selector (default best audio-only stream).

  • filename_template (str) – yt-dlp output template (default "%(title)s (%(id)s).%(ext)s").

  • write_info_json (bool) – Also save the full metadata as *.info.json.

  • write_thumbnail (bool) – Also save the thumbnail image.

  • write_description (bool) – Also save the description as *.description.

  • write_subtitles (bool) – Also save uploaded subtitles for subtitle_langs.

  • write_auto_subtitles (bool) – Also save auto-generated subtitles.

  • subtitle_langs (tuple[str, ...]) – Subtitle languages to fetch when subtitles are enabled.

  • quiet (bool) – Suppress yt-dlp console output.

  • extra_opts (dict | None) – Any additional raw yt-dlp options (merged last, so they win).

  • start (int | float | str | None) –

    Download only a span, as in download_youtube_video():

    >>> download_youtube_audio(url, start="0:07.9", end="0:08.75")
    

  • end (int | float | str | None) –

    Download only a span, as in download_youtube_video():

    >>> download_youtube_audio(url, start="0:07.9", end="0:08.75")
    

  • precise_cuts (bool) –

    Download only a span, as in download_youtube_video():

    >>> download_youtube_audio(url, start="0:07.9", end="0:08.75")
    

Return type:

DownloadResult

Returns:

A DownloadResult whose path is the audio file — converted when audio_format was given and conversion succeeded.

Raises:
yb.download.download_youtube_playlist(url, *, download_dir=None, playlist_items=None, skip_first=False, title_reject=None, download_archive=None, fmt='bestvideo+bestaudio/best', merge_to='mp4', filename_template='%(title)s (%(id)s).%(ext)s', write_info_json=True, write_thumbnail=False, write_description=False, write_subtitles=False, write_auto_subtitles=False, subtitle_langs=('en',), cookies_from_browser=None, extractor_args=None, quiet=True, extra_opts=None, cookies_file=None)[source]

Download all (or a selected subset of) a YouTube playlist’s videos.

Simplest use: download_youtube_playlist(url) → every video downloaded best quality merged to mp4 into download_dir (default ~/Downloads), each with its *.info.json sidecar (write_info_json defaults to True here, since a playlist download is usually an archival operation).

Selecting a subset (yt-dlp --playlist-items is 1-based):

# skip the first (“PV”/intro) entry, keep the rest download_youtube_playlist(url, skip_first=True) # -> playlist_items=”2:” download_youtube_playlist(url, playlist_items=”2:”) # same, explicit download_youtube_playlist(url, playlist_items=”2”) # only the 2nd video download_youtube_playlist(url, title_reject=”PV”) # skip entries whose title contains “PV”

Parameters:
  • url (str) – The playlist URL.

  • download_dir (str | Path | None) – Destination directory (default default_download_dir()).

  • playlist_items (str | None) – yt-dlp item selector (1-based; "2:", "2", "1:5,8").

  • skip_first (bool) – Convenience for playlist_items="2:" (ignored if playlist_items is given).

  • title_reject (str | None) – Skip entries whose (case-insensitive) title contains this substring — more robust than a positional skip if ordering changes.

  • download_archive (str | Path | None) – Path to a yt-dlp archive file recording downloaded ids, making re-runs idempotent/resumable.

  • fmt (str) – yt-dlp format selector (default best video + best audio).

  • merge_to (str | None) – Container to merge into (default "mp4"; needs ffmpeg).

  • filename_template (str) – yt-dlp output template (default "%(title)s (%(id)s).%(ext)s").

  • write_info_json (bool) – Save each video’s *.info.json (default True).

  • write_thumbnail (bool)

  • write_description (bool)

  • write_subtitles (bool)

  • write_auto_subtitles (bool)

Return type:

list[DownloadResult]

:param : :type subtitle_langs: tuple[str, ...] :param subtitle_langs: As in download_youtube_video(). :type cookies_from_browser: str | tuple | None :param cookies_from_browser: Browser to read cookies from for bot-detection /

age / region issues, e.g. "safari" or ("chrome", "Profile 1").

Parameters:
  • extractor_args (dict | None) – yt-dlp extractor_args (e.g. {"youtube": {"player_client": ["web_safari"]}}).

  • quiet (bool) – Suppress yt-dlp console output.

  • extra_opts (dict | None) – Any additional raw yt-dlp options (merged last, so they win).

  • cookies_file (Union[str, Path, Literal[False], None]) – As in download_youtube_video(); an explicit cookies_from_browser takes precedence over the default file.

Return type:

list[DownloadResult]

Returns:

A list of DownloadResult, one per successfully-downloaded entry, in playlist order. Entries skipped by selection/filter or that failed (under ignoreerrors) are omitted.

yb.download.download_youtube_video(url, *, download_dir=None, fmt='bestvideo+bestaudio/best', merge_to='mp4', filename_template='%(title)s (%(id)s).%(ext)s', write_info_json=False, write_thumbnail=False, write_description=False, write_subtitles=False, write_auto_subtitles=False, subtitle_langs=('en',), quiet=True, extra_opts=None, start=None, end=None, precise_cuts=False, cookies_file=None)[source]

Download a YouTube video to download_dir (default ~/Downloads).

Simplest use: download_youtube_video(url) → best quality merged to mp4, named Title (video_id).mp4 in ~/Downloads.

Parameters:
  • url (str) – The video URL (or id).

  • download_dir (str | Path | None) – Destination directory. Defaults to default_download_dir().

  • fmt (str) – yt-dlp format selector (default best video + best audio).

  • merge_to (str | None) – Container to merge video+audio into (default "mp4"; requires ffmpeg). Set None to keep yt-dlp’s default.

  • filename_template (str) – yt-dlp output template (default "%(title)s (%(id)s).%(ext)s").

  • write_info_json (bool) – Also save the full metadata as *.info.json.

  • write_thumbnail (bool) – Also save the thumbnail image.

  • write_description (bool) – Also save the description as *.description.

  • write_subtitles (bool) – Also save uploaded subtitles for subtitle_langs.

  • write_auto_subtitles (bool) – Also save auto-generated subtitles.

  • subtitle_langs (tuple[str, ...]) – Subtitle languages to fetch when subtitles are enabled.

  • quiet (bool) – Suppress yt-dlp console output.

  • extra_opts (dict | None) – Any additional raw yt-dlp options (merged last, so they win).

  • start (int | float | str | None) – Download only this span: seconds (7.9) or a timestamp ("0:07.9", "1:02:03"). Either may be given alone (end only = from the beginning; start only = to the end). The span is recorded in info["download_range"] as {"start", "end"} seconds (end is None for “to the end”), and, with the default filename_template, in the filename (Title (id) [7.9-8.75].mp4) so a clip never collides with the full video. Needs ffmpeg (see yb.download.ranges).

  • end (int | float | str | None) – Download only this span: seconds (7.9) or a timestamp ("0:07.9", "1:02:03"). Either may be given alone (end only = from the beginning; start only = to the end). The span is recorded in info["download_range"] as {"start", "end"} seconds (end is None for “to the end”), and, with the default filename_template, in the filename (Title (id) [7.9-8.75].mp4) so a clip never collides with the full video. Needs ffmpeg (see yb.download.ranges).

  • precise_cuts (bool) – With start/end, re-encode at the cuts for frame-accurate bounds (slower) instead of cutting at keyframes.

  • cookies_file (Union[str, Path, Literal[False], None]) – Netscape-format cookies file to authenticate with (for headless servers where cookies_from_browser cannot work). Default None reads $YB_COOKIES_FILE, else ~/.config/yb/youtube-cookies.txt if it exists, else sends no cookies. An explicit cookies_from_browser or extra_opts cookie option suppresses that default; False opts out of it. The file is checked first (ValueError if explicit, else a warning, naming only line numbers). It cannot be combined with a browser cookie source. yt-dlp rewrites the file with refreshed cookies on exit, so it must be writable and not shared by parallel workers.

Return type:

DownloadResult

Returns:

A DownloadResult with the media path, trimmed info, and any sidecars written.

Raises:

ValueError – If start/end is not a timestamp, or end is not after start. Raised before anything is fetched or written.

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

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

Parameters:
  • which (Callable[[str], str | None]) – PATH lookup (injectable for tests).

  • search_dirs (Iterable[Path] | None) – Extra directories to look in when it isn’t on PATH (default deno_search_dirs()).

Return type:

JsRuntime | None

Returns:

The runtime found, or None.

yb.download.parse_timestamp(value)[source]

Seconds from a number or a "[[h:]m:]s[.fraction]" string.

Raises:

ValueError – If value is negative, not finite, or not a timestamp.

Return type:

float

yb.download.youtube_playlist_info(url, *, playlist_items=None, flat=True, extra_opts=None, cookies_file=None)[source]

Fetch a playlist’s per-video metadata without downloading.

Returns a dict with playlist-level fields (playlist_id, playlist_title, webpage_url, uploader, count) and an entries list. With flat=True (default) extraction is fast/shallow (each entry has at least id, title, url); with flat=False each entry is fully resolved and trimmed to _INFO_FIELDS (slower, but includes duration/fps/etc.).

Parameters:
  • url (str) – The playlist URL.

  • playlist_items (str | None) – yt-dlp --playlist-items selector, 1-based, e.g. "2:" (all but the first), "2" (only the 2nd), "1:5,8".

  • flat (bool) – Shallow vs full per-entry extraction.

  • extra_opts (dict | None) – Additional raw yt-dlp options (merged last).

  • cookies_file (Union[str, Path, Literal[False], None]) – See download_youtube_video().

Return type:

dict[str, Any]

yb.download.youtube_video_info(url, *, extra_opts=None, cookies_file=None)[source]

Fetch a video’s metadata without downloading it.

Returns the trimmed info dict (see _INFO_FIELDS). Useful to preview the title/duration/chapters before deciding to download.

cookies_file: see download_youtube_video().

Return type:

dict[str, Any]

Modules

ranges

Download just a time range of a video: parse start/end, build yt-dlp's options.

requirements

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

youtube

Download YouTube videos (and their metadata) via yt-dlp.