-- name: ListPlayedTracksNeedingSimilarity :many -- Tracks with at least one play, an MBID, and no fresh listenbrainz row -- (no row at all, OR fetched_at older than 7 days). Used by the worker -- to find work each tick. Bounded by $1. SELECT DISTINCT t.id, t.mbid FROM tracks t JOIN play_events pe ON pe.track_id = t.id WHERE t.mbid IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM track_similarity ts WHERE ts.track_a_id = t.id AND ts.source = 'listenbrainz' AND ts.fetched_at > now() - interval '7 days' ) ORDER BY t.id LIMIT $1; -- name: ListPlayedArtistsNeedingSimilarity :many SELECT DISTINCT ar.id, ar.mbid FROM artists ar JOIN tracks t ON t.artist_id = ar.id JOIN play_events pe ON pe.track_id = t.id WHERE ar.mbid IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM artist_similarity asim WHERE asim.artist_a_id = ar.id AND asim.source = 'listenbrainz' AND asim.fetched_at > now() - interval '7 days' ) ORDER BY ar.id LIMIT $1; -- name: GetTracksByMBIDs :many -- Bulk in-library lookup: maps a slice of MBIDs back to local track IDs. SELECT id, mbid FROM tracks WHERE mbid = ANY($1::text[]); -- name: GetArtistsByMBIDs :many SELECT id, mbid FROM artists WHERE mbid = ANY($1::text[]); -- name: UpsertTrackSimilarity :exec INSERT INTO track_similarity (track_a_id, track_b_id, score, source, fetched_at) VALUES ($1, $2, $3, 'listenbrainz', now()) ON CONFLICT (track_a_id, track_b_id, source) DO UPDATE SET score = EXCLUDED.score, fetched_at = EXCLUDED.fetched_at; -- name: UpsertArtistSimilarity :exec INSERT INTO artist_similarity (artist_a_id, artist_b_id, score, source, fetched_at) VALUES ($1, $2, $3, 'listenbrainz', now()) ON CONFLICT (artist_a_id, artist_b_id, source) DO UPDATE SET score = EXCLUDED.score, fetched_at = EXCLUDED.fetched_at; -- name: UpsertArtistSimilarityUnmatched :exec -- Persists an out-of-library similar-artist MBID. Idempotent on -- (seed_artist_id, candidate_mbid, source) — re-fetches refresh the -- name/score and bump fetched_at. INSERT INTO artist_similarity_unmatched ( seed_artist_id, candidate_mbid, candidate_name, score, source ) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (seed_artist_id, candidate_mbid, source) DO UPDATE SET candidate_name = EXCLUDED.candidate_name, score = EXCLUDED.score, fetched_at = now(); -- name: ListSimilarArtistsForArtist :many -- In-library artists similar to a seed artist, ranked by best similarity -- score across sources (deduped per candidate). cover_album_id + album_count -- mirror ListArtistsAlphaWithCovers so the strip renders identical cards. SELECT sqlc.embed(artists), cov.id AS cover_album_id, cnt.album_count::bigint AS album_count FROM ( SELECT artist_b_id, max(score) AS sim_score FROM artist_similarity WHERE artist_a_id = sqlc.arg(seed_artist_id) GROUP BY artist_b_id ) s JOIN artists ON artists.id = s.artist_b_id LEFT JOIN LATERAL ( SELECT id FROM albums WHERE artist_id = artists.id AND cover_art_path IS NOT NULL ORDER BY created_at DESC LIMIT 1 ) cov ON true LEFT JOIN LATERAL ( SELECT count(*) AS album_count FROM albums WHERE artist_id = artists.id ) cnt ON true ORDER BY s.sim_score DESC, artists.sort_name LIMIT sqlc.arg(result_limit);