Manage Yoto CYO playlists as folders on disk
Project description
yoto-library
Manage Yoto Player Create-Your-Own (CYO) playlists as folders on disk, with two-way sync to the Yoto API.
Each playlist is a folder. Audio files live in MKA containers that carry metadata and icon attachments. Cover art and track icons are auto-generated via AI when missing. Sync pushes local state to Yoto; pull downloads remote state to a local folder.
Prerequisites
Required:
- Python 3.10+
- FFmpeg — audio processing, MKA muxing, silence detection
- mkvtoolnix — MKA metadata and attachment read/write
Optional:
- yt-dlp — YouTube audio downloads (for
.weblocsupport) - bsdiff — byte-perfect export patches (install via
brew install bsdiff;bspatchships with macOS)
AI services (for icon and cover art generation):
- Claude CLI — descriptions, icon matching, cover text quality checks (uses your Claude subscription)
node(v18+) — required for web scraping lyrics sources. Install viabrew install nodeor from nodejs.org. Also requiresjsdom:npm install jsdom(run once in the yoto-library directory).- RetroDiffusion — 16x16 pixel art icon generation (
RETRODIFFUSION_API_KEY) - Together AI — album art recomposition via FLUX Kontext (
TOGETHER_API_KEY) - Google Gemini — text rendering for cover art repair (
GEMINI_API_KEY) - OpenAI — text-to-image cover generation when no album art exists (
OPENAI_API_KEY)
On macOS with Homebrew:
brew install ffmpeg mkvtoolnix yt-dlp
Installation
pip install yoto-library
This installs the yoto command.
To install from source:
git clone https://github.com/steverice/yoto-library.git
cd yoto-library
pip install -e .
Quick start
Authenticate:
yoto auth
Opens a device code flow — visit the URL shown, enter the code, and your token is saved to macOS Keychain.
Pull an existing playlist:
yoto pull abc12
Downloads the playlist with card ID abc12 into a local folder.
Create a new playlist:
yoto init "Bedtime Songs"
Scaffolds an empty playlist folder. Add .mka audio files, then sync.
Import existing audio files:
yoto import ~/Music/album -o "Road Trip Mix"
Converts a folder of audio files (MP3, FLAC, WAV, etc.) into MKA-wrapped tracks in a new playlist folder.
Sync to Yoto:
yoto sync "Bedtime Songs"
Pushes local state to the Yoto API — uploads audio, generates icons and cover art if missing, and creates or updates the card.
Playlist folder structure
Bedtime Songs/
playlist.jsonl # track order (JSON strings, one per line)
description.txt # playlist description, ≤500 chars (auto-generated if missing)
cover.png # 638x1011 portrait cover art (auto-generated if missing)
.yoto-card-id # Yoto card ID (written on first sync or pull)
lullaby.mka # audio + metadata + icon attachment
twinkle-twinkle.mka
rock-a-bye.mka
playlist.jsonl — bare JSON strings defining track order. Auto-generated alphabetically if absent. Editable with yoto reorder or any text editor.
"lullaby.mka"
"twinkle-twinkle.mka"
"rock-a-bye.mka"
MKA containers — Matroska Audio files that losslessly wrap any audio codec. Each MKA carries the original audio stream, Matroska metadata tags (artist, language, etc.), and a 16x16 icon attachment (PNG or animated GIF).
Commands
yoto auth
Authenticate with Yoto via OAuth device code flow. Tokens are stored in macOS Keychain.
yoto sync [path]
Push local playlist state to Yoto. Uploads new/changed audio, icons, and cover art. Creates or updates the remote card.
yoto sync # sync playlist in current directory
yoto sync "Bedtime Songs" # sync a specific folder
yoto sync --dry-run # preview changes without executing
yoto sync --no-trim # skip silence trimming on YouTube downloads
yoto sync --print # print cover art after sync
yoto sync --no-print # skip print prompt
yoto pull [path | card-id]
Pull remote playlist state to a local folder. Downloads audio, wraps in MKA, sets icons.
yoto pull abc12 # pull by card ID into a new folder
yoto pull "Bedtime Songs" # update an existing linked folder from remote
yoto pull --all # pull all playlists into subdirectories of cwd
yoto pull --dry-run # preview changes
yoto status [path]
Show the diff between local and remote state for a playlist.
yoto list
Show all MYO cards on the authenticated Yoto account (card ID, title, track count).
yoto init [path]
Scaffold a new empty playlist folder with an empty playlist.jsonl. Defaults to current directory.
yoto import <source>
Bulk import: convert a folder of audio files into a playlist with MKA-wrapped tracks.
yoto import ~/Music/album # in-place
yoto import ~/Music/album -o "Road Trip Mix" # into a new folder
yoto download [path]
Resolve .webloc URLs in a playlist folder — downloads audio (via yt-dlp), trims silence, and wraps in MKA. Does not sync to Yoto.
yoto download # process .webloc files in current directory
yoto download --no-trim # skip silence trimming
yoto export <playlist>
Export MKA tracks back to their original audio format. If a source.patch attachment exists, the export is byte-perfect via bspatch.
yoto export "Bedtime Songs" # export to Bedtime Songs-exported/
yoto export "Bedtime Songs" -o ~/Music/out # export to a specific folder
yoto lyrics <playlist>
Fetch and store lyrics for tracks in a playlist. Checks source tags first, then falls back to the LRCLIB API.
yoto lyrics "Bedtime Songs" # fetch missing lyrics
yoto lyrics "Bedtime Songs" --force # re-fetch all lyrics
yoto lyrics "Bedtime Songs" --show # display stored lyrics in a pager
yoto cover [path]
Generate cover art for a playlist folder without syncing.
yoto cover # generate cover in current directory
yoto cover --force # regenerate even if cover.png exists
yoto cover --backup # rename existing cover.png before generating
yoto cover --ignore-album-art # skip album art reuse, generate from prompt
yoto reorder [playlist]
Open playlist.jsonl in $EDITOR to reorder tracks. Validates JSON on save. Defaults to playlist.jsonl in the current directory.
yoto select-icon <track>
Interactive icon selection for a single track (or multiple tracks in sequence). Generates three pixel art icon options, finds the best match from Yoto's icon catalog, scores all candidates with an LLM, and displays them in bordered panels for selection. Pick one or press r to regenerate.
yoto reset-icon <tracks...>
Remove icon attachments from one or more MKA files. The next yoto sync will regenerate icons for those tracks.
yoto print [path]
Print cover art to a photo printer via macOS CUPS. Optionally applies an ICC color profile for accurate color reproduction.
yoto print # print cover in current directory
yoto print "Bedtime Songs" # print a specific playlist's cover
yoto print --yes # skip confirmation prompt
yoto print --profile /path/to/profile.icc # use ICC color profile
If no cover.png exists, offers to generate one first. If a profile is specified but not found, warns and offers to continue without color management.
yoto lyrics [path]
Fetch and embed lyrics for tracks in a playlist folder. Tries embedded tags, then user-configured web scraping sources, then the LRCLIB public API.
yoto lyrics # fetch lyrics for current directory
yoto lyrics "Bedtime Songs" # fetch lyrics for a specific folder
yoto lyrics --add-source <url> # analyze a website and add it as a lyrics source
yoto billing
Show provider balances, subscription usage, and lifetime cost tracking.
yoto billing # show all billing info
yoto billing --reset # reset all lifetime cost data
yoto billing --reset openai # reset costs for a specific provider group
yoto completions [shell]
Print the shell completion setup command for zsh, bash, or fish. Auto-detects your shell if not specified.
Configuration
Authentication is handled via macOS Keychain — no config file needed. Run yoto auth to log in.
AI services require API keys set as environment variables (e.g., in .env at the project root):
RETRODIFFUSION_API_KEY=... # retrodiffusion.ai — icon generation
TOGETHER_API_KEY=... # together.ai — album art recomposition (FLUX Kontext)
GEMINI_API_KEY=... # aistudio.google.com — text layer rendering
OPENAI_API_KEY=... # platform.openai.com — text-to-image cover generation
Each service handles a specific part of the pipeline — see AI providers below.
Lyrics sources — web scraping configs live in ~/.yoto/lyrics/*.json. Each file defines one source. Use yoto lyrics --add-source <url> to add a new source interactively — Claude analyzes the site's HTML and generates the JS snippets automatically.
Printing — requires a photo printer configured in macOS System Settings:
YOTO_PRINTER— CUPS printer name (default:Canon_SELPHY_CP1300)YOTO_ICC_PROFILE— path to ICC color profile (optional; skips color management if unset)
How it works
Sync flow — loads local playlist state (tracks, metadata, cover, description), fetches remote state, diffs them, then uploads changed audio through Yoto's transcode pipeline, uploads icons and cover art, and POSTs the assembled content JSON.
Pull flow — fetches the remote card with signed audio URLs, downloads tracks in parallel, wraps each in MKA with metadata and icon attachments, and writes playlist.jsonl and cover.png.
Icon pipeline — if a track already has an icon attachment in its MKA, that icon is used. Otherwise, the track title is matched against Yoto's public icon catalog via LLM. High-confidence matches are used directly; lower-confidence matches are compared against 3 AI-generated alternatives (via RetroDiffusion pixel art). The LLM picks the winner.
Cover art — if cover.png is missing, the tool first checks whether all tracks share identical embedded album art (e.g., from a ripped CD or tagged album). If so, FLUX Kontext recomposes the square art into a 638x1011 portrait layout. Claude checks the result for text quality — if text is mangled after 3 attempts, a repair pipeline kicks in: Claude OCRs the original text, Gemini renders a styled text layer, Claude picks placement coordinates, and PIL composites the text onto the artwork. If no shared album art exists, OpenAI generates a cover from scratch using track metadata. Delete cover.png to regenerate.
Use yoto cover --force to regenerate an existing cover. Set YOTO_RECOMPOSE_ATTEMPTS (default 3) to control how many FLUX attempts before falling back to the text repair pipeline.
YOTO_WORKERS— max parallel workers for downloads, uploads, imports, exports (default: 4)
YouTube downloads — drop a .webloc file (Safari bookmark) into a playlist folder. On yoto sync or yoto download, the URL is resolved via yt-dlp, silence is trimmed from pre/post-roll, and the audio is wrapped in MKA. The .webloc is deleted after successful download.
AI providers
Each AI task uses a specific provider chosen for best results at that task:
| Task | Provider | Key | Pricing |
|---|---|---|---|
| Icon generation (16x16 pixel art) | RetroDiffusion | RETRODIFFUSION_API_KEY |
~$0.003/image |
| Album art recomposition | FLUX Kontext Pro via Together AI | TOGETHER_API_KEY |
~$0.04/image |
| Text layer rendering (cover repair) | Gemini 2.5 Flash | GEMINI_API_KEY |
~$0.07/image |
| Text-to-image cover generation | OpenAI gpt-image-1.5 | OPENAI_API_KEY |
~$0.013/image |
| Descriptions, icon matching, cover evaluation (Sonnet) | Claude CLI | Subscription | Included with Claude subscription |
Getting API keys:
- RetroDiffusion — sign up at retrodiffusion.ai, key is on your dashboard
- Together AI — sign up at together.ai, create key in Settings → API Keys
- Gemini — create a key at aistudio.google.com/apikey (free tier available)
- OpenAI — sign up at platform.openai.com, create key in API Keys
- Claude CLI — install from docs.anthropic.com, uses your Claude subscription
Important: If
ANTHROPIC_API_KEYis set in your environment, the Claude CLI will use it for API-key billing instead of your subscription. This can result in significant per-token charges. Make sureANTHROPIC_API_KEYis not set (or excluded from your.env) to use your Claude subscription.
iTerm2 icon display
If you use iTerm2, the select-icon command can improve pixel art rendering by fixing a color space issue in some iTerm2 color presets (notably "Dark Background"). To enable this:
- Enable iTerm2's Python API: Preferences > General > Magic > "Enable Python API"
The iterm2 Python package will be installed automatically on first use. Without the API enabled, icons display normally but may show faint horizontal banding.
Development
See CONTRIBUTING.md for development setup, commit conventions, and release process.
Architecture
Two-layer design: yoto_lib (standalone library) and yoto_cli (thin Click wrapper). See ARCHITECTURE.md for details.
Disclaimer
This project is not affiliated with, endorsed by, or associated with Yoto Limited. "Yoto" is a trademark of Yoto Limited.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yoto_library-0.2.0.tar.gz.
File metadata
- Download URL: yoto_library-0.2.0.tar.gz
- Upload date:
- Size: 168.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a5629c37fe2f91853ed8415f872582f4999e78bf87a8b46b75183e9e6ff0175
|
|
| MD5 |
dbb8941e8b35ec6918e7a4f5a12886bb
|
|
| BLAKE2b-256 |
eacdbd6e74cb02dabc1de2c838ea80eed57f00444c4dc733dbe6cdef5799ea15
|
Provenance
The following attestation bundles were made for yoto_library-0.2.0.tar.gz:
Publisher:
pypi.yml on steverice/yoto-library
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yoto_library-0.2.0.tar.gz -
Subject digest:
7a5629c37fe2f91853ed8415f872582f4999e78bf87a8b46b75183e9e6ff0175 - Sigstore transparency entry: 1283042365
- Sigstore integration time:
-
Permalink:
steverice/yoto-library@a68bb4fc80fa3e965e299a19f1e5072b0881c405 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/steverice
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@a68bb4fc80fa3e965e299a19f1e5072b0881c405 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file yoto_library-0.2.0-py3-none-any.whl.
File metadata
- Download URL: yoto_library-0.2.0-py3-none-any.whl
- Upload date:
- Size: 119.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63d2e3885109d217a73581b0d14191924f19111e89f8f723bec648463b96f977
|
|
| MD5 |
d41ea5b26e220366857294bdbf5bf9ee
|
|
| BLAKE2b-256 |
c5723f5144e7609891713fe30aa45bc0ea93121dddc73626ebb47c0364ee23ec
|
Provenance
The following attestation bundles were made for yoto_library-0.2.0-py3-none-any.whl:
Publisher:
pypi.yml on steverice/yoto-library
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yoto_library-0.2.0-py3-none-any.whl -
Subject digest:
63d2e3885109d217a73581b0d14191924f19111e89f8f723bec648463b96f977 - Sigstore transparency entry: 1283042371
- Sigstore integration time:
-
Permalink:
steverice/yoto-library@a68bb4fc80fa3e965e299a19f1e5072b0881c405 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/steverice
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@a68bb4fc80fa3e965e299a19f1e5072b0881c405 -
Trigger Event:
workflow_dispatch
-
Statement type: