Commit Graph
3 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5.5 dabe1e052d feat: genre mixes pick specific genres that don't share songs (#6933)
release / go (push) Successful in 2m0s
release / web (push) Successful in 1m33s
release / govulncheck (push) Successful in 18s
release / integration (push) Successful in 5m11s
release / android (push) Successful in 4m14s
release / Build signed APK (push) Successful in 4m38s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 29s
release / Verify release artifacts (tag releases only) (push) Skipped
The shelf had four mixes built largely from the same lo-fi beats: about
1,250 tracks carry Hip Hop, Lo-Fi, Instrumental, Downtempo and four more
tags at once, and the near-duplicate guard compared artists, not songs, so
each tag passed as its own channel.

Genre selection now works on songs:
- ListGenreMixCandidates returns each genre's track ids instead of its
  artist ids.
- A broad genre, one whose songs mostly also carry clearly narrower
  candidates (Rock over Pop Punk and Ska Punk), is considered after the
  specific genres of its tier.
- A genre is kept only when at least half its songs are not already in a
  kept genre.
- Each mix leaves out songs tagged with a genre kept before it
  (ListGenreMixTracks exclude_genres), so a song is in one mix at most.

The tiers, the minimum shelf and the minimum mix length are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 14:55:19 -05:00
bvandeusenandClaude Opus 5.5 14debe2ea9 feat: genre mixes lean toward what the listener likes (#6921)
release / web (push) Successful in 1m40s
release / go (push) Successful in 2m5s
release / govulncheck (push) Successful in 19s
release / integration (push) Successful in 5m2s
release / android (push) Successful in 4m40s
release / Build signed APK (push) Successful in 5m7s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 32s
release / Verify release artifacts (tag releases only) (push) Skipped
Within a genre both halves of the mix were a uniform daily draw: a song
played forty times was no likelier than one played once, and the unheard
40% ignored who the artist was. ListGenreMixTracks now draws each half by a
date-seeded weighted lottery (Efraimidis-Spirakis: smallest -ln(u)/weight
wins), so the mix still changes daily and holds within a day.

- Familiar: 1 + ln(1 + plays) + 1 if liked, times the share of plays that
  weren't skips.
- Unheard: 1 + ln(1 + the artist's plays + 2 x its liked tracks)
  + 2 x the artist's best similarity to the user's own artists, times the
  artist's non-skip share. An unknown artist weighs 1, so new artists still
  come up.

Which genres are offered, the exclusions and the familiar/unheard blend
are unchanged. DB tests check the lean averaged over ten days, and that a
stranger's tracks stay in the pool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 14:21:04 -05:00
bvandeusenandClaude Opus 5.5 dbaa8b7d57 feat: genre mixes — a daily playlist per genre you listen to, on a "Your genres" Home row (#6904)
release / Build signed APK (push) Successful in 4m34s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
release / web (push) Successful in 1m24s
release / govulncheck (push) Successful in 25s
release / go (push) Successful in 1m47s
release / integration (push) Failing after 4m38s
release / android (push) Successful in 4m3s
A new system playlist kind, genre_mix: up to 10 "{Genre} mix" playlists per
user, rebuilt daily with the other system mixes.

Which genres: library genres with at least 25 playable tracks across 3
artists, ranked in tiers — taste-profile genres first (matched
case-insensitively, so ID3 "Post-Punk" and folksonomy "post-punk" are one),
then genres the user has played or liked, then the rest of the library, which
only tops a short shelf up to 4. A genre whose artist set is a near
duplicate of one already picked (Jaccard >= 0.5) is skipped, so "Lo-Fi" and
"Lo-Fi Hip Hop" don't both appear but "Alternative Rock" survives "Rock". A
genre that can't fill 15 tracks gives way to the next.

Each mix is 50 tracks: 3 in 5 the user already knows (played through or
liked), the rest unheard in that genre, interleaved, with the usual
per-album/per-artist caps. Tracks skipped twice and more often than played
are left out. The order changes daily and holds within a day. Picks are
stamped taste / taste_unheard, and genre_mix plays count toward rotation and
the recommendation metrics.

Migration 0102 adds genre_mix to the playlists variant constraints.

Web and Android each get a "Your genres" row in name order, hidden until a
mix exists. Kinds with several playlists per user now play by playlist id
wherever the client used to test seed_artist_id (web card, detail page
self-heal), keyed on the server's refreshable flag; on Android genre_mix
joins songs_like_artist as not refreshable. The web detail page's
"mix was rebuilt" reload now finds a Songs-like or genre mix by name instead
of calling the by-kind shuffle, which those kinds don't have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:30:41 -05:00