mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 16:34:02 +01:00
[Files Refactor] Bug fixes (#2868)
* Return error if multiple rows returned for id * Add missing LoadFiles calls * Show id if path is empty
This commit is contained in:
parent
273cf0383d
commit
94d39da706
23 changed files with 93 additions and 26 deletions
|
|
@ -338,10 +338,6 @@ func (r *mutationResolver) GalleryDestroy(ctx context.Context, input models.Gall
|
|||
return fmt.Errorf("gallery with id %d not found", id)
|
||||
}
|
||||
|
||||
if err := gallery.LoadFiles(ctx, qb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
galleries = append(galleries, gallery)
|
||||
|
||||
imgsDestroyed, err = r.galleryService.Destroy(ctx, gallery, fileDeleter, deleteGenerated, deleteFile)
|
||||
|
|
|
|||
|
|
@ -58,10 +58,6 @@ func (r *mutationResolver) SubmitStashBoxSceneDraft(ctx context.Context, input S
|
|||
return err
|
||||
}
|
||||
|
||||
if err := scene.LoadStashIDs(ctx, qb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filepath := manager.GetInstance().Paths.Scene.GetScreenshotPath(scene.GetHash(config.GetInstance().GetVideoFileNamingAlgorithm()))
|
||||
|
||||
res, err = client.SubmitSceneDraft(ctx, scene, boxes[input.StashBoxIndex].Endpoint, filepath)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func getGalleryFileTagger(s *models.Gallery, cache *match.Cache) tagger {
|
|||
return tagger{
|
||||
ID: s.ID,
|
||||
Type: "gallery",
|
||||
Name: s.GetTitle(),
|
||||
Name: s.DisplayName(),
|
||||
Path: path,
|
||||
trimExt: trimExt,
|
||||
cache: cache,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func getImageFileTagger(s *models.Image, cache *match.Cache) tagger {
|
|||
return tagger{
|
||||
ID: s.ID,
|
||||
Type: "image",
|
||||
Name: s.GetTitle(),
|
||||
Name: s.DisplayName(),
|
||||
Path: s.Path,
|
||||
cache: cache,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func getSceneFileTagger(s *models.Scene, cache *match.Cache) tagger {
|
|||
return tagger{
|
||||
ID: s.ID,
|
||||
Type: "scene",
|
||||
Name: s.GetTitle(),
|
||||
Name: s.DisplayName(),
|
||||
Path: s.Path,
|
||||
cache: cache,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,11 +121,11 @@ func (t *tagger) tagScenes(ctx context.Context, paths []string, sceneReader scen
|
|||
added, err := addFunc(p)
|
||||
|
||||
if err != nil {
|
||||
return t.addError("scene", p.GetTitle(), err)
|
||||
return t.addError("scene", p.DisplayName(), err)
|
||||
}
|
||||
|
||||
if added {
|
||||
t.addLog("scene", p.GetTitle())
|
||||
t.addLog("scene", p.DisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -142,11 +142,11 @@ func (t *tagger) tagImages(ctx context.Context, paths []string, imageReader imag
|
|||
added, err := addFunc(p)
|
||||
|
||||
if err != nil {
|
||||
return t.addError("image", p.GetTitle(), err)
|
||||
return t.addError("image", p.DisplayName(), err)
|
||||
}
|
||||
|
||||
if added {
|
||||
t.addLog("image", p.GetTitle())
|
||||
t.addLog("image", p.DisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,11 +163,11 @@ func (t *tagger) tagGalleries(ctx context.Context, paths []string, galleryReader
|
|||
added, err := addFunc(p)
|
||||
|
||||
if err != nil {
|
||||
return t.addError("gallery", p.GetTitle(), err)
|
||||
return t.addError("gallery", p.DisplayName(), err)
|
||||
}
|
||||
|
||||
if added {
|
||||
t.addLog("gallery", p.GetTitle())
|
||||
t.addLog("gallery", p.DisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ func (h *cleanHandler) deleteRelatedScenes(ctx context.Context, fileDeleter *fil
|
|||
|
||||
// only delete if the scene has no other files
|
||||
if len(scene.Files.List()) <= 1 {
|
||||
logger.Infof("Deleting scene %q since it has no other related files", scene.GetTitle())
|
||||
logger.Infof("Deleting scene %q since it has no other related files", scene.DisplayName())
|
||||
if err := mgr.SceneService.Destroy(ctx, scene, sceneFileDeleter, true, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -246,7 +246,7 @@ func (h *cleanHandler) deleteRelatedGalleries(ctx context.Context, fileID file.I
|
|||
|
||||
// only delete if the gallery has no other files
|
||||
if len(g.Files.List()) <= 1 {
|
||||
logger.Infof("Deleting gallery %q since it has no other related files", g.GetTitle())
|
||||
logger.Infof("Deleting gallery %q since it has no other related files", g.DisplayName())
|
||||
if err := qb.Destroy(ctx, g.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -270,7 +270,7 @@ func (h *cleanHandler) deleteRelatedFolderGalleries(ctx context.Context, folderI
|
|||
}
|
||||
|
||||
for _, g := range galleries {
|
||||
logger.Infof("Deleting folder-based gallery %q since the folder no longer exists", g.GetTitle())
|
||||
logger.Infof("Deleting folder-based gallery %q since the folder no longer exists", g.DisplayName())
|
||||
if err := qb.Destroy(ctx, g.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -303,7 +303,7 @@ func (h *cleanHandler) deleteRelatedImages(ctx context.Context, fileDeleter *fil
|
|||
}
|
||||
|
||||
if len(i.Files.List()) <= 1 {
|
||||
logger.Infof("Deleting image %q since it has no other related files", i.GetTitle())
|
||||
logger.Infof("Deleting image %q since it has no other related files", i.DisplayName())
|
||||
if err := mgr.ImageService.Destroy(ctx, i, imageFileDeleter, true, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ func (t *ExportTask) populateGalleryImages(ctx context.Context, repo Repository)
|
|||
|
||||
for _, g := range galleries {
|
||||
if err := g.LoadFiles(ctx, reader); err != nil {
|
||||
logger.Errorf("[galleries] <%s> failed to fetch files for gallery: %s", g.GetTitle(), err.Error())
|
||||
logger.Errorf("[galleries] <%s> failed to fetch files for gallery: %s", g.DisplayName(), err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +761,7 @@ func exportGallery(ctx context.Context, wg *sync.WaitGroup, jobChan <-chan *mode
|
|||
|
||||
for g := range jobChan {
|
||||
if err := g.LoadFiles(ctx, repo.Gallery); err != nil {
|
||||
logger.Errorf("[galleries] <%s> failed to fetch files for gallery: %s", g.GetTitle(), err.Error())
|
||||
logger.Errorf("[galleries] <%s> failed to fetch files for gallery: %s", g.DisplayName(), err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ func (s *Service) Destroy(ctx context.Context, i *models.Gallery, fileDeleter *i
|
|||
}
|
||||
|
||||
func (s *Service) destroyZipFileImages(ctx context.Context, i *models.Gallery, fileDeleter *image.FileDeleter, deleteGenerated, deleteFile bool) ([]*models.Image, error) {
|
||||
if err := i.LoadFiles(ctx, s.Repository); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var imgsDestroyed []*models.Image
|
||||
|
||||
destroyer := &file.ZipDestroyer{
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ func (h *ScanHandler) associateExisting(ctx context.Context, existing []*models.
|
|||
}
|
||||
|
||||
if !found {
|
||||
logger.Infof("Adding %s to gallery %s", f.Base().Path, i.GetTitle())
|
||||
logger.Infof("Adding %s to gallery %s", f.Base().Path, i.DisplayName())
|
||||
|
||||
if err := h.CreatorUpdater.AddFileID(ctx, i.ID, f.Base().ID); err != nil {
|
||||
return fmt.Errorf("adding file to gallery: %w", err)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ type FinderByFile interface {
|
|||
type Repository interface {
|
||||
FinderByFile
|
||||
Destroy(ctx context.Context, id int) error
|
||||
models.FileLoader
|
||||
}
|
||||
|
||||
type ImageFinder interface {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ func (s *Service) destroyImage(ctx context.Context, i *models.Image, fileDeleter
|
|||
|
||||
// deleteFiles deletes files for the image from the database and file system, if they are not in use by other images
|
||||
func (s *Service) deleteFiles(ctx context.Context, i *models.Image, fileDeleter *FileDeleter) error {
|
||||
if err := i.LoadFiles(ctx, s.Repository); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range i.Files.List() {
|
||||
// only delete files where there is no other associated image
|
||||
otherImages, err := s.Repository.FindByFileID(ctx, f.ID)
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ func (h *ScanHandler) associateExisting(ctx context.Context, existing []*models.
|
|||
}
|
||||
|
||||
if !found {
|
||||
logger.Infof("Adding %s to image %s", f.Path, i.GetTitle())
|
||||
logger.Infof("Adding %s to image %s", f.Path, i.DisplayName())
|
||||
|
||||
// associate with folder-based gallery if applicable
|
||||
if h.ScanConfig.GetCreateGalleriesFromFolders() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package models
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/file"
|
||||
|
|
@ -128,6 +129,20 @@ func (g Gallery) GetTitle() string {
|
|||
return g.Path
|
||||
}
|
||||
|
||||
// DisplayName returns a display name for the scene for logging purposes.
|
||||
// It returns the path or title, or otherwise it returns the ID if both of these are empty.
|
||||
func (g Gallery) DisplayName() string {
|
||||
if g.Path != "" {
|
||||
return g.Path
|
||||
}
|
||||
|
||||
if g.Title != "" {
|
||||
return g.Title
|
||||
}
|
||||
|
||||
return strconv.Itoa(g.ID)
|
||||
}
|
||||
|
||||
const DefaultGthumbWidth int = 640
|
||||
|
||||
type Galleries []*Gallery
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/file"
|
||||
|
|
@ -96,6 +97,16 @@ func (i Image) GetTitle() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// DisplayName returns a display name for the scene for logging purposes.
|
||||
// It returns Path if not empty, otherwise it returns the ID.
|
||||
func (i Image) DisplayName() string {
|
||||
if i.Path != "" {
|
||||
return i.Path
|
||||
}
|
||||
|
||||
return strconv.Itoa(i.ID)
|
||||
}
|
||||
|
||||
type ImageCreateInput struct {
|
||||
*Image
|
||||
FileIDs []file.ID
|
||||
|
|
|
|||
|
|
@ -222,6 +222,16 @@ func (s Scene) GetTitle() string {
|
|||
return filepath.Base(s.Path)
|
||||
}
|
||||
|
||||
// DisplayName returns a display name for the scene for logging purposes.
|
||||
// It returns Path if not empty, otherwise it returns the ID.
|
||||
func (s Scene) DisplayName() string {
|
||||
if s.Path != "" {
|
||||
return s.Path
|
||||
}
|
||||
|
||||
return strconv.Itoa(s.ID)
|
||||
}
|
||||
|
||||
// GetHash returns the hash of the scene, based on the hash algorithm provided. If
|
||||
// hash algorithm is MD5, then Checksum is returned. Otherwise, OSHash is returned.
|
||||
func (s Scene) GetHash(hashAlgorithm HashAlgorithm) string {
|
||||
|
|
|
|||
|
|
@ -161,6 +161,10 @@ func (s *Service) Destroy(ctx context.Context, scene *models.Scene, fileDeleter
|
|||
|
||||
// deleteFiles deletes files from the database and file system
|
||||
func (s *Service) deleteFiles(ctx context.Context, scene *models.Scene, fileDeleter *FileDeleter) error {
|
||||
if err := scene.LoadFiles(ctx, s.Repository); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range scene.Files.List() {
|
||||
// only delete files where there is no other associated scene
|
||||
otherScenes, err := s.Repository.FindByFileID(ctx, f.ID)
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ func (h *ScanHandler) associateExisting(ctx context.Context, existing []*models.
|
|||
}
|
||||
|
||||
if !found {
|
||||
logger.Infof("Adding %s to scene %s", f.Path, s.GetTitle())
|
||||
logger.Infof("Adding %s to scene %s", f.Path, s.DisplayName())
|
||||
|
||||
if err := h.CreatorUpdater.AddFileID(ctx, s.ID, f.ID); err != nil {
|
||||
return fmt.Errorf("adding file to scene: %w", err)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type FinderByFile interface {
|
|||
type Repository interface {
|
||||
FinderByFile
|
||||
Destroyer
|
||||
models.VideoFileLoader
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
|
|
|
|||
|
|
@ -806,6 +806,10 @@ func (c Client) SubmitSceneDraft(ctx context.Context, scene *models.Scene, endpo
|
|||
fingerprints := []*graphql.FingerprintInput{}
|
||||
|
||||
// submit all file fingerprints
|
||||
if err := scene.LoadFiles(ctx, r.Scene); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, f := range scene.Files.List() {
|
||||
duration := f.Duration
|
||||
|
||||
|
|
@ -888,6 +892,10 @@ func (c Client) SubmitSceneDraft(ctx context.Context, scene *models.Scene, endpo
|
|||
}
|
||||
}
|
||||
|
||||
if err := scene.LoadStashIDs(ctx, r.Scene); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stashIDs := scene.StashIDs.List()
|
||||
var stashID *string
|
||||
for _, v := range stashIDs {
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ func (qb *GalleryStore) get(ctx context.Context, q *goqu.SelectDataset) (*models
|
|||
func (qb *GalleryStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Gallery, error) {
|
||||
const single = false
|
||||
var ret []*models.Gallery
|
||||
var lastID int
|
||||
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
||||
var f galleryQueryRow
|
||||
if err := r.StructScan(&f); err != nil {
|
||||
|
|
@ -307,6 +308,11 @@ func (qb *GalleryStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*
|
|||
|
||||
s := f.resolve()
|
||||
|
||||
if s.ID == lastID {
|
||||
return fmt.Errorf("internal error: multiple rows returned for single gallery id %d", s.ID)
|
||||
}
|
||||
lastID = s.ID
|
||||
|
||||
ret = append(ret, s)
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ func (qb *ImageStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.I
|
|||
func (qb *ImageStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Image, error) {
|
||||
const single = false
|
||||
var ret []*models.Image
|
||||
var lastID int
|
||||
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
||||
var f imageQueryRow
|
||||
if err := r.StructScan(&f); err != nil {
|
||||
|
|
@ -323,6 +324,11 @@ func (qb *ImageStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
|
|||
|
||||
i := f.resolve()
|
||||
|
||||
if i.ID == lastID {
|
||||
return fmt.Errorf("internal error: multiple rows returned for single image id %d", i.ID)
|
||||
}
|
||||
lastID = i.ID
|
||||
|
||||
ret = append(ret, i)
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
|
|
|||
|
|
@ -410,6 +410,7 @@ func (qb *SceneStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.S
|
|||
func (qb *SceneStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Scene, error) {
|
||||
const single = false
|
||||
var ret []*models.Scene
|
||||
var lastID int
|
||||
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
||||
var f sceneQueryRow
|
||||
if err := r.StructScan(&f); err != nil {
|
||||
|
|
@ -417,6 +418,10 @@ func (qb *SceneStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
|
|||
}
|
||||
|
||||
s := f.resolve()
|
||||
if s.ID == lastID {
|
||||
return fmt.Errorf("internal error: multiple rows returned for single scene id %d", s.ID)
|
||||
}
|
||||
lastID = s.ID
|
||||
|
||||
ret = append(ret, s)
|
||||
return nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue