-- Candidate queries for the discovery system-playlist mixes -- (#419-423). Each returns (id, album_id, artist_id) rows; the Go -- producer caps + truncates and converts to rankedCandidate. Daily- -- deterministic md5(id||dateStr) ordering (where used) keeps a mix -- stable within a day while rotating across days; shuffle-on-play -- gives per-play variety on top. -- name: ListDeepCutsTracks :many -- #419 Deep Cuts: low-play tracks (<=2 plays) from artists the user -- has liked OR played heavily (>=5 non-skip plays across the artist). -- $1 user_id, $2 date string. WITH affinity_artists AS ( SELECT artist_id FROM general_likes_artists WHERE user_id = $1 UNION SELECT t.artist_id 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 HAVING COUNT(*) >= 5 ), play_counts AS ( SELECT track_id, COUNT(*) AS c FROM play_events WHERE user_id = $1 AND was_skipped = false GROUP BY track_id ) SELECT t.id, t.album_id, t.artist_id FROM tracks t JOIN affinity_artists aa ON aa.artist_id = t.artist_id LEFT JOIN play_counts pc ON pc.track_id = t.id WHERE COALESCE(pc.c, 0) <= 2 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; -- name: ListRediscoverTracks :many -- #420 Rediscover: tracks the user played a lot (>=5 non-skip) but -- has drifted away from. Tiered so a young library still gets a mix: -- tier 0 not played in the last 6 months (true rediscovery) -- tier 1 (only if tier 0 empty) not played in the last 30 days -- Ordered by historical affection. $1 user_id. WITH stats AS ( SELECT pe.track_id, COUNT(*) AS c, MAX(pe.started_at) AS last_at FROM play_events pe WHERE pe.user_id = $1 AND pe.was_skipped = false GROUP BY pe.track_id ), deep AS ( SELECT t.id, t.album_id, t.artist_id, s.c, 0 AS tier FROM tracks t JOIN stats s ON s.track_id = t.id WHERE s.c >= 5 AND s.last_at <= now() - interval '6 months' AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ), shallow AS ( SELECT t.id, t.album_id, t.artist_id, s.c, 1 AS tier FROM tracks t JOIN stats s ON s.track_id = t.id WHERE s.c >= 5 AND s.last_at <= now() - interval '30 days' AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ) SELECT id, album_id, artist_id FROM ( SELECT id, album_id, artist_id, c, tier FROM deep UNION ALL SELECT id, album_id, artist_id, c, tier FROM shallow WHERE NOT EXISTS (SELECT 1 FROM deep) ) u ORDER BY tier, c DESC, id LIMIT 200; -- name: ListNewForYouTracks :many -- #421 New for you: tracks from albums added in the last 30 days -- whose artist the user has liked OR played (>=3 non-skip). Album- -- coherent (newest album first, then disc/track) — the producer does -- NOT diversity-cap these; they're meant as whole-album discovery. -- $1 user_id. WITH affinity_artists AS ( SELECT artist_id FROM general_likes_artists WHERE user_id = $1 UNION SELECT t.artist_id 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 HAVING COUNT(*) >= 3 ) SELECT t.id, t.album_id, t.artist_id FROM tracks t JOIN albums al ON al.id = t.album_id JOIN affinity_artists aa ON aa.artist_id = al.artist_id WHERE al.created_at >= now() - interval '30 days' AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ORDER BY al.created_at DESC, t.disc_number NULLS FIRST, t.track_number NULLS FIRST LIMIT 200; -- name: ListOnThisDayTracks :many -- #422 On This Day: tracks the user played around this calendar date -- (±10 day-of-year) in the past, excluding the very recent (>30 days -- ago) so it's nostalgic, not just "last week". Weighted by how much -- they were played in those windows. Floor relaxed from 60→30 days -- and window ±7→±10 so it surfaces on a months-old library instead -- of needing a full year of history; still skips cleanly (no rows → -- no playlist) when there's no qualifying history yet. -- $1 user_id, $2 date string. WITH windowed AS ( SELECT track_id, COUNT(*) AS c FROM play_events WHERE user_id = $1 AND was_skipped = false AND started_at < now() - interval '30 days' AND ABS(EXTRACT(DOY FROM started_at) - EXTRACT(DOY FROM now())) <= 10 GROUP BY track_id ) SELECT t.id, t.album_id, t.artist_id FROM tracks t JOIN windowed w ON w.track_id = t.id WHERE NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ORDER BY w.c DESC, md5(t.id::text || $2::text) LIMIT 200; -- name: ListFirstListensTracks :many -- #423 First Listens: albums the user has never played any track of. -- Tiered: liked-artist albums first, then played-artist albums, then -- the rest — album-coherent within each tier. Not diversity-capped -- (whole-album discovery). $1 user_id. WITH heard_albums AS ( SELECT DISTINCT t.album_id FROM play_events pe JOIN tracks t ON t.id = pe.track_id WHERE pe.user_id = $1 ), played_artists AS ( SELECT DISTINCT t.artist_id FROM play_events pe JOIN tracks t ON t.id = pe.track_id WHERE pe.user_id = $1 ) SELECT t.id, t.album_id, t.artist_id FROM tracks t JOIN albums al ON al.id = t.album_id WHERE NOT EXISTS (SELECT 1 FROM heard_albums h WHERE h.album_id = al.id) AND NOT EXISTS ( SELECT 1 FROM lidarr_quarantine q WHERE q.user_id = $1 AND q.track_id = t.id ) ORDER BY (CASE WHEN EXISTS ( SELECT 1 FROM general_likes_artists gla WHERE gla.user_id = $1 AND gla.artist_id = al.artist_id ) THEN 0 WHEN al.artist_id IN (SELECT artist_id FROM played_artists) THEN 1 ELSE 2 END), al.id, t.disc_number NULLS FIRST, t.track_number NULLS FIRST LIMIT 300;