🏡 index : quine-global/quintodrome.git

// Package matcher matches song results from external agents (Last.fm, Deezer,
// etc.) to tracks in the local music library, prioritizing accuracy over recall.
//
// It exposes a single [Matcher] type with two entry points that share the same
// matching algorithm:
//
//   - [Matcher.MatchSongs] returns an ordered, deduplicated slice of library
//     tracks, capped at a requested count. Use it when presenting "similar
//     songs" results to a client.
//   - [Matcher.MatchSongsIndexed] returns a map from input-song index to matched
//     track, with no deduplication. Use it when the caller needs to correlate
//     each result back to its input position (e.g. to attach a per-song
//     similarity score).
//
// # Algorithm Overview
//
// Each input song is resolved to its best-matching library track using four
// strategies, applied in priority order. A song matched by a higher-priority
// strategy is never reconsidered by a lower-priority one:
//
//  1. Direct ID match: songs with an ID are matched to a MediaFile by ID.
//  2. MusicBrainz Recording ID (MBID) match: songs with an MBID are matched to
//     tracks with the same mbz_recording_id.
//  3. ISRC match: songs with an ISRC are matched to tracks carrying that ISRC tag.
//  4. Title+Artist fuzzy match: remaining songs are matched by fuzzy string
//     comparison with metadata-specificity scoring (see below).
//
// Priority order is ID > MBID > ISRC > Title+Artist, so more reliable
// identifiers always take precedence over fuzzy text matching. Missing tracks
// (those no longer present on disk) are never matched.
//
// # Fuzzy Matching Details
//
// Title+artist matching uses Jaro-Winkler similarity, with a threshold
// configurable via conf.Server.Matcher.FuzzyThreshold (default 85%). A library
// track must clear the title threshold to be considered. Candidates that clear
// it are ranked by, in order:
//
//  1. Title similarity (Jaro-Winkler score, 0.0–1.0)
//  2. Duration proximity (closer duration scores higher; 1.0 when the agent
//     reports no duration)
//  3. Specificity level (0–5, based on metadata precision; higher is better)
//  4. Artist overlap (how many of the song's artists the track credits; more
//     shared artists is better)
//  5. Preferred-track flag (enabled by conf.Server.Matcher.PreferStarred;
//     prioritizes tracks that are starred or rated >= 4, but only among
//     candidates of equal specificity and overlap)
//  6. Album similarity (Jaro-Winkler, as the final tiebreaker)
//
// The specificity levels, from most to least specific, are:
//
//	Level 5: Title + Artist identity + Album MBID
//	Level 4: Title + Artist identity + Album name (fuzzy)
//	Level 3: Title + Artist name + Album name (fuzzy)
//	Level 2: Title + Artist identity
//	Level 1: Title + Artist name
//	Level 0: Title only
//
// "Artist identity" is a match on the artist's Navidrome ID (the strongest signal,
// when a source supplies one) or its MBID. A plain name match is the weaker fallback
// used for an artist with no identity match (e.g. a cover credited to a different
// artist of the same name).
//
// The title phase always requires an agent artist to scope the library query, so
// Level 0 does not mean "no artist": it applies when a candidate matches on title
// but its own artist differs from the query's (e.g. a cover or a featured-artist
// credit), leaving the title as the only shared field.
//
// A song may carry several artists, and the title phase scopes candidate tracks by
// ANY of them: a track credited to at least one shared artist is considered. When a
// source supplies a Navidrome artist ID, that artist is matched directly, skipping
// name/MBID resolution. Among equally specific candidates, the one sharing more of
// the song's artists wins, so a track crediting every collaborator outranks one
// crediting only a single artist.
//
// Each input song is scored independently, so two songs with the same title and
// artist but different durations can resolve to different library tracks (each
// matches the track closest to its own duration).
//
// # Examples
//
// All examples below exercise the title+artist phase, where the interesting
// behavior lives. (Identifier phases — ID, MBID, ISRC — are exact lookups that
// always win over fuzzy matching; they need no illustration.)
//
// Title threshold — a near-miss title still matches; an exact-only threshold
// rejects it:
//
//	Agent returns: {Name: "Bohemian Rhapsody", Artist: "Queen"}
//	Library has:   {ID: "t1", Title: "Bohemian Rhapsody - Remastered", Artist: "Queen"}
//	With threshold 85%: match succeeds (similarity ~0.87)
//	With threshold 100%: no match (not an exact title)
//
// Specificity ranking — among candidates that clear the title threshold, a
// better album match wins:
//
//	Agent returns: {Name: "Enjoy the Silence", Artist: "Depeche Mode", Album: "Violator"}
//	Library has:
//	  {ID: "t1", Title: "Enjoy the Silence", Artist: "Depeche Mode", Album: "101"}       // Level 1
//	  {ID: "t2", Title: "Enjoy the Silence", Artist: "Depeche Mode", Album: "Violator"}  // Level 3
//	Result: t2 (Level 3 beats Level 1 on the album match)
//
// Duration tiebreak — with title and artist equal, the closest duration wins,
// so two near-identical input songs can resolve to different tracks:
//
//	Agent returns:
//	  {Name: "Untitled", Artist: "Interpol", Duration: 245000}  // 4:05
//	  {Name: "Untitled", Artist: "Interpol", Duration: 600000}  // 10:00 (a live take)
//	Library has:
//	  {ID: "studio", Title: "Untitled", Artist: "Interpol", Duration: 248}  // 4:08
//	  {ID: "live",   Title: "Untitled", Artist: "Interpol", Duration: 602}  // 10:02
//	Result: studio for the first song, live for the second
//
// Preferred track — when conf.Server.Matcher.PreferStarred is enabled, a
// starred (or rating >= 4) track is preferred, but only when specificity and
// artist overlap are equal. A more specific match always wins regardless of the
// preferred flag:
//
//	Agent returns: {Name: "Enjoy the Silence", Artist: "Depeche Mode", Album: "Violator"}
//	Library has:
//	  {ID: "exact",   Title: "Enjoy the Silence", Artist: "Depeche Mode", Album: "Violator"}            // Level 3
//	  {ID: "starred", Title: "Enjoy the Silence", Artist: "Depeche Mode", Album: "Singles", Starred: true} // Level 1, starred
//	Result: exact (specificity outranks the starred flag; preferred only breaks ties of equal identity)
package matcher