mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Files refactor fixes (#2743)
* Fix destroy gallery not destroying file * Re-add minModTime functionality * Deprecate useFileMetadata and stripFileExtension * Optimise files post migration * Decorate moved files. Use first missing file in move * Include path in thumbnail generation error log * Fix stash-box draft submission * Don't destroy files unless deleting * Call handler for files with no associated objects * Fix moved zips causing error on scan
This commit is contained in:
@@ -51,11 +51,17 @@ func (j *ScanJob) Execute(ctx context.Context, progress *job.Progress) {
|
||||
const taskQueueSize = 200000
|
||||
taskQueue := job.NewTaskQueue(ctx, progress, taskQueueSize, instance.Config.GetParallelTasksWithAutoDetection())
|
||||
|
||||
var minModTime time.Time
|
||||
if j.input.Filter != nil && j.input.Filter.MinModTime != nil {
|
||||
minModTime = *j.input.Filter.MinModTime
|
||||
}
|
||||
|
||||
j.scanner.Scan(ctx, getScanHandlers(j.input, taskQueue, progress), file.ScanOptions{
|
||||
Paths: paths,
|
||||
ScanFilters: []file.PathFilter{newScanFilter(instance.Config)},
|
||||
ZipFileExtensions: instance.Config.GetGalleryExtensions(),
|
||||
ParallelTasks: instance.Config.GetParallelTasksWithAutoDetection(),
|
||||
Paths: paths,
|
||||
ScanFilters: []file.PathFilter{newScanFilter(instance.Config, minModTime)},
|
||||
ZipFileExtensions: instance.Config.GetGalleryExtensions(),
|
||||
ParallelTasks: instance.Config.GetParallelTasksWithAutoDetection(),
|
||||
HandlerRequiredFilters: []file.Filter{newHandlerRequiredFilter(instance.Config)},
|
||||
}, progress)
|
||||
|
||||
taskQueue.Close()
|
||||
@@ -71,25 +77,92 @@ func (j *ScanJob) Execute(ctx context.Context, progress *job.Progress) {
|
||||
j.subscriptions.notify()
|
||||
}
|
||||
|
||||
type scanFilter struct {
|
||||
stashPaths []*config.StashConfig
|
||||
generatedPath string
|
||||
vidExt []string
|
||||
imgExt []string
|
||||
zipExt []string
|
||||
videoExcludeRegex []*regexp.Regexp
|
||||
imageExcludeRegex []*regexp.Regexp
|
||||
type extensionConfig struct {
|
||||
vidExt []string
|
||||
imgExt []string
|
||||
zipExt []string
|
||||
}
|
||||
|
||||
func newScanFilter(c *config.Instance) *scanFilter {
|
||||
func newExtensionConfig(c *config.Instance) extensionConfig {
|
||||
return extensionConfig{
|
||||
vidExt: c.GetVideoExtensions(),
|
||||
imgExt: c.GetImageExtensions(),
|
||||
zipExt: c.GetGalleryExtensions(),
|
||||
}
|
||||
}
|
||||
|
||||
type fileCounter interface {
|
||||
CountByFileID(ctx context.Context, fileID file.ID) (int, error)
|
||||
}
|
||||
|
||||
// handlerRequiredFilter returns true if a File's handler needs to be executed despite the file not being updated.
|
||||
type handlerRequiredFilter struct {
|
||||
extensionConfig
|
||||
SceneFinder fileCounter
|
||||
ImageFinder fileCounter
|
||||
GalleryFinder fileCounter
|
||||
}
|
||||
|
||||
func newHandlerRequiredFilter(c *config.Instance) *handlerRequiredFilter {
|
||||
db := instance.Database
|
||||
|
||||
return &handlerRequiredFilter{
|
||||
extensionConfig: newExtensionConfig(c),
|
||||
SceneFinder: db.Scene,
|
||||
ImageFinder: db.Image,
|
||||
GalleryFinder: db.Gallery,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *handlerRequiredFilter) Accept(ctx context.Context, ff file.File) bool {
|
||||
path := ff.Base().Path
|
||||
isVideoFile := fsutil.MatchExtension(path, f.vidExt)
|
||||
isImageFile := fsutil.MatchExtension(path, f.imgExt)
|
||||
isZipFile := fsutil.MatchExtension(path, f.zipExt)
|
||||
|
||||
var counter fileCounter
|
||||
|
||||
switch {
|
||||
case isVideoFile:
|
||||
// return true if there are no scenes associated
|
||||
counter = f.SceneFinder
|
||||
case isImageFile:
|
||||
counter = f.ImageFinder
|
||||
case isZipFile:
|
||||
counter = f.GalleryFinder
|
||||
}
|
||||
|
||||
if counter == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
n, err := counter.CountByFileID(ctx, ff.Base().ID)
|
||||
if err != nil {
|
||||
// just ignore
|
||||
return false
|
||||
}
|
||||
|
||||
// execute handler if there are no related objects
|
||||
return n == 0
|
||||
}
|
||||
|
||||
type scanFilter struct {
|
||||
extensionConfig
|
||||
stashPaths []*config.StashConfig
|
||||
generatedPath string
|
||||
videoExcludeRegex []*regexp.Regexp
|
||||
imageExcludeRegex []*regexp.Regexp
|
||||
minModTime time.Time
|
||||
}
|
||||
|
||||
func newScanFilter(c *config.Instance, minModTime time.Time) *scanFilter {
|
||||
return &scanFilter{
|
||||
extensionConfig: newExtensionConfig(c),
|
||||
stashPaths: c.GetStashPaths(),
|
||||
generatedPath: c.GetGeneratedPath(),
|
||||
vidExt: c.GetVideoExtensions(),
|
||||
imgExt: c.GetImageExtensions(),
|
||||
zipExt: c.GetGalleryExtensions(),
|
||||
videoExcludeRegex: generateRegexps(c.GetExcludes()),
|
||||
imageExcludeRegex: generateRegexps(c.GetImageExcludes()),
|
||||
minModTime: minModTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +171,11 @@ func (f *scanFilter) Accept(ctx context.Context, path string, info fs.FileInfo)
|
||||
return false
|
||||
}
|
||||
|
||||
// exit early on cutoff
|
||||
if info.Mode().IsRegular() && info.ModTime().Before(f.minModTime) {
|
||||
return false
|
||||
}
|
||||
|
||||
isVideoFile := fsutil.MatchExtension(path, f.vidExt)
|
||||
isImageFile := fsutil.MatchExtension(path, f.imgExt)
|
||||
isZipFile := fsutil.MatchExtension(path, f.zipExt)
|
||||
|
||||
Reference in New Issue
Block a user