-- Keep ListenBrainz's whole similar-recordings answer, and record every -- fetch, so the library match is made locally and can be made again. -- -- Before: the worker kept only the recordings already in the library (at most -- 20 of LB's 50) and threw the rest away. Two things followed: -- -- * A recording that reached the library later — a Lidarr import, or an MBID -- filled in by the AcoustID lookup — was not linked until its seed was -- fetched again. -- * A seed with no in-library match wrote nothing at all, and freshness was -- read from track_similarity, so that seed was never fresh. With the queue -- ordered by id, such seeds held its head and were re-asked every hour -- while the rest waited. -- -- The listenbrainz rows in track_similarity are now derived from this cache by -- ResolveListenBrainzTrackEdges. CREATE TABLE listenbrainz_similar_recordings ( seed_track_id uuid NOT NULL REFERENCES tracks(id) ON DELETE CASCADE, recording_mbid text NOT NULL, score DOUBLE PRECISION NOT NULL, PRIMARY KEY (seed_track_id, recording_mbid) ); -- The resolve joins the cache to tracks by recording MBID. CREATE INDEX listenbrainz_similar_recordings_mbid_idx ON listenbrainz_similar_recordings (recording_mbid); -- One row per seed that ListenBrainz has answered for, an empty answer -- included. The worker's queue reads this, not the edges. CREATE TABLE track_similarity_fetches ( track_id uuid PRIMARY KEY REFERENCES tracks(id) ON DELETE CASCADE, fetched_at timestamptz NOT NULL DEFAULT now(), returned integer NOT NULL ); -- The same for artists. Their answer is already kept, in artist_similarity and -- artist_similarity_unmatched; this only stops an empty answer being re-asked. CREATE TABLE artist_similarity_fetches ( artist_id uuid PRIMARY KEY REFERENCES artists(id) ON DELETE CASCADE, fetched_at timestamptz NOT NULL DEFAULT now(), returned integer NOT NULL );