Files
docker-infrastructure/.claude/skills/navidrome/SKILL.md
T
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

85 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: navidrome
description: 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.