Skip to main content

Streamlining media publishing: prepare, upload, and edit videos (YouTube) and podcasts

Project description

yb

Streamline media publishing: prepare a piece of media once, publish it anywhere — to YouTube (upload + edit) or as a podcast (show notes, chapters, RSS) — plus a download module for pulling videos back down.

import yb

# Download a video (-> ~/Downloads, named "Title (id).mp4")
r = yb.download_youtube_video("https://youtu.be/PRa9ciOe-us")

# One call: transcribe, write title/description/keywords, detect chapters,
# render a thumbnail, and upload to YouTube (unlisted) with captions.
yb.prepare_and_publish(r.path, language="English", language_code="en",
                       audio_language_code="en", privacy_status="unlisted")

Why

yb separates what you publish from where you publish it. A media file is turned into a platform-neutral PublicationContent — title, description, keywords, chapters, captions, thumbnail — and thin adapters map that onto each destination's API. The media work itself (transcription, chapter detection, thumbnails, dubbing/translation) lives in the mixing package; yb is the publication layer on top.

Install

pip install yb                 # core (needs `mixing`)
pip install 'yb[youtube]'      # YouTube upload/edit (Google API client)
pip install 'yb[download]'     # yt-dlp downloader
pip install 'yb[podcast]'      # podcast chapters (ID3/PSC) + RSS
pip install 'yb[llm]'          # LLM metadata/chapter copy (via `aix`)
pip install 'yb[all]'          # everything

Everything heavy is an optional extra, and import yb never fails for a missing one — the error only surfaces when you actually call that feature. You also need ffmpeg on PATH for media work, and an ELEVENLABS_API_KEY for transcription.

Common tasks

Download

from yb.download import download_youtube_video, youtube_video_info

youtube_video_info(url)                       # metadata only, no download
download_youtube_video(url)                   # best quality -> ~/Downloads/"Title (id).mp4"
download_youtube_video(url, download_dir="~/clips", write_info_json=True,
                       write_subtitles=True, subtitle_langs=("en", "fr"))

The destination defaults to $YB_DOWNLOAD_DIR (else ~/Downloads). Every knob — format, filename template, which sidecar metadata to also save — is overridable, and any raw yt-dlp option can be passed via extra_opts=.

Publish to YouTube

from yb.youtube import prepare_and_publish, VideoMetadata, publish_video, CaptionTrack

# High level: prepare assets from the media file, then upload.
result = prepare_and_publish("promo.fr.mp4", language="French",
                             language_code="fr", audio_language_code="fr",
                             privacy_status="unlisted")
print(result["url"])

# Lower level: you supply the metadata and captions.
meta = VideoMetadata(title="...", description="...", tags=[...],
                     default_language="en", default_audio_language="en")
publish_video("promo.en.mp4", meta, privacy_status="unlisted",
              captions=[CaptionTrack("promo.en.srt", "en", "English")],
              thumbnail="thumb.jpg")

Chapters are on by default: when the media is long enough to host them (YouTube requires ≥3 markers, each ≥10 s, first at 0:00), they are detected from the transcript and embedded in the description so YouTube renders interactive chapters. Short clips simply get none.

Edit an already-published video

from yb.youtube import update_video_fields, upsert_caption, set_chapters, set_thumbnail
from mixing.chapters import Chapter

update_video_fields("VIDEO_ID", title="New title", tags=["a", "b"])
upsert_caption("VIDEO_ID", "subs.fr.srt", language="fr", name="Français")  # replaces same-lang track
set_chapters("VIDEO_ID", [Chapter(0, "Intro"), Chapter(45, "Demo")])
set_thumbnail("VIDEO_ID", "thumb.jpg")

Read live stats & metadata

from yb.youtube import video_metadata, FIELD_GROUPS

video_metadata("VIDEO_ID", group="engagement")            # dict: views, likes, dislikes, comments, ...
print(video_metadata("VIDEO_ID", group="engagement", as_table=True))  # readable ASCII table
video_metadata("VIDEO_ID", fields=["title", "views", "likes"])        # pick & order exact fields
print(video_metadata(["ID1", "ID2"], group="engagement", as_table=True))  # compare videos, one row each

One request returns a flat, typed view of a video's live numbers plus content and status details. With no group/fields you get every field; fields overrides group. Named groups (FIELD_GROUPS): engagement, overview, content, status, identity. dislikes is returned only to the video's owner (else None); watch-time/retention/shares live in the YouTube Analytics API, not here.

Publish a podcast episode

from yb.podcast import prepare_podcast_episode, PodcastChannel, EpisodeFeedItem, build_feed

ep = prepare_podcast_episode("episode.mp3", "out/",
                             cover_image="cover.jpg", make_cover_video=True)
# -> out/episode.mp3 (with ID3 chapters), .shownotes.txt, .psc.xml,
#    .chapters.json, and .cover.mp4

# Assemble an RSS feed (delivery to Spotify/Apple is via your podcast host).

A podcast episode and a YouTube video are built from the same PublicationContent: an episode "could just be audio with a cover image" (or a Ken Burns video), which is exactly what prepare_podcast_episode can render.

Setup (YouTube OAuth)

YouTube upload needs a Google OAuth Desktop client (one-time). gcloud is not required — the console path works. See the yb-setup skill for the full walkthrough (enable the API, create the OAuth client, run consent, test). Point yb at the client JSON via $YOUTUBE_CLIENT_SECRETS_FILE.

Note: until your Google Cloud project passes YouTube's one-time API compliance audit, uploads may be forced to private even when you request unlisted/public.

Layout

Module Role Extra
yb.content platform-neutral content prep (metadata, chapters, thumbnail) core
yb.youtube upload, edit + read stats via YouTube Data API v3 youtube
yb.podcast show notes, ID3/PSC chapters, cover video, RSS podcast
yb.download yt-dlp downloader download

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yb-0.1.4.tar.gz (38.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yb-0.1.4-py3-none-any.whl (43.0 kB view details)

Uploaded Python 3

File details

Details for the file yb-0.1.4.tar.gz.

File metadata

  • Download URL: yb-0.1.4.tar.gz
  • Upload date:
  • Size: 38.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for yb-0.1.4.tar.gz
Algorithm Hash digest
SHA256 51a79920bbd45f4468f601440cf7fd48ce6293620bdd17c793c397565de62621
MD5 f8c1bd07d07ac572de10b9e55db78c0a
BLAKE2b-256 8efb76acc633d84e5541e40d8bac4221443028533dec4776353cff4a87076b1e

See more details on using hashes here.

File details

Details for the file yb-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: yb-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 43.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for yb-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 354addc0839c4d6a607821e127ed4fbd7f814461f77aebbd354d74516856eefc
MD5 22aff58d9e231c8f3eaa7a45523dfd2d
BLAKE2b-256 47b11e4af2903422a7a37894dea30f4efdf7120cd87ed84116b97f57aaaaa075

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page