Skip to content

Personal discovery, stage 1: sets and feed (MAD-815..819) - #65

Merged
madeofpendletonwool merged 2 commits into
mainfrom
mad-814-discovery-stage-1
Oct 13, 2026
Merged

madeofpendletonwool merged 2 commits into
mainfrom
mad-814-discovery-stage-1

Conversation

@madeofpendletonwool

Copy link
Copy Markdown
Owner

Phase 12 (MAD-814), stage 1: seed sets and a feed of music you don't have yet. See ADR 0017.

What's in it

  • MAD-815: data model and ADR 0017. Migration 00029 adds discovery_sets, discovery_set_artists, discovery_feedback, discovery_blocks and want_items, plus library_indexes and deezer_songs. Every query is scoped to its user. Includes store tests.
  • MAD-816: library index (internal/library). Uses a new optional provider.Cataloger, which Navidrome implements with search3, an empty query and 500 songs a page. The index lives in memory and in SQLite and is rebuilt daily or on demand. A rebuild is skipped while getScanStatus.lastScan hasn't changed. It answers Has, HasRelease and KnowsArtist, matching by ISRC or MBID first, then by normalized artist and title (live takes count as different songs). A test builds a 60k-song index from a fake Subsonic server and checks that lookups take under 1ms.
  • MAD-817: discovery engine and API (internal/discover). Walks the music graph out from a set's seeds. Artists near several seeds rank higher. A second hop happens at explore 35 or more, and the seeds' own songs are included as deep cuts. Deezer rank and fan counts are blended in, and a high explore leans toward less-known artists. Pages hold 20 songs: the seeds take turns, and no artist gets more than 2 songs a page. Each song carries because. A build is capped at 15s and kept for 10 minutes. What you own, thumbed down or blocked is filtered again on every page served, so a thumbs-down takes effect at once.
  • MAD-818: Deezer previews. dzTrack now parses the preview, album and cover. Top songs keep their Deezer ID. GET /me/discover/preview/{id} gets a fresh signed URL each time and proxies it with byte ranges, accepting audio only from Deezer's CDN. Covers come through /me/discover/images/..., so the browser never talks to Deezer. Songs with no Deezer ID are looked up once, and misses are cached too.
  • MAD-819: Discover tab. Lists your sets. A set page has seed chips with artist search (any artist, via Deezer), an explore slider and the Deep cuts / Fresh / Both toggle. The feed scrolls endlessly, and each card has a preview (one at a time, local only), a YouTube search link, 👍, 👎 and "Not for me" with Undo. Also adds library index status, a list of blocked artists, and "Add to discovery set" on artist pages. Guests don't see the tab, and the API answers them forbidden.

Notes

  • The feed uses its own walk rather than dj.walk, which is built around a room's members and what they've heard. This one starts from seeds and swaps "playable on your links" for "not in your library". The ADR explains why.
  • newMusicGraph now also returns the Deezer source, so previews share its rate limiter.
  • 👍 is only stored for now (stage 4 adds the Want list), and Fresh mode does nothing until stage 3.

Testing

  • go test -race ./... and golangci-lint run both pass. pnpm typecheck, lint and test pass.
  • Checked against live Deezer and MusicBrainz on a throwaway server. A Slowdive / Hum / Duster set gave 20 songs a page with reasons (MBV, Pumpkins, Galaxie 500, Broadcast…), and the first build took about 14s while the cache was cold. Previews returned 200 and 206 with Content-Range, covers loaded, and infinite scroll went from 20 to 40 items. Screenshots were taken at 390px and 1280px wide.
  • Not tested against a real Navidrome library: the index was only tested with the fake Subsonic server.

🤖 Generated with Claude Code

madeofpendletonwool and others added 2 commits October 13, 2026 09:40
Seed sets of hand-picked artists, each its own feed of music you don't
have yet (ADR 0017). The feed walks the music graph out from the seeds,
ranks artists near several seeds first, and leaves out what's on your
own Navidrome links, what you turned down, and artists you blocked.

The library index lists each Navidrome link with search3, keeps it in
memory and SQLite, and rebuilds daily or on demand, skipping libraries
that haven't been scanned since. Deezer previews are fetched fresh and
proxied with byte ranges, so the browser never talks to Deezer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Discover tab in the app shell, for members: make sets of artists you
love, add any artist by searching, tune how far the feed explores, and
scroll a feed of songs you don't have, each saying which seeds it's
near. Play a 30-second preview here only (the room's playback and Media
Session are left alone), open the whole song on YouTube, thumb it, or
say an artist isn't for you. Artist pages can add the artist to a set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@madeofpendletonwool
madeofpendletonwool merged commit c6729c0 into main Oct 13, 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