Clean missing captions during scan (#3240)

This commit is contained in:
WithoutPants 2022-12-06 12:04:40 +11:00 committed by GitHub
parent b5b9023b3e
commit dc875ed5d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 20 deletions

View file

@ -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,

View file

@ -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
}

View file

@ -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 {

View file

@ -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))