yb

yb — streamline media publishing: prepare once, publish to YouTube or podcast.

Layered by separation of concerns:

  • core (always available): yb.content — build a platform-neutral PublicationContent (title, description, keywords,

    chapters, captions, thumbnail) from a media file, delegating transcription, chapter detection, and thumbnails to the mixing package.

  • adapters (optional extras): - yb.youtube (pip install 'yb[youtube]') — upload and edit videos. - yb.music (pip install 'yb[music]') — turn songs into music videos

    (rendering via muvid) and publish them, including a whole folder as an album. Uploading also needs yb[youtube].

    • yb.podcast (pip install 'yb[podcast]') — show notes, chapter markers, cover-over-audio video (via muvid), RSS episode item.

    • yb.download (pip install 'yb[download]') — fetch videos/metadata.

The audio→video rendering itself lives in muvid.visualize (yb is the publication layer); yb.music is the thin publish-facing facade over it.

The most common callables are re-exported here for convenience; the ones that live in optional extras are imported lazily, so import yb never fails for a missing extra — the error surfaces only when you actually use that feature.

Examples

>>> import yb
>>> r = yb.download_youtube_video("https://youtu.be/PRa9ciOe-us")  # needs yb[download]
>>> content = yb.prepare_content(r.path, language="English", language_code="en")
>>> yb.prepare_and_publish(r.path, privacy_status="unlisted")        # needs yb[youtube]
class yb.ContentMetadata(title, description, keywords=<factory>)[source]

Bases: object

Platform-neutral copy: a title, a description, and keywords.

class yb.PublicationContent(media, title='', description='', keywords=<factory>, chapters=<factory>, language=None, audio_language=None, srt_path=None, thumbnail=None, duration=None)[source]

Bases: object

Everything needed to publish a piece of media, destination-agnostic.

media

Path to the audio/video file.

title

Headline/title.

description

Long-form description / show notes body.

keywords

Topical keywords/tags.

chapters

Ordered chapter markers (mixing.chapters.Chapter).

language

BCP-47 code of the metadata text (e.g. "en").

audio_language

BCP-47 code of the spoken audio (e.g. "fr").

srt_path

Path to the SRT subtitle/caption file, if any.

thumbnail

Path to a thumbnail/cover image, if any.

duration

Media duration in seconds, if known.

description_with_chapters()[source]

Description with a chapters block appended (if any chapters).

Return type:

str

class yb.YbConfig(privacy_status='unlisted', playlist=None, create_playlist_if_missing=True, playlist_privacy_status='private')[source]

Bases: object

Resolved publishing defaults.

privacy_status

Privacy a new upload gets (unlisted | private | public) when the call doesn’t override it.

playlist

Title of a playlist every upload is added to (None = none).

create_playlist_if_missing

Create playlist if no playlist of that title exists yet, rather than erroring.

playlist_privacy_status

Privacy for an auto-created playlist.

classmethod from_mapping(mapping)[source]

Build a config from a mapping, ignoring unknown keys.

Return type:

YbConfig

yb.add_video_to_playlist(video_id, title, *, create=True, privacy_status='private', skip_if_present=True, service=None, **cred_kwargs)[source]

Find-or-create the playlist named title and append video_id.

Idempotent: with skip_if_present (default), a video already in the playlist is left alone instead of duplicated.

Return type:

dict

Returns:

{"playlist_id", "playlist_title", "added", "created"} where added is False if the video was already present and created is True if the playlist had to be made.

Raises:

KeyError – the playlist is absent and create=False.

yb.default_config_file()[source]

Config file location ($XDG_CONFIG_HOME or ~/.config).

Return type:

Path

yb.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_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.format_chapter_lines(chapters)[source]

Render chapters as M:SS Title lines (the shared text convention).

Uses H:MM:SS when any chapter is at or beyond one hour. This is the text format both YouTube descriptions and podcast show notes accept.

Return type:

str

yb.generate_metadata(transcript, *, language='English', brand=None, extra_context=None, model=None)[source]

Generate platform-neutral title/description/keywords from a transcript.

LLM-backed via aix. Pass a ready ContentMetadata to prepare_content() instead if you want to skip generation.

Raises:

ImportError – aix is not importable.

Return type:

ContentMetadata

yb.load_config(config_file=None, **overrides)[source]

Load publishing defaults from config_file (or the default location).

A missing file yields the built-in defaults. overrides (typically the explicit keyword arguments a caller passed) take precedence when not None, so call-site arguments always win over the file.

Return type:

YbConfig

yb.prepare_and_publish(media, *, language='English', language_code=None, audio_language_code=None, brand=None, extra_context=None, with_chapters=True, with_thumbnail=True, privacy_status=None, playlist=<object object>, category_id='28', config=None, client_secrets_file=None, token_file=None, progress=True, **cred_kwargs)[source]

One call: prepare publication content from media and upload it.

Transcribes (persisting the SRT next to the media) if needed, writes LLM metadata, detects chapters, renders a thumbnail, then uploads with captions + thumbnail + chapters and adds the video to the configured playlist. privacy_status and playlist default to your yb config (see publish_content()).

cred_kwargs reach get_credentials() (e.g. open_browser=False, port=8080 for headless consent).

Return type:

dict

yb.prepare_content(media, *, language='English', language_code=None, audio_language_code=None, brand=None, extra_context=None, transcript=None, with_chapters=True, with_thumbnail=False, thumbnail_text=None, metadata=None, model=None, transcribe_kwargs=None, chapters_kwargs=None)[source]

Build a PublicationContent for media (destination-agnostic).

Ensures a persisted SRT next to the media (transcribing once via mixing if needed), writes LLM metadata, detects chapters (default on, auto-skipped for clips too short to host them), and optionally renders a thumbnail. Any precomputed pieces (transcript, metadata) are reused instead of recomputed.

Parameters:
  • media (str | Path) – Audio or video file.

  • language (str) – Human-readable language to write metadata in.

  • audio_language_code (str | None) – BCP-47 codes for the metadata text and the spoken audio.

  • brand (str | None) – Product/brand name to keep verbatim in the copy.

  • extra_context (str | None) – Extra guidance for the copywriter (audience, CTA…).

  • transcript (str | None) – SRT text to use as-is (skips transcription).

  • with_chapters (bool) – Detect chapters (default True).

  • with_thumbnail (bool) – Render a thumbnail image (default False).

  • thumbnail_text (str | None) – Overlay text for the thumbnail (defaults to the title).

  • metadata (ContentMetadata | None) – Precomputed ContentMetadata to reuse.

  • model (str | None) – LLM model override.

  • chapters_kwargs (dict | None) – Forwarded to the mixing calls.

Return type:

PublicationContent

Returns:

A populated PublicationContent.

yb.prepare_podcast_episode(media, output_dir, *, content=None, audio=None, cover_image=None, make_cover_video=False, ken_burns=False, embed_chapters=True, language='English', brand=None, extra_context=None, audio_bitrate='192k')[source]

Build a podcast episode bundle from media into output_dir.

Parameters:
  • media (str | Path) – Source audio or video.

  • output_dir (str | Path) – Directory to write the episode assets into.

  • content (PublicationContent | None) – Precomputed PublicationContent; built via yb.content.prepare_content() when omitted.

  • audio (str | Path | None) – Explicit episode audio. When omitted, media is used if it is audio, else its audio track is extracted to MP3.

  • cover_image (str | Path | None) – Cover art (required for make_cover_video).

  • make_cover_video (bool) – Also render a cover-over-audio mp4 (e.g. for YouTube).

  • ken_burns (bool) – Apply a Ken Burns pan/zoom to the cover video.

  • embed_chapters (bool) – Embed ID3 chapter frames into the episode MP3.

  • extra_context (str | None) – Forwarded to prepare_content.

  • audio_bitrate (str) – Bitrate for extracted MP3 audio.

Return type:

PodcastEpisode

Returns:

A PodcastEpisode with the asset paths.

yb.publish_content(content, *, privacy_status=None, playlist=<object object>, category_id='28', with_chapters=True, attach_caption=True, set_thumb=True, config=None, client_secrets_file=None, token_file=None, progress=True, service=None, resume=None, **cred_kwargs)[source]

Upload a prepared PublicationContent to YouTube.

Maps the content to a YouTube snippet (chapters embedded in the description when present), uploads, attaches the SRT caption track (language = content.audio_language or content.language) and the thumbnail when available, and adds the video to the configured playlist.

privacy_status and playlist default to your yb config (see yb.config): unset means “use the config value”, so privacy falls back to unlisted and the video joins your configured playlist. Pass playlist=None to skip the playlist for one call, or playlist="Name" to override the target.

cred_kwargs reach get_credentials() (e.g. open_browser=False, port=8080 for headless consent).

Return type:

dict

Returns:

{"video_id", "url", "studio_url", "privacy_status", "captions", "thumbnail", "playlist"}. privacy_status reflects what YouTube actually set (an unaudited project may force "private"); playlist is the add_video_to_playlist() result or None.

Raises:

PartialPublish – the upload succeeded and a later step failed; err.result holds the video id and what was done. Pass resume=err.result to finish without uploading again (yb#21).

yb.set_chapters(video_id, chapters, *, header='Chapters:', service=None, **cred_kwargs)[source]

Insert/replace a chapters block in the video’s description.

Strips any prior block under header and appends the new one. YouTube renders interactive chapters when the first timestamp is 0:00.

Return type:

dict

yb.update_video_fields(video_id, *, title=None, description=None, tags=None, category_id=None, default_language=None, default_audio_language=None, service=None, **cred_kwargs)[source]

Patch selected snippet fields, preserving the rest.

Fetches the current snippet, overlays the provided fields, and updates. categoryId must be present (kept from the existing snippet if not given).

Return type:

dict

yb.upsert_caption(video_id, track, *, language=None, name='', is_draft=False, replace=True, service=None, **cred_kwargs)[source]

Insert a caption track, or update the existing same-language one.

Parameters:
  • video_id (str) – Target video.

  • track (CaptionTrack | str | Path) – A CaptionTrack, or a path (then language required).

  • replace (bool) – When an uploaded track in the same language exists, update it (True, default) rather than inserting a duplicate.

Return type:

dict

Returns:

The inserted/updated caption resource.

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

audio_convert

Convert audio files between formats with ffmpeg.

config

User configuration for yb publishing defaults.

content

Target-agnostic publication content: prepare it once, publish anywhere.

download

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

podcast

Podcast publishing: show notes, chapters, cover video, and RSS.

youtube

YouTube publishing via the YouTube Data API v3.