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.podcast (pip install 'yb[podcast]') — show notes, chapter

    markers, cover-over-audio video, RSS episode item.

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

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: str, description: str, keywords: list[str] = <factory>)[source]

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

class yb.PublicationContent(media: Path, title: str = '', description: str = '', keywords: list[str] = <factory>, chapters: list[Chapter] = <factory>, language: str | None = None, audio_language: str | None = None, srt_path: Path | None = None, thumbnail: Path | None = None, duration: float | None = None)[source]

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

media

Path to the audio/video file.

Type:

pathlib.Path

title

Headline/title.

Type:

str

description

Long-form description / show notes body.

Type:

str

keywords

Topical keywords/tags.

Type:

list[str]

chapters

Ordered chapter markers (mixing.chapters.Chapter).

Type:

list[mixing.chapters.Chapter]

language

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

Type:

str | None

audio_language

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

Type:

str | None

srt_path

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

Type:

pathlib.Path | None

thumbnail

Path to a thumbnail/cover image, if any.

Type:

pathlib.Path | None

duration

Media duration in seconds, if known.

Type:

float | None

description_with_chapters() str[source]

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

yb.download_youtube_video(url: str, *, download_dir: str | Path | None = None, fmt: str = 'bestvideo+bestaudio/best', merge_to: str | None = 'mp4', filename_template: str = '%(title)s (%(id)s).%(ext)s', write_info_json: bool = False, write_thumbnail: bool = False, write_description: bool = False, write_subtitles: bool = False, write_auto_subtitles: bool = False, subtitle_langs: tuple[str, ...] = ('en',), quiet: bool = True, extra_opts: dict | None = None) DownloadResult[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 – The video URL (or id).

  • download_dir – Destination directory. Defaults to default_download_dir().

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

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

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

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

  • write_thumbnail – Also save the thumbnail image.

  • write_description – Also save the description as *.description.

  • write_subtitles – Also save uploaded subtitles for subtitle_langs.

  • write_auto_subtitles – Also save auto-generated subtitles.

  • subtitle_langs – Subtitle languages to fetch when subtitles are enabled.

  • quiet – Suppress yt-dlp console output.

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

Returns:

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

yb.format_chapter_lines(chapters: Sequence[Chapter]) str[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.

yb.generate_metadata(transcript: str, *, language: str = 'English', brand: str | None = None, extra_context: str | None = None, model: str | None = None) ContentMetadata[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:

ImportErroraix is not importable.

yb.prepare_and_publish(media: str | Path, *, language: str = 'English', language_code: str | None = None, audio_language_code: str | None = None, brand: str | None = None, extra_context: str | None = None, with_chapters: bool = True, with_thumbnail: bool = True, privacy_status: str = 'unlisted', category_id: str = '28', client_secrets_file: str | Path | None = None, token_file: str | Path | None = None, progress: bool = True) dict[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.

yb.prepare_content(media: str | Path, *, language: str = 'English', language_code: str | None = None, audio_language_code: str | None = None, brand: str | None = None, extra_context: str | None = None, transcript: str | None = None, with_chapters: bool = True, with_thumbnail: bool = False, thumbnail_text: str | None = None, metadata: ContentMetadata | None = None, model: str | None = None, transcribe_kwargs: dict | None = None, chapters_kwargs: dict | None = None) PublicationContent[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 – Audio or video file.

  • language – Human-readable language to write metadata in.

  • audio_language_code (language_code /) – BCP-47 codes for the metadata text and the spoken audio.

  • brand – Product/brand name to keep verbatim in the copy.

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

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

  • with_chapters – Detect chapters (default True).

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

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

  • metadata – Precomputed ContentMetadata to reuse.

  • model – LLM model override.

  • chapters_kwargs (transcribe_kwargs /) – Forwarded to the mixing calls.

Returns:

A populated PublicationContent.

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

Build a podcast episode bundle from media into output_dir.

Parameters:
  • media – Source audio or video.

  • output_dir – Directory to write the episode assets into.

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

  • audio – Explicit episode audio. When omitted, media is used if it is audio, else its audio track is extracted to MP3.

  • cover_image – Cover art (required for make_cover_video).

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

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

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

  • extra_context (language / brand /) – Forwarded to prepare_content.

  • audio_bitrate – Bitrate for extracted MP3 audio.

Returns:

A PodcastEpisode with the asset paths.

yb.publish_content(content: PublicationContent, *, privacy_status: str = 'unlisted', category_id: str = '28', with_chapters: bool = True, attach_caption: bool = True, set_thumb: bool = True, client_secrets_file: str | Path | None = None, token_file: str | Path | None = None, progress: bool = True, service=None) dict[source]

Upload a prepared PublicationContent to YouTube.

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

Returns:

{"video_id", "url", "studio_url", "privacy_status", "captions", "thumbnail"}. privacy_status reflects what YouTube actually set (an unaudited project may force "private").

yb.set_chapters(video_id: str, chapters: Sequence[Chapter], *, header: str = 'Chapters:', service=None, **cred_kwargs) dict[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.

yb.update_video_fields(video_id: str, *, title: str | None = None, description: str | None = None, tags: Sequence[str] | None = None, category_id: str | None = None, default_language: str | None = None, default_audio_language: str | None = None, service=None, **cred_kwargs) dict[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).

yb.upsert_caption(video_id: str, track: CaptionTrack | str | Path, *, language: str | None = None, name: str = '', is_draft: bool = False, replace: bool = True, service=None, **cred_kwargs) dict[source]

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

Parameters:
  • video_id – Target video.

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

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

Returns:

The inserted/updated caption resource.

yb.youtube_video_info(url: str, *, extra_opts: dict | None = None) dict[str, Any][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.