Skip to content

Personal discovery stage 3: Fresh releases (MAD-822, MAD-823) - #67

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

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

Conversation

@madeofpendletonwool

Copy link
Copy Markdown
Owner

Stage 3 of Phase 12 (MAD-814): the Fresh feed, "new releases for you". It shows recent albums, EPs and singles by a set's seed artists and their nearest neighbors.

MAD-822: Recent releases lookup

  • New internal/releases package. It merges three sources by artist and normalized title:
    • ListenBrainz fresh releases: one 90-day list for everything, read every 6 hours and indexed by artist MBID and name.
    • MusicBrainz release groups, searched by first-release date. This goes through the shared one-request-a-second client and retries once if MusicBrainz is busy. Year-only dates are skipped.
    • Deezer artist albums, which carry the cover and the Deezer ID that tracks and previews come from.
  • Each release is dated from its earliest Deezer edition, so a deluxe reissue doesn't make an old album look new.
  • Kinds are album, ep, single, compilation and live.
  • Releases are cached a day per artist in artist_releases, or an hour if a source failed (migration 00030, which also adds discovery_sets.fresh_days).
  • In the background, every set's seeds and their ten nearest neighbors are warmed one artist at a time, every 6 hours.

MAD-823: Fresh feed

  • API:
    • GET /me/discover/sets/{setId}/fresh returns the feed.
    • GET /me/discover/release-tracks returns a release's songs from Deezer, with previews.
    • GET /me/discover/release-art/{mbid} serves Cover Art Archive covers for releases Deezer doesn't have.
    • Sets have a new freshDays setting (30, 60 or 90; default 60).
  • Ranking: compilations and live albums come last. Ahead of them, the seeds' releases come first, then albums and EPs before singles. Within those, a release scores higher the nearer its artist is, the more recent it is, and by the set's explore lean.
  • Filtering: releases you own (HasRelease), want, or by an artist you blocked are left out. There are at most 3 per artist and 100 in all.
  • Speed: the feed reads the cache. It fetches up to 4 seeds' releases that aren't cached, within 6 seconds, warms the rest, and says it's partial. The page reloads it while it fills in.
  • Web:
    • Fresh is now enabled in the mode toggle, with a 30/60/90-day window toggle.
    • Release cards show cover, kind, date and why the release is here. A Songs button lists its tracks with previews and YouTube links.
    • Each card has a YouTube search for the whole release, and "Not for me".
    • In Both mode, Fresh cards are mixed into the deep-cuts feed with a New badge.
  • The optional unread dot on the Discover tab isn't built. It would mean working out every set's Fresh feed for the tab bar. ADR 0017 notes this.

Testing

  • go test ./..., golangci-lint (0 issues), and web pnpm test (252), typecheck and lint all pass.
  • Live run of the lookup against ListenBrainz, MusicBrainz and Deezer:
    • Merges came out right, e.g. Turnstile's "Never Enough: Versions" from all three sources.
    • It caught two bugs, both fixed and tested: a deluxe reissue showing as new, and "every source failed" when one source was rate-limited while the others had nothing recent.
  • Live run of the server, with a set of Wednesday, Turnstile and Waxahatchee:
    • The first, cold load came back empty and partial after 6 seconds.
    • Later loads took 6ms. One about 20 seconds later had 7 releases, and the next was complete with 12.
    • Release tracks and Cover Art Archive covers load. A cover's first fetch is slow (about 9s, through archive.org), then cached.
  • Not checked yet: the UI hasn't been looked at in a browser, so it's covered by component tests only.
  • TestGamesAPI failed once in a full run and then passed 5 of 5 runs on its own, plus the final full run. It's unrelated to this change and looks flaky.

🤖 Generated with Claude Code

madeofpendletonwool and others added 2 commits October 13, 2026 12:40
…MAD-823)

internal/releases finds an artist's releases from the last 100 days. It
merges ListenBrainz's fresh releases (one list, read every 6 hours),
MusicBrainz release groups by first-release date, and Deezer's albums.
Releases match by artist and title, and each counts from its first
edition, so a deluxe reissue isn't new. Answers are cached a day per
artist (migration 00030), and every set's seeds and their nearest
neighbors are warmed in the background.

GET /me/discover/sets/{setId}/fresh ranks a set's recent releases:
- The seeds' come first, albums and EPs before singles, and
  compilations and live albums last.
- Releases you have, want, or by blocked artists are left out.
- It looks back the set's freshDays (30, 60 or 90).

The release-tracks and release-art endpoints serve a release's songs with
previews, and Cover Art Archive covers. ADR 0017 is updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Fresh mode on a set lists recent releases near your artists. Each
release card shows its cover, kind, date and why it's there. Open a card
to see its songs with previews; it also has a YouTube search for the
whole release. A window toggle picks 30, 60 or 90 days. In Both mode,
Fresh cards are mixed into the deep-cuts feed with a New badge. The song
row is shared with the map's artist sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@madeofpendletonwool
madeofpendletonwool merged commit f891cec 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