mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-04 13:07:36 +03:00
Better termination handling in Scanner's progress
This commit is contained in:
parent
3ad36ebd2a
commit
f29bb211d1
3 changed files with 36 additions and 31 deletions
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/deluan/navidrome/conf"
|
"github.com/deluan/navidrome/conf"
|
||||||
"github.com/deluan/navidrome/log"
|
"github.com/deluan/navidrome/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fullRescan bool
|
var fullRescan bool
|
||||||
|
@ -26,7 +27,7 @@ func runScanner() {
|
||||||
conf.Server.DevPreCacheAlbumArtwork = false
|
conf.Server.DevPreCacheAlbumArtwork = false
|
||||||
|
|
||||||
scanner := GetScanner()
|
scanner := GetScanner()
|
||||||
_ = scanner.RescanAll(fullRescan)
|
_ = scanner.RescanAll(context.Background(), fullRescan)
|
||||||
if fullRescan {
|
if fullRescan {
|
||||||
log.Info("Finished full rescan")
|
log.Info("Finished full rescan")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
type Scanner interface {
|
type Scanner interface {
|
||||||
Start(interval time.Duration)
|
Start(interval time.Duration)
|
||||||
Stop()
|
Stop()
|
||||||
RescanAll(fullRescan bool) error
|
RescanAll(ctx context.Context, fullRescan bool) error
|
||||||
Status(mediaFolder string) (*StatusInfo, error)
|
Status(mediaFolder string) (*StatusInfo, error)
|
||||||
Scanning() bool
|
Scanning() bool
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ func (s *scanner) Start(interval time.Duration) {
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
err := s.RescanAll(false)
|
err := s.RescanAll(context.Background(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ func (s *scanner) Stop() {
|
||||||
s.done <- true
|
s.done <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
|
func (s *scanner) rescan(ctx context.Context, mediaFolder string, fullRescan bool) error {
|
||||||
folderScanner := s.folders[mediaFolder]
|
folderScanner := s.folders[mediaFolder]
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
@ -105,16 +105,16 @@ func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
|
||||||
|
|
||||||
lastModifiedSince := time.Time{}
|
lastModifiedSince := time.Time{}
|
||||||
if !fullRescan {
|
if !fullRescan {
|
||||||
lastModifiedSince = s.getLastModifiedSince(mediaFolder)
|
lastModifiedSince = s.getLastModifiedSince(ctx, mediaFolder)
|
||||||
log.Debug("Scanning folder", "folder", mediaFolder, "lastModifiedSince", lastModifiedSince)
|
log.Debug("Scanning folder", "folder", mediaFolder, "lastModifiedSince", lastModifiedSince)
|
||||||
} else {
|
} else {
|
||||||
log.Debug("Scanning folder (full scan)", "folder", mediaFolder)
|
log.Debug("Scanning folder (full scan)", "folder", mediaFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
progress := s.startProgressTracker(mediaFolder)
|
progress, cancel := s.startProgressTracker(mediaFolder)
|
||||||
defer close(progress)
|
defer cancel()
|
||||||
|
|
||||||
err := folderScanner.Scan(log.NewContext(context.TODO()), lastModifiedSince, progress)
|
err := folderScanner.Scan(ctx, lastModifiedSince, progress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error importing MediaFolder", "folder", mediaFolder, err)
|
log.Error("Error importing MediaFolder", "folder", mediaFolder, err)
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,8 @@ func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) startProgressTracker(mediaFolder string) chan uint32 {
|
func (s *scanner) startProgressTracker(mediaFolder string) (chan uint32, context.CancelFunc) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
progress := make(chan uint32, 100)
|
progress := make(chan uint32, 100)
|
||||||
go func() {
|
go func() {
|
||||||
s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0})
|
s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0})
|
||||||
|
@ -135,25 +136,26 @@ func (s *scanner) startProgressTracker(mediaFolder string) chan uint32 {
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
count, more := <-progress
|
select {
|
||||||
if !more {
|
case <-ctx.Done():
|
||||||
break
|
return
|
||||||
|
case count := <-progress:
|
||||||
|
if count == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
totalFolders, totalFiles := s.incStatusCounter(mediaFolder, count)
|
||||||
|
s.broker.SendMessage(&events.ScanStatus{
|
||||||
|
Scanning: true,
|
||||||
|
Count: int64(totalFiles),
|
||||||
|
FolderCount: int64(totalFolders),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if count == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
totalFolders, totalFiles := s.incStatusCounter(mediaFolder, count)
|
|
||||||
s.broker.SendMessage(&events.ScanStatus{
|
|
||||||
Scanning: true,
|
|
||||||
Count: int64(totalFiles),
|
|
||||||
FolderCount: int64(totalFolders),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return progress
|
return progress, cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) RescanAll(fullRescan bool) error {
|
func (s *scanner) RescanAll(ctx context.Context, fullRescan bool) error {
|
||||||
if s.Scanning() {
|
if s.Scanning() {
|
||||||
log.Debug("Scanner already running, ignoring request for rescan.")
|
log.Debug("Scanner already running, ignoring request for rescan.")
|
||||||
return ErrAlreadyScanning
|
return ErrAlreadyScanning
|
||||||
|
@ -164,7 +166,7 @@ func (s *scanner) RescanAll(fullRescan bool) error {
|
||||||
defer s.cacheWarmer.Flush(context.Background())
|
defer s.cacheWarmer.Flush(context.Background())
|
||||||
var hasError bool
|
var hasError bool
|
||||||
for folder := range s.folders {
|
for folder := range s.folders {
|
||||||
err := s.rescan(folder, fullRescan)
|
err := s.rescan(ctx, folder, fullRescan)
|
||||||
hasError = hasError || err != nil
|
hasError = hasError || err != nil
|
||||||
}
|
}
|
||||||
if hasError {
|
if hasError {
|
||||||
|
@ -232,8 +234,8 @@ func (s *scanner) Status(mediaFolder string) (*StatusInfo, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) getLastModifiedSince(folder string) time.Time {
|
func (s *scanner) getLastModifiedSince(ctx context.Context, folder string) time.Time {
|
||||||
ms, err := s.ds.Property(context.TODO()).Get(model.PropLastScan + "-" + folder)
|
ms, err := s.ds.Property(ctx).Get(model.PropLastScan + "-" + folder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}
|
return time.Time{}
|
||||||
}
|
}
|
||||||
|
@ -252,7 +254,8 @@ func (s *scanner) updateLastModifiedSince(folder string, t time.Time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) loadFolders() {
|
func (s *scanner) loadFolders() {
|
||||||
fs, _ := s.ds.MediaFolder(context.TODO()).GetAll()
|
ctx := context.TODO()
|
||||||
|
fs, _ := s.ds.MediaFolder(ctx).GetAll()
|
||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path)
|
log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path)
|
||||||
s.folders[f.Path] = s.newScanner(f)
|
s.folders[f.Path] = s.newScanner(f)
|
||||||
|
@ -260,7 +263,7 @@ func (s *scanner) loadFolders() {
|
||||||
active: false,
|
active: false,
|
||||||
fileCount: 0,
|
fileCount: 0,
|
||||||
folderCount: 0,
|
folderCount: 0,
|
||||||
lastUpdate: s.getLastModifiedSince(f.Path),
|
lastUpdate: s.getLastModifiedSince(ctx, f.Path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,8 @@ func (c *LibraryScanningController) GetScanStatus(w http.ResponseWriter, r *http
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||||
loggedUser, ok := request.UserFrom(r.Context())
|
ctx := r.Context()
|
||||||
|
loggedUser, ok := request.UserFrom(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, newError(responses.ErrorGeneric, "Internal error")
|
return nil, newError(responses.ErrorGeneric, "Internal error")
|
||||||
}
|
}
|
||||||
|
@ -51,9 +52,9 @@ func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Req
|
||||||
fullScan := utils.ParamBool(r, "fullScan", false)
|
fullScan := utils.ParamBool(r, "fullScan", false)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := c.scanner.RescanAll(fullScan)
|
err := c.scanner.RescanAll(ctx, fullScan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(r.Context(), err)
|
log.Error(ctx, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue