From fadaaf3ad14e628162b4b559dbf1c344ed75da98 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 11 Nov 2025 17:35:45 -0500 Subject: [PATCH] refactor(scanner): simplify selective scan logic using slice.Filter Signed-off-by: Deluan --- scanner/scanner.go | 14 +++++--------- utils/slice/slice.go | 11 +++++++++++ utils/slice/slice_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/scanner/scanner.go b/scanner/scanner.go index 96fdb1604..543b9b46a 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -15,6 +15,7 @@ import ( "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/utils/run" + "github.com/navidrome/navidrome/utils/slice" ) type scannerImpl struct { @@ -30,7 +31,6 @@ type scanState struct { changesDetected atomic.Bool libraries model.Libraries // Store libraries list for consistency across phases targets map[int][]string // Optional: map[libraryID][]folderPaths for selective scans - affectedLibIDs []int // IDs of libraries involved in the scan (for GC scoping) } func (s *scanState) sendProgress(info *ProgressInfo) { @@ -74,7 +74,6 @@ func (s *scannerImpl) scanFolders(ctx context.Context, fullScan bool, targets [] if isSelectiveScan { // Selective scan: filter libraries and build targets map state.targets = make(map[int][]string) - affectedLibIDSet := make(map[int]bool) for _, target := range targets { folderPath := target.FolderPath @@ -82,15 +81,12 @@ func (s *scannerImpl) scanFolders(ctx context.Context, fullScan bool, targets [] folderPath = "." } state.targets[target.LibraryID] = append(state.targets[target.LibraryID], folderPath) - affectedLibIDSet[target.LibraryID] = true } - for _, lib := range allLibs { - if affectedLibIDSet[lib.ID] { - libs = append(libs, lib) - state.affectedLibIDs = append(state.affectedLibIDs, lib.ID) - } - } + // Filter libraries to only those in targets + libs = slice.Filter(allLibs, func(lib model.Library) bool { + return len(state.targets[lib.ID]) > 0 + }) log.Info(ctx, "Scanner: Starting selective scan", "fullScan", state.fullScan, "numLibraries", len(libs), "numTargets", len(targets)) } else { diff --git a/utils/slice/slice.go b/utils/slice/slice.go index 1d7c64f50..b1f50afcc 100644 --- a/utils/slice/slice.go +++ b/utils/slice/slice.go @@ -171,3 +171,14 @@ func SeqFunc[I, O any](s []I, f func(I) O) iter.Seq[O] { } } } + +// Filter returns a new slice containing only the elements of s for which filterFunc returns true +func Filter[T any](s []T, filterFunc func(T) bool) []T { + var result []T + for _, item := range s { + if filterFunc(item) { + result = append(result, item) + } + } + return result +} diff --git a/utils/slice/slice_test.go b/utils/slice/slice_test.go index c6d4be1e0..65e5f0934 100644 --- a/utils/slice/slice_test.go +++ b/utils/slice/slice_test.go @@ -172,4 +172,42 @@ var _ = Describe("Slice Utils", func() { Expect(result).To(ConsistOf("2", "4", "6", "8")) }) }) + + Describe("Filter", func() { + It("returns empty slice for an empty input", func() { + filterFunc := func(v int) bool { return v > 0 } + result := slice.Filter([]int{}, filterFunc) + Expect(result).To(BeEmpty()) + }) + + It("returns all elements when filter matches all", func() { + filterFunc := func(v int) bool { return v > 0 } + result := slice.Filter([]int{1, 2, 3, 4}, filterFunc) + Expect(result).To(HaveExactElements(1, 2, 3, 4)) + }) + + It("returns empty slice when filter matches none", func() { + filterFunc := func(v int) bool { return v > 10 } + result := slice.Filter([]int{1, 2, 3, 4}, filterFunc) + Expect(result).To(BeEmpty()) + }) + + It("returns only matching elements", func() { + filterFunc := func(v int) bool { return v%2 == 0 } + result := slice.Filter([]int{1, 2, 3, 4, 5, 6}, filterFunc) + Expect(result).To(HaveExactElements(2, 4, 6)) + }) + + It("works with string slices", func() { + filterFunc := func(s string) bool { return len(s) > 3 } + result := slice.Filter([]string{"a", "abc", "abcd", "ab", "abcde"}, filterFunc) + Expect(result).To(HaveExactElements("abcd", "abcde")) + }) + + It("preserves order of elements", func() { + filterFunc := func(v int) bool { return v%2 == 1 } + result := slice.Filter([]int{9, 8, 7, 6, 5, 4, 3, 2, 1}, filterFunc) + Expect(result).To(HaveExactElements(9, 7, 5, 3, 1)) + }) + }) })