mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Clean missing captions during scan (#3240)
This commit is contained in:
parent
b5b9023b3e
commit
dc875ed5d7
4 changed files with 82 additions and 20 deletions
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/scene"
|
||||
"github.com/stashapp/stash/pkg/scene/generate"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
)
|
||||
|
||||
type scanner interface {
|
||||
|
|
@ -111,9 +112,11 @@ type sceneFinder interface {
|
|||
// handlerRequiredFilter returns true if a File's handler needs to be executed despite the file not being updated.
|
||||
type handlerRequiredFilter struct {
|
||||
extensionConfig
|
||||
txnManager txn.Manager
|
||||
SceneFinder sceneFinder
|
||||
ImageFinder fileCounter
|
||||
GalleryFinder galleryFinder
|
||||
CaptionUpdater video.CaptionUpdater
|
||||
|
||||
FolderCache *lru.LRU
|
||||
|
||||
|
|
@ -126,9 +129,11 @@ func newHandlerRequiredFilter(c *config.Instance) *handlerRequiredFilter {
|
|||
|
||||
return &handlerRequiredFilter{
|
||||
extensionConfig: newExtensionConfig(c),
|
||||
txnManager: db,
|
||||
SceneFinder: db.Scene,
|
||||
ImageFinder: db.Image,
|
||||
GalleryFinder: db.Gallery,
|
||||
CaptionUpdater: db.File,
|
||||
FolderCache: lru.New(processes * 2),
|
||||
videoFileNamingAlgorithm: c.GetVideoFileNamingAlgorithm(),
|
||||
}
|
||||
|
|
@ -205,6 +210,15 @@ func (f *handlerRequiredFilter) Accept(ctx context.Context, ff file.File) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// clean captions - scene handler handles this as well, but
|
||||
// unchanged files aren't processed by the scene handler
|
||||
videoFile, _ := ff.(*file.VideoFile)
|
||||
if videoFile != nil {
|
||||
if err := video.CleanCaptions(ctx, videoFile, f.txnManager, f.CaptionUpdater); err != nil {
|
||||
logger.Errorf("Error cleaning captions: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
|
|
@ -329,6 +343,7 @@ func getScanHandlers(options ScanMetadataInput, taskQueue *job.TaskQueue, progre
|
|||
Handler: &scene.ScanHandler{
|
||||
CreatorUpdater: db.Scene,
|
||||
PluginCache: pluginCache,
|
||||
CaptionUpdater: db.File,
|
||||
CoverGenerator: &coverGenerator{},
|
||||
ScanGenerator: &sceneGenerators{
|
||||
input: options,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package video
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -59,23 +60,6 @@ func IsLangInCaptions(lang string, ext string, captions []*models.VideoCaption)
|
|||
return false
|
||||
}
|
||||
|
||||
// CleanCaptions removes non existent/accessible language codes from captions
|
||||
func CleanCaptions(scenePath string, captions []*models.VideoCaption) (cleanedCaptions []*models.VideoCaption, changed bool) {
|
||||
changed = false
|
||||
for _, caption := range captions {
|
||||
found := false
|
||||
f := caption.Path(scenePath)
|
||||
if _, er := os.Stat(f); er == nil {
|
||||
cleanedCaptions = append(cleanedCaptions, caption)
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getCaptionPrefix returns the prefix used to search for video files for the provided caption path
|
||||
func getCaptionPrefix(captionPath string) string {
|
||||
basename := strings.TrimSuffix(captionPath, filepath.Ext(captionPath)) // caption filename without the extension
|
||||
|
|
@ -148,3 +132,52 @@ func AssociateCaptions(ctx context.Context, captionPath string, txnMgr txn.Manag
|
|||
logger.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// CleanCaptions removes non existent/accessible language codes from captions
|
||||
func CleanCaptions(ctx context.Context, f *file.VideoFile, txnMgr txn.Manager, w CaptionUpdater) error {
|
||||
captions, err := w.GetCaptions(ctx, f.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting captions for file %s: %w", f.Path, err)
|
||||
}
|
||||
|
||||
if len(captions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
filePath := f.Path
|
||||
|
||||
changed := false
|
||||
var newCaptions []*models.VideoCaption
|
||||
|
||||
for _, caption := range captions {
|
||||
captionPath := caption.Path(filePath)
|
||||
_, err := os.Stat(captionPath)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
logger.Infof("Removing non existent caption %s for %s", caption.Filename, f.Path)
|
||||
changed = true
|
||||
} else {
|
||||
// other errors are ignored for the purposes of cleaning
|
||||
newCaptions = append(newCaptions, caption)
|
||||
}
|
||||
}
|
||||
|
||||
if changed {
|
||||
fn := func(ctx context.Context) error {
|
||||
return w.UpdateCaptions(ctx, f.ID, newCaptions)
|
||||
}
|
||||
|
||||
// possible that we are already in a transaction and txnMgr is nil
|
||||
// in that case just call the function directly
|
||||
if txnMgr == nil {
|
||||
err = fn(ctx)
|
||||
} else {
|
||||
err = txn.WithTxn(ctx, txnMgr, fn)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("updating captions for file %s: %w", f.Path, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/file"
|
||||
"github.com/stashapp/stash/pkg/file/video"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/models/paths"
|
||||
|
|
@ -36,6 +37,7 @@ type ScanHandler struct {
|
|||
|
||||
CoverGenerator CoverGenerator
|
||||
ScanGenerator ScanGenerator
|
||||
CaptionUpdater video.CaptionUpdater
|
||||
PluginCache *plugin.Cache
|
||||
|
||||
FileNamingAlgorithm models.HashAlgorithm
|
||||
|
|
@ -52,6 +54,9 @@ func (h *ScanHandler) validate() error {
|
|||
if h.ScanGenerator == nil {
|
||||
return errors.New("ScanGenerator is required")
|
||||
}
|
||||
if h.CaptionUpdater == nil {
|
||||
return errors.New("CaptionUpdater is required")
|
||||
}
|
||||
if !h.FileNamingAlgorithm.IsValid() {
|
||||
return errors.New("FileNamingAlgorithm is required")
|
||||
}
|
||||
|
|
@ -72,6 +77,12 @@ func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File
|
|||
return ErrNotVideoFile
|
||||
}
|
||||
|
||||
if oldFile != nil {
|
||||
if err := video.CleanCaptions(ctx, videoFile, nil, h.CaptionUpdater); err != nil {
|
||||
return fmt.Errorf("cleaning captions: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// try to match the file to a scene
|
||||
existing, err := h.CreatorUpdater.FindByFileID(ctx, f.Base().ID)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -7,3 +7,6 @@
|
|||
|
||||
### 🎨 Improvements
|
||||
* Changed performer aliases to be a list, rather than a string field. ([#3113](https://github.com/stashapp/stash/pull/3113))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fixed missing captions not being removed during scan. ([#3240](https://github.com/stashapp/stash/pull/3240))
|
||||
Loading…
Reference in a new issue