Add Artists view for browsing albums grouped by artist
Summary
Adds a new /artists page so you can browse the library by artist and see all of an artist's albums — unsorted and already-sorted — side by side. This is useful when a new album comes in and you want to match the date format, category, and naming of what's already on disk, and when you have several unsorted albums by the same artist that are faster to sort together.
Layout
Two panes:
- Left: searchable artist list, with pending-count (blue) and sorted-count (gray) badges.
-
Right: selected artist header, then an Unsorted section (reuses
AlbumCard) and a Sorted section (new lightweightSortedAlbumCard). Empty state when nothing is selected.
Clicking an unsorted album opens the existing Organize slide-over so you can sort in place — the same UX as the home page.
Grouping
Case-insensitive + trimmed matching, so Beatles / BEATLES / Beatles collapse into one row. Display name preference: parsedArtist → tagArtist → sortedAlbums.artist → Unknown Artist.
Refactor
Extracted the home page's Organize slide-over into a new AlbumOrganizePanel component (owning its own audio element + keyboard handlers). Both / and /artists mount it, so there's only one copy of the panel.
API
-
GET /api/artists→{ artists: [{ key, name, pendingCount, sortedCount }] } -
GET /api/artists/[key]→{ name, pendingAlbums, sortedAlbums }
Backed by new getArtistIndex / getArtistDetail service functions in scanner.ts.
Test plan
-
pnpm run buildpasses -
/artistsrenders (empty state locally, no test data) -
Home page still loads and nav has new "Artists" entry -
On the NUC (or with data): artist list populates with correct counts; search filters the list; clicking an artist loads their unsorted + sorted sections; clicking an unsorted album opens the Organize panel; sorting an album updates counts without a manual refresh -
Edge cases worth spot-checking: artist with only sorted albums, artist with only pending albums, two albums with different casing collapse into one row, album where parsedArtistis null buttagArtistis set