Distilled from tonight's session building SUB/WAVE anchor-playlist shows by hand: a CLI (search/artist/album/playlist get/create/replace/ add/remove) plus a playlist-audit command that flags accidental full-album dumps, replacing the one-off curl/Python snippets used throughout. SKILL.md documents the gotchas hit along the way (case-sensitive artist matching, deluxe-reissue duplicate tracks, createPlaylist's full-replace semantics) and this session's curation conventions (15-20 tracks/artist, prefer playlistStrict). Claude-Session: https://claude.ai/code/session_01L7Rwa6guD5wK8F8tWQwcJX
4.6 KiB
name, description
| name | description |
|---|---|
| navidrome | Query and edit the Navidrome music library/playlists (search artists/albums, inspect or build playlists, audit for accidental full-album dumps). Use for any SUB/WAVE anchor-playlist curation work or general Navidrome library lookups. |
Navidrome (Subsonic API)
A CLI wrapper (navidrome_api.py, in this skill's directory) around Navidrome's
Subsonic API, distilled from a long session of building SUB/WAVE anchor-playlist
shows by hand. Use it instead of writing one-off curl/Python snippets — every
gotcha below was hit at least once doing it the ad-hoc way.
Setup
Auth/URL come from /srv/subwave/state/setup-config.json (world-readable),
already pointed at navidrome:4533 — the script rewrites that host to
localhost for you. No flags needed for auth.
Run it as: python3 .claude/skills/navidrome/navidrome_api.py <command> ...
Commands
search <query> [--artists N] [--albums N] [--songs N] # raw multi-type search
artist <name> # albums + track counts for one artist
album <artist> <album> # track ids for one album
playlists # list all playlists (id, count, name)
playlist get <id> # dump entries
playlist create <name> --ids id1,id2,... # new playlist
playlist replace <id> --ids id1,id2,... # FULL REPLACE of contents
playlist add <id> --ids id1,id2,... # append in place
playlist remove <id> --ids id1,id2,... # remove by id, in place
playlist audit <id> [--min-size N] # full-album-dump check (see below)
Gotchas learned the hard way
-
Artist name casing is inconsistent and case-sensitive matching silently drops real hits.
eelsis lowercase,CAKEis uppercase, most others are title-case. A naiveartist["name"] == "Eels"filter returns "not found" even though the artist is right there.artist/albumin this script already do case-insensitive exact matching — don't re-derive this bug with a freshcurl. -
An artist with 0 albums from
getArtistisn't necessarily absent — it may only have loose tracks scattered across compilations (soundtrack/box-set albums credited to "Various Artists"). Fall back tosearch3with a highsongCountand filter by exact artist name (theartistcommand does this automatically when it finds zero grouped albums). -
Reissues/deluxe editions duplicate the base album's tracks under a different album name (
DoolittlevsDoolittle 25,Bricks Are Heavyvs a live/remix bonus disc, etc). When curating, pick tracks from ONE edition — checkalbumoutput for suspiciously large counts before assuming it's all distinct songs. -
createPlaylistwithplaylistIdset REPLACES the entire contents — it is not additive. Useplaylist replaceonly when you intend to overwrite everything (e.g., rebuilding after a curation pass). Useplaylist add/playlist removefor incremental edits to an existing playlist. -
No native "remove by id" in the Subsonic API —
playlist removehere works by reading the current entries, filtering out the unwanted ids in Python, then doing a fullreplace. This is safe (order-preserving for everything you keep) but means a remove is really a replace under the hood. -
playlist audit's "FULL ALBUM" flag is a signal, not a verdict. A genuinely short album (say, 10 tracks) will always show10/10with nothing left to trim, and an artist you were explicitly told to go "heavy" on is fine full. Use it to know where to look, then use judgment (or ask) before trimming.
Curation conventions established this session
- Default to ~15–20 tracks per artist for an anchor playlist, not a full discography — unless the user explicitly asks for heavier coverage of a specific artist ("heavy Nirvana", "triple that, focusing on XTC").
- Prefer
playlistStrict: trueon SUB/WAVE shows with a pinned anchor playlist. Soft-anchor (playlistStrict: false) was tried and rolled back station-wide after live testing showed the playlist rarely won picks over the genre/mood fallback pool, and the fallback's unfiltered "explore" source could drift the show off-genre (seesubwave/bug-report-soft-anchor-drift.md). - Cross-show duplicate tracks are fine for these anchor-genre shows (the no-duplicate rule only applies to the historical radio-chart recreation shows) — don't spend time deduplicating against other playlists unless asked.