diff --git a/graphql/schema/types/metadata.graphql b/graphql/schema/types/metadata.graphql index 983d0db5f..3221b0cc6 100644 --- a/graphql/schema/types/metadata.graphql +++ b/graphql/schema/types/metadata.graphql @@ -75,6 +75,8 @@ input ScanMetaDataFilterInput { input ScanMetadataInput { paths: [String!] + "Forces a rescan on files even if modification time is unchanged" + rescan: Boolean "Generate covers during scan" scanGenerateCovers: Boolean "Generate previews during scan" @@ -95,6 +97,8 @@ input ScanMetadataInput { } type ScanMetadataOptions { + "Forces a rescan on files even if modification time is unchanged" + rescan: Boolean! "Generate covers during scan" scanGenerateCovers: Boolean! "Generate previews during scan" diff --git a/internal/manager/config/tasks.go b/internal/manager/config/tasks.go index a92c11e85..0cfabef30 100644 --- a/internal/manager/config/tasks.go +++ b/internal/manager/config/tasks.go @@ -1,6 +1,8 @@ package config type ScanMetadataOptions struct { + // Forces a rescan on files even if they have not changed + Rescan bool `json:"rescan"` // Generate scene covers during scan ScanGenerateCovers bool `json:"scanGenerateCovers"` // Generate previews during scan diff --git a/internal/manager/task_scan.go b/internal/manager/task_scan.go index 9f9fa66a2..48a06d098 100644 --- a/internal/manager/task_scan.go +++ b/internal/manager/task_scan.go @@ -35,6 +35,7 @@ type ScanJob struct { } func (j *ScanJob) Execute(ctx context.Context, progress *job.Progress) error { + cfg := config.GetInstance() input := j.input if job.IsCancelled(ctx) { @@ -55,7 +56,7 @@ func (j *ScanJob) Execute(ctx context.Context, progress *job.Progress) error { start := time.Now() const taskQueueSize = 200000 - taskQueue := job.NewTaskQueue(ctx, progress, taskQueueSize, c.GetParallelTasksWithAutoDetection()) + taskQueue := job.NewTaskQueue(ctx, progress, taskQueueSize, cfg.GetParallelTasksWithAutoDetection()) var minModTime time.Time if j.input.Filter != nil && j.input.Filter.MinModTime != nil { @@ -65,9 +66,10 @@ func (j *ScanJob) Execute(ctx context.Context, progress *job.Progress) error { j.scanner.Scan(ctx, getScanHandlers(j.input, taskQueue, progress), file.ScanOptions{ Paths: paths, ScanFilters: []file.PathFilter{newScanFilter(c, repo, minModTime)}, - ZipFileExtensions: c.GetGalleryExtensions(), - ParallelTasks: c.GetParallelTasksWithAutoDetection(), - HandlerRequiredFilters: []file.Filter{newHandlerRequiredFilter(c, repo)}, + ZipFileExtensions: cfg.GetGalleryExtensions(), + ParallelTasks: cfg.GetParallelTasksWithAutoDetection(), + HandlerRequiredFilters: []file.Filter{newHandlerRequiredFilter(cfg, repo)}, + Rescan: j.input.Rescan, }, progress) taskQueue.Close() diff --git a/pkg/file/scan.go b/pkg/file/scan.go index 7cd6d5aab..fac493080 100644 --- a/pkg/file/scan.go +++ b/pkg/file/scan.go @@ -134,6 +134,9 @@ type ScanOptions struct { HandlerRequiredFilters []Filter ParallelTasks int + + // When true files in path will be rescanned even if they haven't changed + Rescan bool } // Scan starts the scanning process. @@ -1023,14 +1026,20 @@ func (s *scanJob) onExistingFile(ctx context.Context, f scanFile, existing model fileModTime := f.ModTime updated := !fileModTime.Equal(base.ModTime) + forceRescan := s.options.Rescan - if !updated { + if !updated && !forceRescan { return s.onUnchangedFile(ctx, f, existing) } oldBase := *base - logger.Infof("%s has been updated: rescanning", path) + if !updated && forceRescan { + logger.Infof("rescanning %s", path) + } else { + logger.Infof("%s has been updated: rescanning", path) + } + base.ModTime = fileModTime base.Size = f.Size base.UpdatedAt = time.Now() diff --git a/ui/v2.5/graphql/data/config.graphql b/ui/v2.5/graphql/data/config.graphql index 7286dd0b5..ae15aa939 100644 --- a/ui/v2.5/graphql/data/config.graphql +++ b/ui/v2.5/graphql/data/config.graphql @@ -151,6 +151,7 @@ fragment ScraperSourceData on ScraperSource { fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult { scan { + # don't get rescan - it should never be defaulted to true scanGenerateCovers scanGeneratePreviews scanGenerateImagePreviews