mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-05 21:47:36 +03:00
90 lines
2.8 KiB
Go
90 lines
2.8 KiB
Go
package scanner2
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
|
|
"github.com/google/go-pipeline/pkg/pipeline"
|
|
"github.com/navidrome/navidrome/log"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/scanner/metadata"
|
|
"github.com/navidrome/navidrome/utils/slice"
|
|
"golang.org/x/exp/maps"
|
|
)
|
|
|
|
const (
|
|
// filesBatchSize used for batching file metadata extraction
|
|
filesBatchSize = 100
|
|
)
|
|
|
|
func (s *scanner2) processFolder(ctx context.Context) pipeline.StageFn[*folderEntry] {
|
|
return func(entry *folderEntry) (*folderEntry, error) {
|
|
// Load children mediafiles from DB
|
|
mfs, err := entry.scanCtx.ds.MediaFile(ctx).GetByFolder(entry.id)
|
|
if err != nil {
|
|
log.Error(ctx, "Scanner: Error loading mediafiles from DB", "folder", entry.path, err)
|
|
return entry, err
|
|
}
|
|
dbTracks := slice.ToMap(mfs, func(mf model.MediaFile) (string, model.MediaFile) { return mf.Path, mf })
|
|
|
|
// Get list of files to import, leave dbTracks with tracks to be removed
|
|
var filesToImport []string
|
|
for afPath, af := range entry.audioFiles {
|
|
fullPath := filepath.Join(entry.path, afPath)
|
|
dbTrack, foundInDB := dbTracks[afPath]
|
|
if !foundInDB || entry.scanCtx.fullRescan {
|
|
filesToImport = append(filesToImport, fullPath)
|
|
} else {
|
|
info, err := af.Info()
|
|
if err != nil {
|
|
log.Warn(ctx, "Scanner: Error getting file info", "folder", entry.path, "file", af.Name(), err)
|
|
return nil, err
|
|
}
|
|
if info.ModTime().After(dbTrack.UpdatedAt) {
|
|
filesToImport = append(filesToImport, fullPath)
|
|
}
|
|
}
|
|
delete(dbTracks, afPath)
|
|
}
|
|
|
|
// Remaining dbTracks are tracks that were not found in the folder, so they should be marked as missing
|
|
entry.missingTracks = maps.Values(dbTracks)
|
|
|
|
entry.tracks, err = loadTagsFromFiles(ctx, entry, filesToImport)
|
|
if err != nil {
|
|
log.Warn(ctx, "Scanner: Error loading tags from files. Skipping", "folder", entry.path, err)
|
|
return entry, nil
|
|
}
|
|
|
|
entry.albums = loadAlbumsFromTags(ctx, entry)
|
|
entry.artists = loadArtistsFromTags(ctx, entry)
|
|
|
|
return entry, nil
|
|
}
|
|
}
|
|
|
|
func loadTagsFromFiles(ctx context.Context, entry *folderEntry, toImport []string) (model.MediaFiles, error) {
|
|
tracks := model.MediaFiles{}
|
|
mapper := newMediaFileMapper(entry)
|
|
err := slice.RangeByChunks(toImport, filesBatchSize, func(chunk []string) error {
|
|
allTags, err := metadata.Extract(toImport...)
|
|
if err != nil {
|
|
log.Warn(ctx, "Scanner: Error extracting tags from files. Skipping", "folder", entry.path, err)
|
|
return err
|
|
}
|
|
for _, tags := range allTags {
|
|
track := mapper.toMediaFile(tags)
|
|
tracks = append(tracks, track)
|
|
}
|
|
return nil
|
|
})
|
|
return tracks, err
|
|
}
|
|
|
|
func loadAlbumsFromTags(ctx context.Context, entry *folderEntry) model.Albums {
|
|
return nil // TODO
|
|
}
|
|
|
|
func loadArtistsFromTags(ctx context.Context, entry *folderEntry) model.Artists {
|
|
return nil // TODO
|
|
}
|