Clean missing galleries (#489)

* Clean missing galleries
* Refactor matchFile
This commit is contained in:
WithoutPants
2020-04-25 09:32:55 +10:00
committed by GitHub
parent 8a4d853a5d
commit 5923917e6c
5 changed files with 93 additions and 35 deletions

View File

@@ -1,9 +1,10 @@
package manager package manager
import ( import (
"github.com/stashapp/stash/pkg/logger"
"regexp" "regexp"
"strings" "strings"
"github.com/stashapp/stash/pkg/logger"
) )
func excludeFiles(files []string, patterns []string) ([]string, int) { func excludeFiles(files []string, patterns []string) ([]string, int) {
@@ -37,21 +38,13 @@ func excludeFiles(files []string, patterns []string) ([]string, int) {
} }
func matchFile(file string, patterns []string) bool { func matchFile(file string, patterns []string) bool {
if patterns == nil { if patterns != nil {
logger.Infof("No exclude patterns in config.")
} else {
fileRegexps := generateRegexps(patterns) fileRegexps := generateRegexps(patterns)
if len(fileRegexps) == 0 {
return false
}
for _, regPattern := range fileRegexps { for _, regPattern := range fileRegexps {
if regPattern.MatchString(strings.ToLower(file)) { if regPattern.MatchString(strings.ToLower(file)) {
return true return true
} }
} }
} }

View File

@@ -1,15 +1,16 @@
package manager package manager
import ( import (
"path/filepath"
"strconv"
"sync"
"time"
"github.com/bmatcuk/doublestar" "github.com/bmatcuk/doublestar"
"github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils" "github.com/stashapp/stash/pkg/utils"
"path/filepath"
"strconv"
"sync"
"time"
) )
var extensionsToScan = []string{"zip", "m4v", "mp4", "mov", "wmv", "avi", "mpg", "mpeg", "rmvb", "rm", "flv", "asf", "mkv", "webm"} var extensionsToScan = []string{"zip", "m4v", "mp4", "mov", "wmv", "avi", "mpg", "mpeg", "rmvb", "rm", "flv", "asf", "mkv", "webm"}
@@ -474,6 +475,7 @@ func (s *singleton) Clean() {
s.Status.indefiniteProgress() s.Status.indefiniteProgress()
qb := models.NewSceneQueryBuilder() qb := models.NewSceneQueryBuilder()
gqb := models.NewGalleryQueryBuilder()
go func() { go func() {
defer s.returnToIdleState() defer s.returnToIdleState()
@@ -484,6 +486,12 @@ func (s *singleton) Clean() {
return return
} }
galleries, err := gqb.All()
if err != nil {
logger.Errorf("failed to fetch list of galleries for cleaning")
return
}
if s.Status.stopping { if s.Status.stopping {
logger.Info("Stopping due to user request") logger.Info("Stopping due to user request")
return return
@@ -491,7 +499,7 @@ func (s *singleton) Clean() {
var wg sync.WaitGroup var wg sync.WaitGroup
s.Status.Progress = 0 s.Status.Progress = 0
total := len(scenes) total := len(scenes) + len(galleries)
for i, scene := range scenes { for i, scene := range scenes {
s.Status.setProgress(i, total) s.Status.setProgress(i, total)
if s.Status.stopping { if s.Status.stopping {
@@ -506,7 +514,26 @@ func (s *singleton) Clean() {
wg.Add(1) wg.Add(1)
task := CleanTask{Scene: *scene} task := CleanTask{Scene: scene}
go task.Start(&wg)
wg.Wait()
}
for i, gallery := range galleries {
s.Status.setProgress(len(scenes)+i, total)
if s.Status.stopping {
logger.Info("Stopping due to user request")
return
}
if gallery == nil {
logger.Errorf("nil gallery, skipping Clean")
continue
}
wg.Add(1)
task := CleanTask{Gallery: gallery}
go task.Start(&wg) go task.Start(&wg)
wg.Wait() wg.Wait()
} }

View File

@@ -2,33 +2,47 @@ package manager
import ( import (
"context" "context"
"github.com/stashapp/stash/pkg/database"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
"github.com/stashapp/stash/pkg/database"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models"
) )
type CleanTask struct { type CleanTask struct {
Scene models.Scene Scene *models.Scene
Gallery *models.Gallery
} }
func (t *CleanTask) Start(wg *sync.WaitGroup) { func (t *CleanTask) Start(wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
if t.fileExists(t.Scene.Path) && t.pathInStash() { if t.Scene != nil && t.shouldClean(t.Scene.Path) {
logger.Debugf("File Found: %s", t.Scene.Path)
if matchFile(t.Scene.Path, config.GetExcludes()) {
logger.Infof("File matched regex. Cleaning: \"%s\"", t.Scene.Path)
t.deleteScene(t.Scene.ID) t.deleteScene(t.Scene.ID)
} }
if t.Gallery != nil && t.shouldClean(t.Gallery.Path) {
t.deleteGallery(t.Gallery.ID)
}
}
func (t *CleanTask) shouldClean(path string) bool {
if t.fileExists(path) && t.pathInStash(path) {
logger.Debugf("File Found: %s", path)
if matchFile(path, config.GetExcludes()) {
logger.Infof("File matched regex. Cleaning: \"%s\"", path)
return true
}
} else { } else {
logger.Infof("File not found. Cleaning: \"%s\"", t.Scene.Path) logger.Infof("File not found. Cleaning: \"%s\"", path)
t.deleteScene(t.Scene.ID) return true
} }
return false
} }
func (t *CleanTask) deleteScene(sceneID int) { func (t *CleanTask) deleteScene(sceneID int) {
@@ -53,6 +67,25 @@ func (t *CleanTask) deleteScene(sceneID int) {
DeleteGeneratedSceneFiles(scene) DeleteGeneratedSceneFiles(scene)
} }
func (t *CleanTask) deleteGallery(galleryID int) {
ctx := context.TODO()
qb := models.NewGalleryQueryBuilder()
tx := database.DB.MustBeginTx(ctx, nil)
err := qb.Destroy(galleryID, tx)
if err != nil {
logger.Infof("Error deleting gallery from database: %s", err.Error())
tx.Rollback()
return
}
if err := tx.Commit(); err != nil {
logger.Infof("Error deleting gallery from database: %s", err.Error())
return
}
}
func (t *CleanTask) fileExists(filename string) bool { func (t *CleanTask) fileExists(filename string) bool {
info, err := os.Stat(filename) info, err := os.Stat(filename)
if os.IsNotExist(err) { if os.IsNotExist(err) {
@@ -61,19 +94,19 @@ func (t *CleanTask) fileExists(filename string) bool {
return !info.IsDir() return !info.IsDir()
} }
func (t *CleanTask) pathInStash() bool { func (t *CleanTask) pathInStash(pathToCheck string) bool {
for _, path := range config.GetStashPaths() { for _, path := range config.GetStashPaths() {
rel, error := filepath.Rel(path, filepath.Dir(t.Scene.Path)) rel, error := filepath.Rel(path, filepath.Dir(pathToCheck))
if error == nil { if error == nil {
if !strings.HasPrefix(rel, ".."+string(filepath.Separator)) { if !strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
logger.Debugf("File %s belongs to stash path %s", t.Scene.Path, path) logger.Debugf("File %s belongs to stash path %s", pathToCheck, path)
return true return true
} }
} }
} }
logger.Debugf("File %s is out from stash path", t.Scene.Path) logger.Debugf("File %s is out from stash path", pathToCheck)
return false return false
} }

View File

@@ -3,6 +3,7 @@ package models
import ( import (
"database/sql" "database/sql"
"path/filepath" "path/filepath"
"strconv"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/database" "github.com/stashapp/stash/pkg/database"
@@ -51,6 +52,10 @@ func (qb *GalleryQueryBuilder) Update(updatedGallery Gallery, tx *sqlx.Tx) (*Gal
return &updatedGallery, nil return &updatedGallery, nil
} }
func (qb *GalleryQueryBuilder) Destroy(id int, tx *sqlx.Tx) error {
return executeDeleteQuery("galleries", strconv.Itoa(id), tx)
}
type GalleryNullSceneID struct { type GalleryNullSceneID struct {
SceneID sql.NullInt64 SceneID sql.NullInt64
} }

View File

@@ -105,8 +105,8 @@ export const SettingsTasksPanel: React.FC = () => {
cancel={{ onClick: () => setIsCleanAlertOpen(false) }} cancel={{ onClick: () => setIsCleanAlertOpen(false) }}
> >
<p> <p>
Are you sure you want to Clean? This will delete db information and Are you sure you want to Clean? This will delete database information and
generated content for all scenes that are no longer found in the generated content for all scenes and galleries that are no longer found in the
filesystem. filesystem.
</p> </p>
</Modal> </Modal>