feat(server/playlists): Discover system playlist
Adds the third system playlist variant: 'discover'. Surfaces 100 tracks the operator has not played and not liked, biased toward artists they rarely play (< 10 plays) and complemented by tracks liked by other users plus a random unheard sample. Cold start collapses to all-random; single-user servers redistribute the cross-user-likes allocation equally across the other two buckets. The build runs as a fourth phase inside BuildSystemPlaylists alongside For You and the seed-artist mixes. Same daily-deterministic md5(track_id || dateStr) ordering as the other variants. Per-album (<=2) and per-artist (<=3) caps prevent collapse onto a single prolific artist. Buckets interleave round-robin so the playlist order doesn't front-load one bucket's flavour. Post-commit collage generation (already wired) gives Discover the same 4-cell cover treatment as the other system playlists — no new collage code needed. Tests cover the slot-redistribution table (all-available, cold-start, single-user, partial-dormant, fully-empty), the per-album/per-artist caps, the round-robin interleave, and a DB-backed cold-start integration test that asserts a Discover playlist lands with non-zero tracks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -226,6 +226,14 @@ func BuildSystemPlaylists(ctx context.Context, pool *pgxpool.Pool, logger *slog.
|
||||
})
|
||||
}
|
||||
|
||||
// 4. Discover: surface unheard tracks, biased toward dormant artists.
|
||||
discoverTracks, derr := buildDiscoverCandidates(ctx, q, userID, dateStr)
|
||||
if derr != nil {
|
||||
logger.Warn("system playlist: discover candidates load failed; skipping",
|
||||
"user_id", uuidStringPL(userID), "err", derr)
|
||||
discoverTracks = nil
|
||||
}
|
||||
|
||||
// 3. Atomic replace inside a transaction.
|
||||
tx, err := pool.Begin(ctx)
|
||||
if err != nil {
|
||||
@@ -270,6 +278,16 @@ func BuildSystemPlaylists(ctx context.Context, pool *pgxpool.Pool, logger *slog.
|
||||
createdIDs = append(createdIDs, id)
|
||||
}
|
||||
|
||||
if len(discoverTracks) > 0 {
|
||||
id, err := insertSystemPlaylist(ctx, qtx, userID, "Discover", "discover",
|
||||
pgtype.UUID{}, discoverTracks)
|
||||
if err != nil {
|
||||
buildErr = fmt.Errorf("insert discover: %w", err)
|
||||
return buildErr
|
||||
}
|
||||
createdIDs = append(createdIDs, id)
|
||||
}
|
||||
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
buildErr = fmt.Errorf("commit tx: %w", err)
|
||||
return buildErr
|
||||
|
||||
Reference in New Issue
Block a user