Add FindMissingReleases and MissingRelease to internal/scanner: skips IsIgnored external releases, scopes matches per ArtistID, and reports external releases with no local album above the fuzzy threshold.
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package scanner
|
|
|
|
import (
|
|
"naviwatcher/internal/database"
|
|
)
|
|
|
|
// MissingRelease describes an external release that has no sufficiently similar
|
|
// local album. It is a flattened, consumer-friendly projection of a
|
|
// database.ExternalRelease.
|
|
type MissingRelease struct {
|
|
RGID string `json:"rgid"`
|
|
ArtistID string `json:"artist_id"`
|
|
Title string `json:"title"`
|
|
Type string `json:"type"`
|
|
ReleaseDate string `json:"release_date"`
|
|
}
|
|
|
|
// FindMissingReleases compares an artist's external discography against the
|
|
// user's local albums and returns the releases that are present externally but
|
|
// have no sufficiently similar local album.
|
|
//
|
|
// Rules:
|
|
// - External releases flagged IsIgnored are never reported.
|
|
// - A local album only matches an external release for the same ArtistID.
|
|
// - An external release is "missing" when none of the local albums (same
|
|
// ArtistID) IsMatch at the given threshold.
|
|
func FindMissingReleases(local []database.LocalAlbum, external []database.ExternalRelease, threshold float64) []MissingRelease {
|
|
// Group local albums by artist for O(1) lookup per external release.
|
|
localByArtist := make(map[string][]database.LocalAlbum)
|
|
for _, a := range local {
|
|
localByArtist[a.ArtistID] = append(localByArtist[a.ArtistID], a)
|
|
}
|
|
|
|
var missing []MissingRelease
|
|
for _, ext := range external {
|
|
if ext.IsIgnored {
|
|
continue
|
|
}
|
|
|
|
albums := localByArtist[ext.ArtistID]
|
|
matched := false
|
|
for _, a := range albums {
|
|
if IsMatch(a.Title, ext.Title, threshold) {
|
|
matched = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if matched {
|
|
continue
|
|
}
|
|
|
|
missing = append(missing, MissingRelease{
|
|
RGID: ext.RGID,
|
|
ArtistID: ext.ArtistID,
|
|
Title: ext.Title,
|
|
Type: ext.Type,
|
|
ReleaseDate: ext.ReleaseDate,
|
|
})
|
|
}
|
|
|
|
return missing
|
|
}
|