update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
This commit is contained in:
130
scanner/phase_4_playlists.go
Normal file
130
scanner/phase_4_playlists.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
ppl "github.com/google/go-pipeline/pkg/pipeline"
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/core"
|
||||
"github.com/navidrome/navidrome/core/artwork"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
)
|
||||
|
||||
type phasePlaylists struct {
|
||||
ctx context.Context
|
||||
scanState *scanState
|
||||
ds model.DataStore
|
||||
pls core.Playlists
|
||||
cw artwork.CacheWarmer
|
||||
refreshed atomic.Uint32
|
||||
}
|
||||
|
||||
func createPhasePlaylists(ctx context.Context, scanState *scanState, ds model.DataStore, pls core.Playlists, cw artwork.CacheWarmer) *phasePlaylists {
|
||||
return &phasePlaylists{
|
||||
ctx: ctx,
|
||||
scanState: scanState,
|
||||
ds: ds,
|
||||
pls: pls,
|
||||
cw: cw,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *phasePlaylists) description() string {
|
||||
return "Import/update playlists"
|
||||
}
|
||||
|
||||
func (p *phasePlaylists) producer() ppl.Producer[*model.Folder] {
|
||||
return ppl.NewProducer(p.produce, ppl.Name("load folders with playlists from db"))
|
||||
}
|
||||
|
||||
func (p *phasePlaylists) produce(put func(entry *model.Folder)) error {
|
||||
if !conf.Server.AutoImportPlaylists {
|
||||
log.Info(p.ctx, "Playlists will not be imported, AutoImportPlaylists is set to false")
|
||||
return nil
|
||||
}
|
||||
u, _ := request.UserFrom(p.ctx)
|
||||
if !u.IsAdmin {
|
||||
log.Warn(p.ctx, "Playlists will not be imported, as there are no admin users yet, "+
|
||||
"Please create an admin user first, and then update the playlists for them to be imported")
|
||||
return nil
|
||||
}
|
||||
|
||||
count := 0
|
||||
cursor, err := p.ds.Folder(p.ctx).GetTouchedWithPlaylists()
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading touched folders: %w", err)
|
||||
}
|
||||
log.Debug(p.ctx, "Scanner: Checking playlists that may need refresh")
|
||||
for folder, err := range cursor {
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading touched folder: %w", err)
|
||||
}
|
||||
count++
|
||||
put(&folder)
|
||||
}
|
||||
if count == 0 {
|
||||
log.Debug(p.ctx, "Scanner: No playlists need refreshing")
|
||||
} else {
|
||||
log.Debug(p.ctx, "Scanner: Found folders with playlists that may need refreshing", "count", count)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *phasePlaylists) stages() []ppl.Stage[*model.Folder] {
|
||||
return []ppl.Stage[*model.Folder]{
|
||||
ppl.NewStage(p.processPlaylistsInFolder, ppl.Name("process playlists in folder"), ppl.Concurrency(3)),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *phasePlaylists) processPlaylistsInFolder(folder *model.Folder) (*model.Folder, error) {
|
||||
files, err := os.ReadDir(folder.AbsolutePath())
|
||||
if err != nil {
|
||||
log.Error(p.ctx, "Scanner: Error reading files", "folder", folder, err)
|
||||
p.scanState.sendWarning(err.Error())
|
||||
return folder, nil
|
||||
}
|
||||
for _, f := range files {
|
||||
started := time.Now()
|
||||
if strings.HasPrefix(f.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
if !model.IsValidPlaylist(f.Name()) {
|
||||
continue
|
||||
}
|
||||
// BFR: Check if playlist needs to be refreshed (timestamp, sync flag, etc)
|
||||
pls, err := p.pls.ImportFile(p.ctx, folder, f.Name())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if pls.IsSmartPlaylist() {
|
||||
log.Debug("Scanner: Imported smart playlist", "name", pls.Name, "lastUpdated", pls.UpdatedAt, "path", pls.Path, "elapsed", time.Since(started))
|
||||
} else {
|
||||
log.Debug("Scanner: Imported playlist", "name", pls.Name, "lastUpdated", pls.UpdatedAt, "path", pls.Path, "numTracks", len(pls.Tracks), "elapsed", time.Since(started))
|
||||
}
|
||||
p.cw.PreCache(pls.CoverArtID())
|
||||
p.refreshed.Add(1)
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
func (p *phasePlaylists) finalize(err error) error {
|
||||
refreshed := p.refreshed.Load()
|
||||
logF := log.Info
|
||||
if refreshed == 0 {
|
||||
logF = log.Debug
|
||||
} else {
|
||||
p.scanState.changesDetected.Store(true)
|
||||
}
|
||||
logF(p.ctx, "Scanner: Finished refreshing playlists", "refreshed", refreshed, err)
|
||||
return err
|
||||
}
|
||||
|
||||
var _ phase[*model.Folder] = (*phasePlaylists)(nil)
|
||||
Reference in New Issue
Block a user