mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Scene filename to metadata parser (#164)
* Initial UI prototype
* Add backend support to update multiple scenes
* Fix title editing issues
* Add query regex support. UI improvements
* Rewrite parser. Add fields button and page size
* Add helper text for escaping {} characters
* Validate date
* Only set values if different from original
* Only update scenes that have something changed
* Add built in parser input recipes
* Make pattern matching case-insensistive
This commit is contained in:
@@ -6,12 +6,57 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"github.com/stashapp/stash/pkg/database"
|
||||
"github.com/stashapp/stash/pkg/manager"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) {
|
||||
// Start the transaction and save the scene
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
|
||||
ret, err := r.sceneUpdate(input, tx)
|
||||
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ScenesUpdate(ctx context.Context, input []*models.SceneUpdateInput) ([]*models.Scene, error) {
|
||||
// Start the transaction and save the scene
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
|
||||
var ret []*models.Scene
|
||||
|
||||
for _, scene := range input {
|
||||
thisScene, err := r.sceneUpdate(*scene, tx)
|
||||
ret = append(ret, thisScene)
|
||||
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.Tx) (*models.Scene, error) {
|
||||
// Populate scene from the input
|
||||
sceneID, _ := strconv.Atoi(input.ID)
|
||||
updatedTime := time.Now()
|
||||
@@ -47,13 +92,10 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp
|
||||
updatedScene.StudioID = &sql.NullInt64{Valid: false}
|
||||
}
|
||||
|
||||
// Start the transaction and save the scene marker
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
jqb := models.NewJoinsQueryBuilder()
|
||||
scene, err := qb.Update(updatedScene, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -61,7 +103,6 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp
|
||||
gqb := models.NewGalleryQueryBuilder()
|
||||
err = gqb.ClearGalleryId(sceneID, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -76,7 +117,6 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp
|
||||
gqb := models.NewGalleryQueryBuilder()
|
||||
_, err := gqb.Update(updatedGallery, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -92,7 +132,6 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp
|
||||
performerJoins = append(performerJoins, performerJoin)
|
||||
}
|
||||
if err := jqb.UpdatePerformersScenes(sceneID, performerJoins, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -107,12 +146,6 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp
|
||||
tagJoins = append(tagJoins, tagJoin)
|
||||
}
|
||||
if err := jqb.UpdateScenesTags(sceneID, tagJoins, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -27,3 +27,13 @@ func (r *queryResolver) FindScenes(ctx context.Context, sceneFilter *models.Scen
|
||||
Scenes: scenes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindScenesByPathRegex(ctx context.Context, filter *models.FindFilterType) (*models.FindScenesResultType, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
|
||||
scenes, total := qb.QueryByPathRegex(filter)
|
||||
return &models.FindScenesResultType{
|
||||
Count: total,
|
||||
Scenes: scenes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/source"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
sqlite3 "github.com/mattn/go-sqlite3"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
"os"
|
||||
@@ -15,11 +17,16 @@ import (
|
||||
var DB *sqlx.DB
|
||||
var appSchemaVersion uint = 1
|
||||
|
||||
const sqlite3Driver = "sqlite3_regexp"
|
||||
|
||||
func Initialize(databasePath string) {
|
||||
runMigrations(databasePath)
|
||||
|
||||
// register custom driver with regexp function
|
||||
registerRegexpFunc()
|
||||
|
||||
// https://github.com/mattn/go-sqlite3
|
||||
conn, err := sqlx.Open("sqlite3", "file:"+databasePath+"?_fk=true")
|
||||
conn, err := sqlx.Open(sqlite3Driver, "file:"+databasePath+"?_fk=true")
|
||||
conn.SetMaxOpenConns(25)
|
||||
conn.SetMaxIdleConns(4)
|
||||
if err != nil {
|
||||
@@ -62,3 +69,16 @@ func runMigrations(databasePath string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func registerRegexpFunc() {
|
||||
regexFn := func(re, s string) (bool, error) {
|
||||
return regexp.MatchString(re, s)
|
||||
}
|
||||
|
||||
sql.Register(sqlite3Driver,
|
||||
&sqlite3.SQLiteDriver{
|
||||
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
||||
return conn.RegisterFunc("regexp", regexFn, true)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -291,6 +291,32 @@ func getMultiCriterionClause(table string, joinTable string, joinTableField stri
|
||||
return whereClause, havingClause
|
||||
}
|
||||
|
||||
func (qb *SceneQueryBuilder) QueryByPathRegex(findFilter *FindFilterType) ([]*Scene, int) {
|
||||
if findFilter == nil {
|
||||
findFilter = &FindFilterType{}
|
||||
}
|
||||
|
||||
var whereClauses []string
|
||||
var havingClauses []string
|
||||
var args []interface{}
|
||||
body := selectDistinctIDs("scenes")
|
||||
|
||||
if q := findFilter.Q; q != nil && *q != "" {
|
||||
whereClauses = append(whereClauses, "scenes.path regexp '" + *q + "'")
|
||||
}
|
||||
|
||||
sortAndPagination := qb.getSceneSort(findFilter) + getPagination(findFilter)
|
||||
idsResult, countResult := executeFindQuery("scenes", body, args, sortAndPagination, whereClauses, havingClauses)
|
||||
|
||||
var scenes []*Scene
|
||||
for _, id := range idsResult {
|
||||
scene, _ := qb.Find(id)
|
||||
scenes = append(scenes, scene)
|
||||
}
|
||||
|
||||
return scenes, countResult
|
||||
}
|
||||
|
||||
func (qb *SceneQueryBuilder) getSceneSort(findFilter *FindFilterType) string {
|
||||
if findFilter == nil {
|
||||
return " ORDER BY scenes.path, scenes.date ASC "
|
||||
|
||||
Reference in New Issue
Block a user