diff --git a/go.mod b/go.mod index 4b0a70d99..630885d74 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( golang.org/x/image v0.20.0 golang.org/x/sync v0.8.0 golang.org/x/text v0.18.0 + golang.org/x/time v0.6.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 772da2c15..2d01deedf 100644 --- a/go.sum +++ b/go.sum @@ -283,6 +283,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/scanner/scanner.go b/scanner/scanner.go index 365ad1d57..4bcf8658f 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -13,6 +13,7 @@ import ( "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/server/events" "github.com/navidrome/navidrome/utils/singleton" + "golang.org/x/time/rate" ) type Scanner interface { @@ -117,7 +118,8 @@ func (s *scanner) rescan(ctx context.Context, library string, fullRescan bool) e func (s *scanner) startProgressTracker(library string) (chan uint32, context.CancelFunc) { // Must be a new context (not the one passed to the scan method) to allow broadcasting the scan status to all clients ctx, cancel := context.WithCancel(context.Background()) - progress := make(chan uint32, 100) + progress := make(chan uint32, 1000) + limiter := rate.Sometimes{Every: 10} go func() { s.broker.SendMessage(ctx, &events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0}) defer func() { @@ -138,10 +140,12 @@ func (s *scanner) startProgressTracker(library string) (chan uint32, context.Can continue } totalFolders, totalFiles := s.incStatusCounter(library, count) - s.broker.SendMessage(ctx, &events.ScanStatus{ - Scanning: true, - Count: int64(totalFiles), - FolderCount: int64(totalFolders), + limiter.Do(func() { + s.broker.SendMessage(ctx, &events.ScanStatus{ + Scanning: true, + Count: int64(totalFiles), + FolderCount: int64(totalFolders), + }) }) } } diff --git a/scanner/tag_scanner.go b/scanner/tag_scanner.go index b1b1f20f6..ab315c778 100644 --- a/scanner/tag_scanner.go +++ b/scanner/tag_scanner.go @@ -118,7 +118,7 @@ func (s *TagScanner) Scan(ctx context.Context, lib model.Library, fullScan bool, g, walkCtx := errgroup.WithContext(ctx) g.Go(func() error { for folderStats := range pl.ReadOrDone(walkCtx, foldersFound) { - progress <- folderStats.AudioFilesCount + updateProgress(progress, folderStats.AudioFilesCount) allFSDirs[folderStats.Path] = folderStats if s.folderHasChanged(folderStats, allDBDirs, s.lib.LastScanAt) || fullScan { @@ -185,6 +185,13 @@ func (s *TagScanner) Scan(ctx context.Context, lib model.Library, fullScan bool, return s.cnt.total(), err } +func updateProgress(progress chan uint32, count uint32) { + select { + case progress <- count: + default: // It is ok to miss a count update + } +} + func isDirEmpty(ctx context.Context, dir string) (bool, error) { children, stats, err := loadDir(ctx, dir) if err != nil {