package scanner import ( "context" "log" "naviwatcher/internal/database" ) // ScanArtist loads the local albums and external releases for a single artist // from the database and computes the list of missing releases. // // threshold is the fuzzy-similarity cutoff; pass 0 to use DefaultThreshold. // The context is checked before querying the database; if it is already // cancelled, no work is performed and the sentinel error ctx.Err() is returned. func ScanArtist(ctx context.Context, db *database.DB, artistID string, threshold float64) ([]MissingRelease, error) { if err := ctx.Err(); err != nil { return nil, err } local, err := database.GetLocalAlbumsByArtist(db, artistID) if err != nil { return nil, err } external, err := database.GetExternalReleasesByArtist(db, artistID) if err != nil { return nil, err } missing := FindMissingReleases(local, external, threshold) return missing, nil } // ScanAll iterates over all monitored artists (those with Monitored == true) // and computes the missing releases for each. Results are concatenated into a // single slice across all artists. // // ctx.Err() is checked between artists; if cancellation occurs mid-iteration, // scanning stops early and the accumulated results so far are returned along // with the cancellation error. threshold follows the same contract as // ScanArtist (0 → DefaultThreshold). func ScanAll(ctx context.Context, db *database.DB, threshold float64) ([]MissingRelease, error) { settings, err := database.GetAllArtistSettings(db) if err != nil { return nil, err } var all []MissingRelease for _, s := range settings { if err := ctx.Err(); err != nil { return all, err } if !s.Monitored { continue } // A transient error for one artist must not abort the whole scan and // take down the daemon; log it and continue with the remaining artists. missing, err := ScanArtist(ctx, db, s.ID, threshold) if err != nil { log.Printf("scan artist %s failed: %v", s.ID, err) continue } all = append(all, missing...) } return all, nil }