-- Discover playlist bucket queries. Each returns up to its LIMIT -- count of (track_id, album_id, artist_id) triples ordered -- daily-deterministically via md5(track_id || dateStr). The Go-side -- bucket allocator (internal/playlists/discover.go) applies -- per-album (<=2) and per-artist (<=3) caps then redistributes any -- bucket deficit equally across the others. LIMIT values are -- generous so the caps + redistribution have headroom. -- name: ListDormantArtistTracksForDiscover :many -- Tracks whose artist this user has played fewer than 10 times total. -- The artist threshold defines "dormant" — we want to surface the -- long tail of artists in the user's library that they rarely listen -- to. Excludes tracks the user has played, liked, or has quarantined. -- $1 = user_id, $2 = date string for md5 ordering. WITH user_artist_counts AS ( SELECT t.artist_id, COUNT(*) AS play_count FROM play_events pe JOIN tracks t ON t.id = pe.track_id WHERE pe.user_id = $1 AND pe.was_skipped = false GROUP BY t.artist_id ), dormant_artists AS ( SELECT a.id FROM artists a LEFT JOIN user_artist_counts uac ON uac.artist_id = a.id WHERE COALESCE(uac.play_count, 0) < 10 ) SELECT t.id, t.album_id, t.artist_id FROM tracks t JOIN dormant_artists da ON da.id = t.artist_id WHERE NOT EXISTS ( SELECT 1 FROM play_events pe WHERE pe.user_id = $1 AND pe.track_id = t.id AND pe.was_skipped = false ) AND NOT EXISTS ( SELECT 1 FROM general_likes gl WHERE gl.user_id = $1 AND gl.track_id = t.id ) AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ORDER BY md5(t.id::text || $2::text) LIMIT 80; -- name: ListCrossUserLikedTracksForDiscover :many -- Tracks any OTHER user has liked, that this user hasn't played, -- liked, or had quarantined. On single-user servers this returns 0 -- rows (the caller's slot redistribution rolls the deficit into the -- other two buckets). -- $1 = user_id, $2 = date string for md5 ordering. SELECT DISTINCT t.id, t.album_id, t.artist_id FROM general_likes gl JOIN tracks t ON t.id = gl.track_id WHERE gl.user_id != $1 AND NOT EXISTS ( SELECT 1 FROM play_events pe WHERE pe.user_id = $1 AND pe.track_id = t.id AND pe.was_skipped = false ) AND NOT EXISTS ( SELECT 1 FROM general_likes ml WHERE ml.user_id = $1 AND ml.track_id = t.id ) AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ORDER BY md5(t.id::text || $2::text) LIMIT 60; -- name: ListRandomUnheardTracksForDiscover :many -- Random sample from the entire library. Same exclusion filters as -- the other two buckets. The generous LIMIT (200) gives the caller -- headroom for the per-album/artist caps and the slot redistribution. -- $1 = user_id, $2 = date string for md5 ordering. SELECT t.id, t.album_id, t.artist_id FROM tracks t WHERE NOT EXISTS ( SELECT 1 FROM play_events pe WHERE pe.user_id = $1 AND pe.track_id = t.id AND pe.was_skipped = false ) AND NOT EXISTS ( SELECT 1 FROM general_likes gl WHERE gl.user_id = $1 AND gl.track_id = t.id ) AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ORDER BY md5(t.id::text || $2::text) LIMIT 200;