Skip to main content

Generate and play music playlists from natural language prompts or seed songs

Project description

myplaylist

PyPI version Python versions

Generate and play music playlists in your terminal from natural language prompts or seed songs.

myplaylist TUI — playlist view with lyrics panel and mood animation

Why myplaylist?

  • AI-native, terminal-first — describe any mood or song in plain language and get a curated playlist instantly, without leaving your terminal
  • Ad-free playback — streams directly from YouTube via yt-dlp and mpv; no ads, no interruptions
  • You own your playlists — add, delete, reorder, and save tracks live during playback; export to M3U/CSV/JSON for use anywhere
  • Vast music catalog — any song on YouTube is fair game, from mainstream hits to obscure jazz recordings and everything in between
  • No account, no tracking — everything stays local in ~/.myplaylist/; no sign-up, no cloud sync, no data collection
  • Zero extra subscription — works with your existing Claude subscription, a free Groq/Qwen/DeepSeek API key, or a local Ollama instance; no music platform membership required
  • Immersive terminal experience — time-synced lyrics and mood-driven ASCII animations keep the vibe going while you work
  • Background playback — detach to a headless daemon with b or --detach; close the terminal and music keeps playing
  • Remote controlmyplaylist ctl next/pause/quit from any terminal, or attach a full TUI with myplaylist attach
  • Global hotkeys — system-wide keyboard shortcuts via skhd (macOS); control playback from any app

Features

  • Natural language prompts: myplaylist new "下雨天的 lo-fi jazz"
  • Seed songs: myplaylist new --seed "Norah Jones - Come Away With Me"
  • Terminal playback via mpv with a rich TUI (pause / skip / lyrics marquee / progress bar)
  • Headless daemon mode: myplaylist play --detach or press b during playback to background
  • Attach TUI: myplaylist attach connects to a running daemon with full keyboard controls
  • Remote control: myplaylist ctl pause, myplaylist ctl next, myplaylist ctl quit
  • Global hotkeys: myplaylist hotkeys sets up system-wide shortcuts (Ctrl+Alt+P/N/Q/R/A)
  • Lyrics panel: toggle a side panel showing time-synced lyrics with mood-driven ASCII animations
  • In-session append: press + to fetch ~10 more tracks without interrupting playback
  • Playlist loops: automatically restarts from track 1 after the last track
  • Local persistence at ~/.myplaylist/playlists/
  • Export to .m3u, .csv, or .json
  • Multiple LLM backends: Claude Code CLI (zero-config), Gemini, Groq, Qwen (通义千问), DeepSeek, Kimi, Ollama (local/offline), or any OpenAI-compatible endpoint

Requirements

  • Python 3.9+
  • macOS or Linux
  • One of the following LLM backends (for natural language mode):
    • Claude Code CLI (claude) — zero-config if you have a Claude subscription
    • Gemini API key — set via myplaylist setup
    • Groq, Qwen (通义千问), DeepSeek, or Kimi — free API keys, set via myplaylist setup
    • Ollama — fully local, no API key, works offline

Installation

macOS — Homebrew (recommended)

brew tap haoziwlh/autoplaylist https://github.com/haoziwlh/autoplaylist && brew install myplaylist

Homebrew handles everything: Python, mpv, and myplaylist itself.

macOS / Linux — curl one-liner

curl -fsSL https://raw.githubusercontent.com/haoziwlh/autoplaylist/main/install.sh | bash

The script detects your OS, installs pipx, myplaylist, and mpv automatically.

Manual — pipx

pipx install myplaylist

mpv is required for playback. Install it separately if needed:

  • macOS: brew install mpv
  • Linux: sudo apt-get install mpv

On first run, myplaylist will automatically guide you through setup (LLM backend, optional Last.fm key).

Quick Start

# Play your most recent playlist instantly
myplaylist

# Natural language prompt
myplaylist new "rainy day lo-fi jazz for working"

# Seed song
myplaylist new --seed "Norah Jones - Come Away With Me"

# Seed from YouTube URL
myplaylist new --seed "https://www.youtube.com/watch?v=..."

# Custom track count (default 20, max 50) and name
myplaylist new "chill beats" --count 30 --name my-chill-list

Commands

Command Description
myplaylist Play the most recent playlist
myplaylist new "<prompt>" Generate playlist from natural language
myplaylist new --seed "<song>" Generate playlist from seed song
myplaylist new ... --count <n> Set track count (default 20, max 50)
myplaylist list List all saved playlists
myplaylist show <name> Show track listing
myplaylist play [name] Play a playlist (defaults to most recent)
myplaylist export <name> --format m3u|csv|json Export playlist
myplaylist delete <name> Delete a playlist
myplaylist play --detach Start playback as a background daemon
myplaylist attach Attach TUI to a running daemon
myplaylist ctl status Show current playback status
myplaylist ctl pause Toggle pause / resume
myplaylist ctl next Skip to next track
myplaylist ctl mode [seq|repeat|shuffle] Cycle or set play mode
myplaylist ctl quit Stop the player daemon
myplaylist hotkeys Set up global keyboard shortcuts (macOS)
myplaylist hotkeys --show Show current hotkey bindings
myplaylist hotkeys --remove Remove hotkeys and stop skhd
myplaylist setup Choose LLM backend and configure API keys
myplaylist doctor Diagnose playback prerequisites (yt-dlp, mpv, JS runtime)

Playback Controls

Key Action
p Pause / resume
n Skip to next track
, / . Seek ±5 seconds (mpv-style)
< / > Seek ±30 seconds
↑ / ↓ Move cursor up / down
← / → Page up / page down
Enter Jump to selected track
09 + Enter Jump to track by number
+ Append ~10 more tracks (background, non-blocking)
r Cycle playback mode: sequential →→ / repeat-one ↺ / shuffle ⇄
l Toggle lyrics panel (time-synced lyrics + mood animation)
y Cycle to next lyrics source (when multiple candidates available)
[ / ] Switch to previous / next playlist
d Delete cursor track from live playlist
s Save current playlist to disk
b Detach to background daemon (music keeps playing)
q Quit

Background Playback & Global Hotkeys

Detach to background: press b during playback or start with myplaylist play --detach. Music keeps playing after the terminal closes.

Remote control from any terminal:

myplaylist ctl pause      # toggle pause
myplaylist ctl next       # skip track
myplaylist ctl status     # show what's playing
myplaylist attach         # full TUI reconnect

Global hotkeys (macOS):

myplaylist hotkeys        # install skhd + configure default bindings
myplaylist hotkeys --show # show current bindings

Default bindings (Ctrl+Alt+…):

Shortcut Action
Ctrl+Alt+P Pause / resume
Ctrl+Alt+N Next track
Ctrl+Alt+Q Quit daemon
Ctrl+Alt+R Cycle play mode
Ctrl+Alt+A Open attach TUI

The attach hotkey opens Terminal.app by default. To use iTerm2 (new tab in existing window), edit ~/.config/skhd/skhdrc:

# Replace the ctrl + alt - a line with:
ctrl + alt - a : osascript -e 'tell app "iTerm2"' -e 'if (count of windows) > 0 then' -e 'tell current window to create tab with default profile' -e 'else' -e 'create window with default profile' -e 'end if' -e 'tell current session of current window to write text "myplaylist ctl status >/dev/null 2>&1 || myplaylist play --detach; sleep 1; exec myplaylist attach"' -e 'end tell'

Lyrics Panel

Press l during playback to open a side panel with time-synced lyrics. The panel also shows a mood-driven ASCII animation in the margin — determined per track by the LLM (calm, melancholic, energetic, romantic, nostalgic).

Lyrics are fetched in parallel from three sources: lrclib.net (up to 3 candidates), Netease Cloud Music, and Kugou Music — improving coverage for Chinese music and tracks not found on lrclib. Press y to cycle through available sources (the preferred source is remembered for next time); press Y to discard the cached lyrics and re-fetch fresh candidates.

Requires terminal width ≥ 84 columns.

Last.fm (optional)

Last.fm integration improves similar-song quality — without it, myplaylist falls back to yt-dlp search only.

Getting a free API key:

  1. Go to https://www.last.fm/api/account/create (create a Last.fm account first if needed)
  2. Fill in any values for Application name / description (e.g. myplaylist / personal use)
  3. Leave Callback URL blank, submit
  4. Copy the API key and Shared secret from the confirmation page

Saving the key:

myplaylist config --lastfm-key <API key> --lastfm-secret <shared secret>

Or re-run setup and enter them interactively:

myplaylist setup

LLM Backends

Run myplaylist setup to choose your backend interactively. You can also switch at any time:

myplaylist config --llm-backend groq --llm-api-key <key>
myplaylist config --llm-backend qwen --llm-api-key <key>
myplaylist config --llm-backend ollama --ollama-model qwen2.5:7b
Backend Free? Notes
claude With Claude subscription Zero-config; recommended
gemini Free tier gemini-2.5-flash
groq Free tier Fast inference; llama3
qwen Free credits Best for Chinese music; get key
deepseek Free credits Strong reasoning; get key
kimi Free credits Moonshot AI; get key
ollama Free, local Requires Ollama + ollama pull qwen2.5:7b
openai-compat Varies Any OpenAI-compatible endpoint

Troubleshooting

Playback stuck on "Loading" / tracks all skipped

YouTube occasionally requires authentication for certain IPs. myplaylist automatically tries to use cookies from your browser (Chrome, Firefox, Edge, or Brave) to work around this. If you still have issues:

  1. Run with --debug to see what's happening:
    myplaylist play --debug
    cat ~/.myplaylist/player.log
    
  2. If the log shows Sign in to confirm you're not a bot, export a cookies.txt file from your browser using an extension such as Get cookies.txt LOCALLY (Chrome) or cookies.txt (Firefox), then:
    myplaylist config --cookie-file ~/cookies.txt
    

YouTube signature decryption errors (e.g. Some formats may be missing or nsig extraction failed)

YouTube requires a JavaScript runtime to decrypt video signatures. myplaylist passes --remote-components ejs:github to fetch the decryption script on the fly — but you still need a local JS runtime. Install one:

brew install deno           # recommended (macOS)
# or: brew install node / bun

Run myplaylist doctor to confirm the runtime is detected. The doctor output also shows whether yt-dlp-ejs is installed locally (reduces per-play network calls).

myplaylist command not found after install

Open a new terminal, or run:

source ~/.zshrc   # macOS / zsh
source ~/.bashrc  # Linux / bash

Data Storage

~/.myplaylist/
  config.json          # API keys and settings
  playlists/
    <name>.json        # Saved playlists
  cache/
    audio/             # Cached audio files (LRU, default 500 MB)
    lyrics/            # Cached lyrics per track

Audio and lyrics are cached on first play for faster subsequent loads and offline listening. When a cached track plays, the status line shows a marker (e.g. ⚡ Playing [3/20] …). Cache size is configurable:

myplaylist config --cache-max-mb 1000   # increase to 1 GB
myplaylist cache --clear                # clear everything
myplaylist cache --clear-audio          # clear audio only
myplaylist cache --clear-lyrics         # clear lyrics only

Upgrade

# pipx
pipx upgrade myplaylist

# Homebrew
brew upgrade myplaylist

Uninstall

# If installed via pipx or the install.sh script:
pipx uninstall myplaylist

# If installed via Homebrew tap:
brew uninstall myplaylist
brew untap haoziwlh/autoplaylist

License

MIT — see LICENSE.

Running Tests

pip install pytest
pytest tests/                     # smoke tests (no network)
pytest tests/ -m slow             # include integration tests (requires network)

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

myplaylist-0.4.4.tar.gz (79.9 kB view details)

Uploaded Source

Built Distribution

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

myplaylist-0.4.4-py3-none-any.whl (72.6 kB view details)

Uploaded Python 3

File details

Details for the file myplaylist-0.4.4.tar.gz.

File metadata

  • Download URL: myplaylist-0.4.4.tar.gz
  • Upload date:
  • Size: 79.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for myplaylist-0.4.4.tar.gz
Algorithm Hash digest
SHA256 f8b9efe1a00acb489a209dd14bf4434905ac98a2e46be0eb3d06e180a33322a7
MD5 87af52bd976a999283b99ee34254b87a
BLAKE2b-256 2ef41482fa0e24a514020e1845ecf9498738d3c9fadb8a06dab0e94bbbc4ad7f

See more details on using hashes here.

Provenance

The following attestation bundles were made for myplaylist-0.4.4.tar.gz:

Publisher: release.yml on haoziwlh/autoplaylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file myplaylist-0.4.4-py3-none-any.whl.

File metadata

  • Download URL: myplaylist-0.4.4-py3-none-any.whl
  • Upload date:
  • Size: 72.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for myplaylist-0.4.4-py3-none-any.whl
Algorithm Hash digest
SHA256 e3e35e672c2b11201229212fe896f9dbdf1531637c82b476f1f8344d18b6ef0d
MD5 4fd837447f54298d7b51f2d98d3d2c1d
BLAKE2b-256 f8ae6e60aed764e4652268f6f5bed71098c8a39c6e743d78a42a8fac96e3a63a

See more details on using hashes here.

Provenance

The following attestation bundles were made for myplaylist-0.4.4-py3-none-any.whl:

Publisher: release.yml on haoziwlh/autoplaylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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