feat: add DB-backed scanner entrypoint and compute-only main hook

Implements ScanArtist/ScanAll in internal/scanner loading local/external
releases via the database layer with ctx-cancellation checks, plus a
compute-only run() hook that logs missing-release counts. Add table-driven
tests using in-memory SQLite fixtures.
This commit is contained in:
2026-07-19 18:19:57 +03:00
parent a4f0460664
commit c2da8c2095
6 changed files with 348 additions and 8 deletions

View File

@@ -12,6 +12,7 @@ import (
"naviwatcher/internal/config"
"naviwatcher/internal/database"
"naviwatcher/internal/musicbrainz"
"naviwatcher/internal/scanner"
)
// App holds all application dependencies for clean shutdown and testability.
@@ -91,9 +92,27 @@ func (a *App) Close() {
}
func (a *App) run(ctx context.Context) error {
// Compute-only scanner hook: scan all monitored artists for missing
// releases and log the count. Notifier/Web UI are out of scope for this
// plan, so results are only logged. This call is non-blocking and
// goroutine-safe; it observes ctx cancellation and returns early.
missing, err := scanner.ScanAll(ctx, a.db, a.cfg.Scanner.FuzzyThreshold)
if err != nil {
if ctx.Err() != nil {
// Context cancelled (e.g. shutdown) — exit cleanly.
return nil
}
return fmt.Errorf("scan all: %w", err)
}
log.Printf("Scan complete: %d missing release(s) across monitored artists", len(missing))
for _, m := range missing {
log.Printf(" missing: artist=%s rgid=%s title=%q", m.ArtistID, m.RGID, m.Title)
}
// Main application loop — blocks until context is cancelled.
// Business logic (scanner, notifier, web server) will be wired into
// separate goroutines here in future tasks.
// Business logic (notifier, web server) will be wired into separate
// goroutines here in future tasks.
<-ctx.Done()
return nil
}