feat: the library's folders are set in Admin › Library, and changing a folder moves its tracks with it, keeping their plays, likes and playlists (#6129)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m20s
release / go (push) Failing after 1m37s
release / integration (push) Failing after 4m56s
release / android (push) Successful in 5m1s
release / Build signed APK (releases and dev) (push) Successful in 5m13s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m20s
release / go (push) Failing after 1m37s
release / integration (push) Failing after 4m56s
release / android (push) Successful in 5m1s
release / Build signed APK (releases and dev) (push) Successful in 5m13s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,18 +67,16 @@ type Watcher struct {
|
||||
scanner *Scanner
|
||||
enricher *coverart.Enricher
|
||||
logger *slog.Logger
|
||||
roots []string
|
||||
debounce time.Duration
|
||||
}
|
||||
|
||||
func NewWatcher(
|
||||
scanner *Scanner, enricher *coverart.Enricher, logger *slog.Logger, roots []string,
|
||||
) *Watcher {
|
||||
// NewWatcher watches the scanner's folders, and moves to the new ones when
|
||||
// they change in Settings (#6129).
|
||||
func NewWatcher(scanner *Scanner, enricher *coverart.Enricher, logger *slog.Logger) *Watcher {
|
||||
return &Watcher{
|
||||
scanner: scanner,
|
||||
enricher: enricher,
|
||||
logger: logger,
|
||||
roots: roots,
|
||||
debounce: watcherDebounce,
|
||||
}
|
||||
}
|
||||
@@ -87,8 +85,32 @@ func NewWatcher(
|
||||
// fsnotify watcher cannot be created at all; per-path watch failures and
|
||||
// fsnotify errors are logged and tolerated.
|
||||
func (w *Watcher) Run(ctx context.Context) error {
|
||||
if len(w.roots) == 0 {
|
||||
w.logger.Info("library watcher: no scan paths configured, watcher disabled")
|
||||
for {
|
||||
if err := w.watch(ctx, w.scanner.Roots()); err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// watch watches roots until ctx is cancelled or the folders change.
|
||||
func (w *Watcher) watch(ctx context.Context, roots []string) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
go func() {
|
||||
select {
|
||||
case <-w.scanner.RootsChanged():
|
||||
w.logger.Info("library watcher: folders changed, restarting")
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
|
||||
if len(roots) == 0 {
|
||||
w.logger.Info("library watcher: no scan paths configured, watcher idle")
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
||||
fsw, err := fsnotify.NewWatcher()
|
||||
@@ -98,10 +120,10 @@ func (w *Watcher) Run(ctx context.Context) error {
|
||||
}
|
||||
defer func() { _ = fsw.Close() }()
|
||||
|
||||
for _, root := range w.roots {
|
||||
for _, root := range roots {
|
||||
w.addRecursive(fsw, root)
|
||||
}
|
||||
w.logger.Info("library watcher: started", "roots", len(w.roots))
|
||||
w.logger.Info("library watcher: started", "roots", len(roots))
|
||||
|
||||
batches := make(chan []string, batchQueueDepth)
|
||||
go w.processLoop(ctx, batches)
|
||||
|
||||
Reference in New Issue
Block a user