-- 0069_acoustid_lookup.up.sql — recording MBIDs looked up through AcoustID -- for tracks whose tags carry none (Scribe milestone #401). -- -- A track with no recording MBID is invisible to the ListenBrainz similarity -- arm in both directions, so this fills the ids the tags leave empty. -- Where tracks.mbid came from. The file's own tag always outranks a lookup -- (M401 D4): the scan's upsert keeps a looked-up id while the tag carries -- none, and replaces it the moment the tag carries one. ALTER TABLE tracks ADD COLUMN mbid_source text; -- Every id stored so far was read from a tag (the scan or the tag backfill), -- or inherited from a merged duplicate's tag. UPDATE tracks SET mbid_source = 'tag' WHERE mbid IS NOT NULL; ALTER TABLE tracks ADD CONSTRAINT tracks_mbid_source_check CHECK (mbid_source IN ('tag', 'acoustid')), ADD CONSTRAINT tracks_mbid_source_pair CHECK ((mbid IS NULL) = (mbid_source IS NULL)); -- What happened the last time a track was looked up. A table of its own, as -- track_loudness is (0065): tracks is read with SELECT * on the hot path. -- -- What a row means, which the lookup worker depends on: -- no row never looked up, or the file changed since (the scan deletes -- the row): look it up -- matched one recording cleared the score threshold, or one was left -- after disambiguating by title and length; recording_mbid is it -- ambiguous several recordings cleared it and nothing told them apart. -- Nothing is written: a wrong MBID would feed similarity the -- wrong neighbours, which is worse than none (M401 D5) -- no_match AcoustID linked nothing at or above the threshold -- failed fpcalc rejected the file, or AcoustID rejected its print -- Every state is settled until the file changes. A failure that says nothing -- about the file (AcoustID unreachable, a timeout, a cancelled pass) writes no -- row, so the worker tries again. CREATE TABLE track_acoustid_lookups ( track_id uuid PRIMARY KEY REFERENCES tracks (id) ON DELETE CASCADE, state text NOT NULL, -- The best score any linked recording had; NULL when none was linked. best_score real, -- How many distinct recordings were linked, at any score. candidates integer NOT NULL DEFAULT 0, recording_mbid text, -- Why a lookup failed, for the admin list. detail text, looked_up_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT track_acoustid_lookups_state_check CHECK (state IN ('matched', 'ambiguous', 'no_match', 'failed')), CONSTRAINT track_acoustid_lookups_matched_has_mbid CHECK ((state = 'matched') = (recording_mbid IS NOT NULL)) ); CREATE INDEX track_acoustid_lookups_state ON track_acoustid_lookups (state); -- AcoustID's knobs, in admin Settings (rule 25). Singleton in the style of -- loudness_settings (0065). CREATE TABLE acoustid_settings ( id boolean PRIMARY KEY DEFAULT true, -- Off by default (rule 26): AcoustID needs a key the operator registers, -- and the lookup sends fingerprints to a third party. enabled boolean NOT NULL DEFAULT false, api_key text, -- The score a recording needs before it is considered at all. AcoustID -- scores a true match close to 1; 0.85 leaves room for a lossy encode. min_score real NOT NULL DEFAULT 0.85, updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT acoustid_settings_singleton CHECK (id = true), CONSTRAINT acoustid_settings_min_score_range CHECK (min_score >= 0.5 AND min_score <= 1) ); INSERT INTO acoustid_settings (id) VALUES (true) ON CONFLICT (id) DO NOTHING;