Files
poprhythm 435cb931b6 Add navidrome skill for Subsonic API playlist curation
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
2026-09-13 23:20:02 +00:00

4.6 KiB
Raw Permalink Blame History

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. eels is lowercase, CAKE is uppercase, most others are title-case. A naive artist["name"] == "Eels" filter returns "not found" even though the artist is right there. artist/album in this script already do case-insensitive exact matching — don't re-derive this bug with a fresh curl.

  • An artist with 0 albums from getArtist isn't necessarily absent — it may only have loose tracks scattered across compilations (soundtrack/box-set albums credited to "Various Artists"). Fall back to search3 with a high songCount and filter by exact artist name (the artist command does this automatically when it finds zero grouped albums).

  • Reissues/deluxe editions duplicate the base album's tracks under a different album name (Doolittle vs Doolittle 25, Bricks Are Heavy vs a live/remix bonus disc, etc). When curating, pick tracks from ONE edition — check album output for suspiciously large counts before assuming it's all distinct songs.

  • createPlaylist with playlistId set REPLACES the entire contents — it is not additive. Use playlist replace only when you intend to overwrite everything (e.g., rebuilding after a curation pass). Use playlist add / playlist remove for incremental edits to an existing playlist.

  • No native "remove by id" in the Subsonic API — playlist remove here works by reading the current entries, filtering out the unwanted ids in Python, then doing a full replace. 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 show 10/10 with 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: true on 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 (see subwave/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.