package scanner
import (
"context"
"sync"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
)
type imageChangedFolder struct {
id string
path string
artistImage bool
}
type imageChangeCollector struct {
libs map[int]model.Library
folders map[int][]imageChangedFolder
ds model.DataStore
mutex sync.Mutex
}
func (c *imageChangeCollector) record(lib model.Library, folder imageChangedFolder) {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.folders == nil {
c.folders = map[int][]imageChangedFolder{}
c.libs = map[int]model.Library{}
}
c.libs[lib.ID] = lib
c.folders[lib.ID] = append(c.folders[lib.ID], folder)
}
func (c *imageChangeCollector) enqueue(ctx context.Context) {
c.mutex.Lock()
foldersMap, libsMap := c.folders, c.libs
c.folders, c.libs = nil, nil
c.mutex.Unlock()
for libID, folders := range foldersMap {
lib := libsMap[libID]
items, err := c.queueItems(ctx, lib, folders)
if err != nil {
log.Warn(ctx, "Scanner: could not map image changes to artwork items", "lib", lib.Name, err)
continue
}
if len(items) == 0 {
continue
}
if err := c.ds.ArtworkQueue().Enqueue(ctx, items...); err != nil {
log.Warn(ctx, "Scanner: could not enqueue artwork for image changes", "lib", lib.Name, err)
continue
}
log.Debug(ctx, "Scanner: Enqueued artwork resolution for image changes", "lib", lib.Name,
"changedFolders", len(folders), "items", len(items))
}
}
func (c *imageChangeCollector) queueItems(ctx context.Context, lib model.Library,
folders []imageChangedFolder,
) ([]model.ArtworkQueueItem, error) {
folderIDs := make([]string, len(folders))
var artistFolderPaths []string
for i, f := range folders {
folderIDs[i] = f.id
if f.artistImage {
artistFolderPaths = append(artistFolderPaths, f.path)
}
}
var items []model.ArtworkQueueItem
albumIDs, err := c.ds.MediaFile().GetAlbumIDsByFolder(ctx, lib, folderIDs...)
if err != nil {
return nil, err
}
for _, id := range albumIDs {
items = append(items, scanArtworkItem(model.KindAlbumArtwork, id))
}
if len(artistFolderPaths) == 0 {
return items, nil
}
artistIDs, err := c.ds.Album().GetSoleAlbumArtistIDsInSubtrees(ctx, lib, artistFolderPaths...)
if err != nil {
log.Warn(ctx, "Scanner: could not map image changes to artists", "lib", lib.Name, err)
return items, nil
}
for _, id := range artistIDs {
if id == "" || id == consts.UnknownArtistID || id == consts.VariousArtistsID {
continue
}
items = append(items, scanArtworkItem(model.KindArtistArtwork, id))
}
return items, nil
}
func scanArtworkItem(kind model.Kind, id string) model.ArtworkQueueItem {
return model.ArtworkQueueItem{
ItemKind: kind.Prefix(), ItemID: id, ImageType: model.ImageTypePrimary,
Priority: model.ArtworkPriorityScan,
}
}