Skip to content

Saved artists stage 2: save artists to your Library (MAD-839, MAD-840, MAD-841) - #69

Merged
madeofpendletonwool merged 3 commits into
mainfrom
mad-836-saved-artists
Oct 14, 2026
Merged

madeofpendletonwool merged 3 commits into
mainfrom
mad-836-saved-artists

Conversation

@madeofpendletonwool

@madeofpendletonwool madeofpendletonwool commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Stage 2 of Phase 13 (MAD-836): someone queues a band, you think "damn, that's good", and one tap saves the artist to an Artists section in your Library, beside your playlists.

Builds on #68 (linked names, now merged): saved artists open through its artist links.

MAD-839: Data model and API

  • New internal/savedartists package and migration 00031 (saved_artists).
  • Saved artists are personal and on no service. An artist is known by its simplified name (match.Simplify), unique per user. Saving the same artist again, from another service or under another spelling, returns the existing one. It only adds that link to refs, which keeps up to 10 links, newest first, as hints for opening its page.
  • Saving from a room's song (itemId plus artistIndex) checks you can enter the room, and remembers the room and who queued it. Autopilot songs record no one as the person who queued them.
  • Pictures come from the music graph's cache (Deezer), shown through the existing /me/discover/images/artist/... proxy. If the graph doesn't know the artist yet, it's fetched in the background and filled in on a later list. Saving never waits on the network. Without the music graph, rows show an initial instead.
  • API:
    • GET /me/saved-artists (newest first).
    • POST /me/saved-artists returns 201 when new, 200 when already saved.
    • DELETE /me/saved-artists/{id}.
    • Guests get 403.
  • refs link IDs aren't checked on save. They're only hints for the same user, and the app checks you can use a link before opening through it.

MAD-840: Save button

  • A star, so it doesn't look like the bookmark that saves a song to a playlist. It shows:
    • in the now-playing sheet, on the badges row
    • on the room page next to the playlist bookmark
    • as a labelled Save artist button on artist pages, beside "Add to discovery set"
  • From a room's song it saves through the queue item, so the Library knows where you heard the artist.
  • With several artists, the star opens a sheet to pick which to save.
  • The saved state matches everywhere. The web app uses artistKey, a TypeScript copy of match.Simplify, tested with the same examples as the Go function, so another spelling still shows as saved.
  • Save and remove toast with Undo. Undo calls the API directly, so it still works after the star is gone (for example, after you close now playing).
  • Not added to every queue or history row. There's no row menu to put it in, and a star on each row would be cluttered. Say if you want it there.

MAD-841: Library Artists section

  • The Library toggles between Playlists and Artists. The choice is in the URL (?show=artists), so Back and links keep it. The new-playlist button only shows on Playlists.
  • Each row: the picture, the name, and "Living room · queued by Sam · 2 days ago" (or "Saved 2 days ago").
    • Sort by Recent or A–Z. A filter box appears past 12 artists.
    • Tapping opens the artist through the newest of its links you can use, or finds it by name (stage 1's resolve).
    • A compass button adds the artist to a discovery set (Phase 12).
    • The star unsaves, with Undo. An undo from the Library re-saves from the artist's newest link, but loses the room and who queued it.
  • An empty state explains the star in now playing.
  • ArtistLink now takes children, so a whole row can be the link.

Testing

  • go test ./..., golangci-lint (0 issues), and web pnpm test (276), typecheck, lint and build all pass.
  • New tests:
    • TestSavedArtists (HTTP): saving from a song, merging across spellings and services, privacy between users, 400s and 404s, unsaving.
    • savedartists package: picture fill and background warming, the cap on refs.
    • lib/saved-artists.test.ts: key parity with Go, finding saved artists, which link opens, sorting and filtering.
    • Component tests for the star (save, Undo, another spelling, the picker) and the Library list.
  • Not checked yet: nothing has been tried in a browser.

🤖 Generated with Claude Code

madeofpendletonwool and others added 3 commits October 13, 2026 21:48
An artist saved to your Library is personal and on no service. It's
known by its simplified name (match.Simplify), so saving it again from
another service finds the same one, and only adds that link to its refs:
hints, newest first, for opening its page.

- Saving from a room's song (itemId, artistIndex) also remembers the
  room and who queued it. Autopilot's songs are nobody's.
- Pictures come from the music graph's cache (Deezer). An artist the
  graph doesn't know yet is fetched in the background and filled in on
  a later list.
- GET/POST /me/saved-artists and DELETE /me/saved-artists/{id}.
  Guests can't save. Migration 00031 adds saved_artists.

The web lib has the queries, and artistKey, the same simplification,
so the app can tell which artists you already saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A star saves the artist to your Library. It sits in the now-playing
sheet and on the room page beside the playlist bookmark, saving from the
room's song so the Library knows where you heard it. Artist pages get a
labelled Save artist button. With several artists, the star opens a list
to pick from. Saving and removing toast with an Undo, which works even
after the star is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Library switches between Playlists and Artists (?show=artists).
Saved artists are listed newest first or A–Z, with a filter once there
are many. Each shows its picture, where it was heard and who queued it.
Tapping one opens the artist on the newest of its links you can use, or
finds it by name. Each can be added to a discovery set or unsaved.

ArtistLink takes children, so a whole row can be the link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@madeofpendletonwool
madeofpendletonwool changed the base branch from mad-836-linked-names to main October 14, 2026 02:49
@madeofpendletonwool
madeofpendletonwool merged commit 5d35b73 into main Oct 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant