mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Support file-less scenes. Add scene split, merge and reassign file (#3006)
* Reassign scene file functionality * Implement scene create * Add scene create UI * Add sceneMerge backend support * Add merge scene to UI * Populate split create with scene details * Add merge button to duplicate checker * Handle file-less scenes in marker preview generate * Make unique file name for file-less scene exports * Add o-counter to scene update input * Hide rescan for file-less scenes * Generate heatmap if no speed set on file * Fix count in scene/image queries
This commit is contained in:
@@ -746,7 +746,7 @@ func (qb *ImageStore) queryGroupedFields(ctx context.Context, options models.Ima
|
||||
aggregateQuery := qb.newQuery()
|
||||
|
||||
if options.Count {
|
||||
aggregateQuery.addColumn("COUNT(temp.id) as total")
|
||||
aggregateQuery.addColumn("COUNT(DISTINCT temp.id) as total")
|
||||
}
|
||||
|
||||
// TODO - this doesn't work yet
|
||||
|
||||
@@ -975,7 +975,7 @@ func (qb *SceneStore) queryGroupedFields(ctx context.Context, options models.Sce
|
||||
aggregateQuery := qb.newQuery()
|
||||
|
||||
if options.Count {
|
||||
aggregateQuery.addColumn("COUNT(temp.id) as total")
|
||||
aggregateQuery.addColumn("COUNT(DISTINCT temp.id) as total")
|
||||
}
|
||||
|
||||
if options.TotalDuration {
|
||||
@@ -1432,6 +1432,22 @@ func (qb *SceneStore) DestroyCover(ctx context.Context, sceneID int) error {
|
||||
return qb.imageRepository().destroy(ctx, []int{sceneID})
|
||||
}
|
||||
|
||||
func (qb *SceneStore) AssignFiles(ctx context.Context, sceneID int, fileIDs []file.ID) error {
|
||||
// assuming a file can only be assigned to a single scene
|
||||
if err := scenesFilesTableMgr.destroyJoins(ctx, fileIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// assign primary only if destination has no files
|
||||
existingFileIDs, err := qb.filesRepository().get(ctx, sceneID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
firstPrimary := len(existingFileIDs) == 0
|
||||
return scenesFilesTableMgr.insertJoins(ctx, sceneID, firstPrimary, fileIDs)
|
||||
}
|
||||
|
||||
func (qb *SceneStore) moviesRepository() *repository {
|
||||
return &repository{
|
||||
tx: qb.tx,
|
||||
|
||||
@@ -4077,5 +4077,47 @@ func TestSceneStore_FindDuplicates(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSceneStore_AssignFiles(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sceneID int
|
||||
fileID file.ID
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"valid",
|
||||
sceneIDs[sceneIdx1WithPerformer],
|
||||
sceneFileIDs[sceneIdx1WithStudio],
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid file id",
|
||||
sceneIDs[sceneIdx1WithPerformer],
|
||||
invalidFileID,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid scene id",
|
||||
invalidID,
|
||||
sceneFileIDs[sceneIdx1WithStudio],
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
qb := db.Scene
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
withRollbackTxn(func(ctx context.Context) error {
|
||||
if err := qb.AssignFiles(ctx, tt.sceneID, []file.ID{tt.fileID}); (err != nil) != tt.wantErr {
|
||||
t.Errorf("SceneStore.AssignFiles() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Count
|
||||
// TODO SizeCount
|
||||
|
||||
@@ -529,6 +529,17 @@ func (t *relatedFilesTable) replaceJoins(ctx context.Context, id int, fileIDs []
|
||||
return t.insertJoins(ctx, id, firstPrimary, fileIDs)
|
||||
}
|
||||
|
||||
// destroyJoins destroys all entries in the table with the provided fileIDs
|
||||
func (t *relatedFilesTable) destroyJoins(ctx context.Context, fileIDs []file.ID) error {
|
||||
q := dialect.Delete(t.table.table).Where(t.table.table.Col("file_id").In(fileIDs))
|
||||
|
||||
if _, err := exec(ctx, q); err != nil {
|
||||
return fmt.Errorf("destroying file joins in %s: %w", t.table.table.GetTable(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *relatedFilesTable) setPrimary(ctx context.Context, id int, fileID file.ID) error {
|
||||
table := t.table.table
|
||||
|
||||
|
||||
Reference in New Issue
Block a user