feat(scanner): add library stats to DB (#4229)
* Combine library stats migrations * test: verify full library stats * Fix total_songs calculation * Fix library stats migration * fix(scanner): log elapsed time and number of libraries updated during scan Signed-off-by: Deluan <deluan@navidrome.org> * fix(scanner): refresh library stats conditionally, only if changes were detected Signed-off-by: Deluan <deluan@navidrome.org> * fix(scanner): refresh library stats conditionally, only if changes were detected Signed-off-by: Deluan <deluan@navidrome.org> * fix(scanner): update queries to exclude missing entries in library stats Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
+6
-13
@@ -7,7 +7,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/core"
|
||||
@@ -178,20 +177,14 @@ func (s *controller) Status(ctx context.Context) (*StatusInfo, error) {
|
||||
}
|
||||
|
||||
func (s *controller) getCounters(ctx context.Context) (int64, int64, error) {
|
||||
count, err := s.ds.MediaFile(ctx).CountAll()
|
||||
libs, err := s.ds.Library(ctx).GetAll()
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("media file count: %w", err)
|
||||
return 0, 0, fmt.Errorf("library count: %w", err)
|
||||
}
|
||||
folderCount, err := s.ds.Folder(ctx).CountAll(
|
||||
model.QueryOptions{
|
||||
Filters: squirrel.And{
|
||||
squirrel.Gt{"num_audio_files": 0},
|
||||
squirrel.Eq{"missing": false},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("folder count: %w", err)
|
||||
var count, folderCount int64
|
||||
for _, l := range libs {
|
||||
count += int64(l.TotalSongs)
|
||||
folderCount += int64(l.TotalFolders)
|
||||
}
|
||||
return count, folderCount, nil
|
||||
}
|
||||
|
||||
+13
-2
@@ -100,7 +100,7 @@ func (s *scannerImpl) scanAll(ctx context.Context, fullScan bool, progress chan<
|
||||
s.runRefreshStats(ctx, &state),
|
||||
|
||||
// Update last_scan_completed_at for all libraries
|
||||
s.runUpdateLibraries(ctx, libs),
|
||||
s.runUpdateLibraries(ctx, libs, &state),
|
||||
|
||||
// Optimize DB
|
||||
s.runOptimize(ctx),
|
||||
@@ -175,8 +175,9 @@ func (s *scannerImpl) runOptimize(ctx context.Context) func() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *scannerImpl) runUpdateLibraries(ctx context.Context, libs model.Libraries) func() error {
|
||||
func (s *scannerImpl) runUpdateLibraries(ctx context.Context, libs model.Libraries, state *scanState) func() error {
|
||||
return func() error {
|
||||
start := time.Now()
|
||||
return s.ds.WithTx(func(tx model.DataStore) error {
|
||||
for _, lib := range libs {
|
||||
err := tx.Library(ctx).ScanEnd(lib.ID)
|
||||
@@ -194,7 +195,17 @@ func (s *scannerImpl) runUpdateLibraries(ctx context.Context, libs model.Librari
|
||||
log.Error(ctx, "Scanner: Error updating album PID conf", err)
|
||||
return fmt.Errorf("updating album PID conf: %w", err)
|
||||
}
|
||||
if state.changesDetected.Load() {
|
||||
log.Debug(ctx, "Scanner: Refreshing library stats", "lib", lib.Name)
|
||||
if err := tx.Library(ctx).RefreshStats(lib.ID); err != nil {
|
||||
log.Error(ctx, "Scanner: Error refreshing library stats", "lib", lib.Name, err)
|
||||
return fmt.Errorf("refreshing library stats: %w", err)
|
||||
}
|
||||
} else {
|
||||
log.Debug(ctx, "Scanner: No changes detected, skipping library stats refresh", "lib", lib.Name)
|
||||
}
|
||||
}
|
||||
log.Debug(ctx, "Scanner: Updated libraries after scan", "elapsed", time.Since(start), "numLibraries", len(libs))
|
||||
return nil
|
||||
}, "scanner: update libraries")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user