mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Model refactor, part 3 (#4152)
* Remove manager.Repository * Refactor other repositories * Fix tests and add database mock * Add AssertExpectations method * Refactor routes * Move default movie image to internal/static and add convenience methods * Refactor default performer image boxes
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/internal/static"
|
||||
"github.com/stashapp/stash/pkg/hash"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
@@ -18,7 +19,7 @@ type imageBox struct {
|
||||
files []string
|
||||
}
|
||||
|
||||
var imageExtensions = []string{
|
||||
var imageBoxExts = []string{
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".png",
|
||||
@@ -42,7 +43,7 @@ func newImageBox(box fs.FS) (*imageBox, error) {
|
||||
}
|
||||
|
||||
baseName := strings.ToLower(d.Name())
|
||||
for _, ext := range imageExtensions {
|
||||
for _, ext := range imageBoxExts {
|
||||
if strings.HasSuffix(baseName, ext) {
|
||||
ret.files = append(ret.files, path)
|
||||
break
|
||||
@@ -55,65 +56,14 @@ func newImageBox(box fs.FS) (*imageBox, error) {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
var performerBox *imageBox
|
||||
var performerBoxMale *imageBox
|
||||
var performerBoxCustom *imageBox
|
||||
|
||||
func initialiseImages() {
|
||||
var err error
|
||||
performerBox, err = newImageBox(&static.Performer)
|
||||
if err != nil {
|
||||
logger.Warnf("error loading performer images: %v", err)
|
||||
}
|
||||
performerBoxMale, err = newImageBox(&static.PerformerMale)
|
||||
if err != nil {
|
||||
logger.Warnf("error loading male performer images: %v", err)
|
||||
}
|
||||
initialiseCustomImages()
|
||||
}
|
||||
|
||||
func initialiseCustomImages() {
|
||||
customPath := config.GetInstance().GetCustomPerformerImageLocation()
|
||||
if customPath != "" {
|
||||
logger.Debugf("Loading custom performer images from %s", customPath)
|
||||
// We need to set performerBoxCustom at runtime, as this is a custom path, and store it in a pointer.
|
||||
var err error
|
||||
performerBoxCustom, err = newImageBox(os.DirFS(customPath))
|
||||
if err != nil {
|
||||
logger.Warnf("error loading custom performer from %s: %v", customPath, err)
|
||||
}
|
||||
} else {
|
||||
performerBoxCustom = nil
|
||||
}
|
||||
}
|
||||
|
||||
func getRandomPerformerImageUsingName(name string, gender *models.GenderEnum, customPath string) ([]byte, error) {
|
||||
var box *imageBox
|
||||
|
||||
// If we have a custom path, we should return a new box in the given path.
|
||||
if performerBoxCustom != nil && len(performerBoxCustom.files) > 0 {
|
||||
box = performerBoxCustom
|
||||
func (box *imageBox) GetRandomImageByName(name string) ([]byte, error) {
|
||||
files := box.files
|
||||
if len(files) == 0 {
|
||||
return nil, errors.New("box is empty")
|
||||
}
|
||||
|
||||
var g models.GenderEnum
|
||||
if gender != nil {
|
||||
g = *gender
|
||||
}
|
||||
|
||||
if box == nil {
|
||||
switch g {
|
||||
case models.GenderEnumFemale, models.GenderEnumTransgenderFemale:
|
||||
box = performerBox
|
||||
case models.GenderEnumMale, models.GenderEnumTransgenderMale:
|
||||
box = performerBoxMale
|
||||
default:
|
||||
box = performerBox
|
||||
}
|
||||
}
|
||||
|
||||
imageFiles := box.files
|
||||
index := hash.IntFromString(name) % uint64(len(imageFiles))
|
||||
img, err := box.box.Open(imageFiles[index])
|
||||
index := hash.IntFromString(name) % uint64(len(files))
|
||||
img, err := box.box.Open(files[index])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -121,3 +71,64 @@ func getRandomPerformerImageUsingName(name string, gender *models.GenderEnum, cu
|
||||
|
||||
return io.ReadAll(img)
|
||||
}
|
||||
|
||||
var performerBox *imageBox
|
||||
var performerBoxMale *imageBox
|
||||
var performerBoxCustom *imageBox
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
performerBox, err = newImageBox(static.Sub(static.Performer))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("loading performer images: %v", err))
|
||||
}
|
||||
performerBoxMale, err = newImageBox(static.Sub(static.PerformerMale))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("loading male performer images: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
func initCustomPerformerImages(customPath string) {
|
||||
if customPath != "" {
|
||||
logger.Debugf("Loading custom performer images from %s", customPath)
|
||||
var err error
|
||||
performerBoxCustom, err = newImageBox(os.DirFS(customPath))
|
||||
if err != nil {
|
||||
logger.Warnf("error loading custom performer images from %s: %v", customPath, err)
|
||||
}
|
||||
} else {
|
||||
performerBoxCustom = nil
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultPerformerImage(name string, gender *models.GenderEnum) []byte {
|
||||
// try the custom box first if we have one
|
||||
if performerBoxCustom != nil {
|
||||
ret, err := performerBoxCustom.GetRandomImageByName(name)
|
||||
if err == nil {
|
||||
return ret
|
||||
}
|
||||
logger.Warnf("error loading custom default performer image: %v", err)
|
||||
}
|
||||
|
||||
var g models.GenderEnum
|
||||
if gender != nil {
|
||||
g = *gender
|
||||
}
|
||||
|
||||
var box *imageBox
|
||||
switch g {
|
||||
case models.GenderEnumFemale, models.GenderEnumTransgenderFemale:
|
||||
box = performerBox
|
||||
case models.GenderEnumMale, models.GenderEnumTransgenderMale:
|
||||
box = performerBoxMale
|
||||
default:
|
||||
box = performerBox
|
||||
}
|
||||
|
||||
ret, err := box.GetRandomImageByName(name)
|
||||
if err != nil {
|
||||
logger.Warnf("error loading default performer image: %v", err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
)
|
||||
|
||||
type contextKey struct{ name string }
|
||||
@@ -49,8 +47,7 @@ type Loaders struct {
|
||||
}
|
||||
|
||||
type Middleware struct {
|
||||
DatabaseProvider txn.DatabaseProvider
|
||||
Repository manager.Repository
|
||||
Repository models.Repository
|
||||
}
|
||||
|
||||
func (m Middleware) Middleware(next http.Handler) http.Handler {
|
||||
@@ -131,13 +128,9 @@ func toErrorSlice(err error) []error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Middleware) withTxn(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||
return txn.WithDatabase(ctx, m.DatabaseProvider, fn)
|
||||
}
|
||||
|
||||
func (m Middleware) fetchScenes(ctx context.Context) func(keys []int) ([]*models.Scene, []error) {
|
||||
return func(keys []int) (ret []*models.Scene, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Scene.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -148,7 +141,7 @@ func (m Middleware) fetchScenes(ctx context.Context) func(keys []int) ([]*models
|
||||
|
||||
func (m Middleware) fetchImages(ctx context.Context) func(keys []int) ([]*models.Image, []error) {
|
||||
return func(keys []int) (ret []*models.Image, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Image.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -160,7 +153,7 @@ func (m Middleware) fetchImages(ctx context.Context) func(keys []int) ([]*models
|
||||
|
||||
func (m Middleware) fetchGalleries(ctx context.Context) func(keys []int) ([]*models.Gallery, []error) {
|
||||
return func(keys []int) (ret []*models.Gallery, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Gallery.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -172,7 +165,7 @@ func (m Middleware) fetchGalleries(ctx context.Context) func(keys []int) ([]*mod
|
||||
|
||||
func (m Middleware) fetchPerformers(ctx context.Context) func(keys []int) ([]*models.Performer, []error) {
|
||||
return func(keys []int) (ret []*models.Performer, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Performer.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -184,7 +177,7 @@ func (m Middleware) fetchPerformers(ctx context.Context) func(keys []int) ([]*mo
|
||||
|
||||
func (m Middleware) fetchStudios(ctx context.Context) func(keys []int) ([]*models.Studio, []error) {
|
||||
return func(keys []int) (ret []*models.Studio, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Studio.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -195,7 +188,7 @@ func (m Middleware) fetchStudios(ctx context.Context) func(keys []int) ([]*model
|
||||
|
||||
func (m Middleware) fetchTags(ctx context.Context) func(keys []int) ([]*models.Tag, []error) {
|
||||
return func(keys []int) (ret []*models.Tag, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Tag.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -206,7 +199,7 @@ func (m Middleware) fetchTags(ctx context.Context) func(keys []int) ([]*models.T
|
||||
|
||||
func (m Middleware) fetchMovies(ctx context.Context) func(keys []int) ([]*models.Movie, []error) {
|
||||
return func(keys []int) (ret []*models.Movie, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Movie.FindMany(ctx, keys)
|
||||
return err
|
||||
@@ -217,7 +210,7 @@ func (m Middleware) fetchMovies(ctx context.Context) func(keys []int) ([]*models
|
||||
|
||||
func (m Middleware) fetchFiles(ctx context.Context) func(keys []models.FileID) ([]models.File, []error) {
|
||||
return func(keys []models.FileID) (ret []models.File, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.File.Find(ctx, keys...)
|
||||
return err
|
||||
@@ -228,7 +221,7 @@ func (m Middleware) fetchFiles(ctx context.Context) func(keys []models.FileID) (
|
||||
|
||||
func (m Middleware) fetchScenesFileIDs(ctx context.Context) func(keys []int) ([][]models.FileID, []error) {
|
||||
return func(keys []int) (ret [][]models.FileID, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Scene.GetManyFileIDs(ctx, keys)
|
||||
return err
|
||||
@@ -239,7 +232,7 @@ func (m Middleware) fetchScenesFileIDs(ctx context.Context) func(keys []int) ([]
|
||||
|
||||
func (m Middleware) fetchImagesFileIDs(ctx context.Context) func(keys []int) ([][]models.FileID, []error) {
|
||||
return func(keys []int) (ret [][]models.FileID, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Image.GetManyFileIDs(ctx, keys)
|
||||
return err
|
||||
@@ -250,7 +243,7 @@ func (m Middleware) fetchImagesFileIDs(ctx context.Context) func(keys []int) ([]
|
||||
|
||||
func (m Middleware) fetchGalleriesFileIDs(ctx context.Context) func(keys []int) ([][]models.FileID, []error) {
|
||||
return func(keys []int) (ret [][]models.FileID, errs []error) {
|
||||
err := m.withTxn(ctx, func(ctx context.Context) error {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Gallery.GetManyFileIDs(ctx, keys)
|
||||
return err
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/plugin"
|
||||
"github.com/stashapp/stash/pkg/scraper"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/scraper/stashbox"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -33,8 +33,7 @@ type hookExecutor interface {
|
||||
}
|
||||
|
||||
type Resolver struct {
|
||||
txnManager txn.Manager
|
||||
repository manager.Repository
|
||||
repository models.Repository
|
||||
sceneService manager.SceneService
|
||||
imageService manager.ImageService
|
||||
galleryService manager.GalleryService
|
||||
@@ -102,11 +101,15 @@ type tagResolver struct{ *Resolver }
|
||||
type savedFilterResolver struct{ *Resolver }
|
||||
|
||||
func (r *Resolver) withTxn(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||
return txn.WithTxn(ctx, r.txnManager, fn)
|
||||
return r.repository.WithTxn(ctx, fn)
|
||||
}
|
||||
|
||||
func (r *Resolver) withReadTxn(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||
return txn.WithReadTxn(ctx, r.txnManager, fn)
|
||||
return r.repository.WithReadTxn(ctx, fn)
|
||||
}
|
||||
|
||||
func (r *Resolver) stashboxRepository() stashbox.Repository {
|
||||
return stashbox.NewRepository(r.repository)
|
||||
}
|
||||
|
||||
func (r *queryResolver) MarkerWall(ctx context.Context, q *string) (ret []*models.SceneMarker, err error) {
|
||||
|
||||
@@ -316,7 +316,7 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input ConfigGen
|
||||
|
||||
if input.CustomPerformerImageLocation != nil {
|
||||
c.Set(config.CustomPerformerImageLocation, *input.CustomPerformerImageLocation)
|
||||
initialiseCustomImages()
|
||||
initCustomPerformerImages(*input.CustomPerformerImageLocation)
|
||||
}
|
||||
|
||||
if input.ScraperUserAgent != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ func (r *mutationResolver) MoveFiles(ctx context.Context, input MoveFilesInput)
|
||||
fileStore := r.repository.File
|
||||
folderStore := r.repository.Folder
|
||||
mover := file.NewMover(fileStore, folderStore)
|
||||
mover.RegisterHooks(ctx, r.txnManager)
|
||||
mover.RegisterHooks(ctx)
|
||||
|
||||
var (
|
||||
folder *models.Folder
|
||||
|
||||
@@ -11,30 +11,30 @@ import (
|
||||
)
|
||||
|
||||
func (r *mutationResolver) MigrateSceneScreenshots(ctx context.Context, input MigrateSceneScreenshotsInput) (string, error) {
|
||||
db := manager.GetInstance().Database
|
||||
mgr := manager.GetInstance()
|
||||
t := &task.MigrateSceneScreenshotsJob{
|
||||
ScreenshotsPath: manager.GetInstance().Paths.Generated.Screenshots,
|
||||
Input: scene.MigrateSceneScreenshotsInput{
|
||||
DeleteFiles: utils.IsTrue(input.DeleteFiles),
|
||||
OverwriteExisting: utils.IsTrue(input.OverwriteExisting),
|
||||
},
|
||||
SceneRepo: db.Scene,
|
||||
TxnManager: db,
|
||||
SceneRepo: mgr.Repository.Scene,
|
||||
TxnManager: mgr.Repository.TxnManager,
|
||||
}
|
||||
jobID := manager.GetInstance().JobManager.Add(ctx, "Migrating scene screenshots to blobs...", t)
|
||||
jobID := mgr.JobManager.Add(ctx, "Migrating scene screenshots to blobs...", t)
|
||||
|
||||
return strconv.Itoa(jobID), nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) MigrateBlobs(ctx context.Context, input MigrateBlobsInput) (string, error) {
|
||||
db := manager.GetInstance().Database
|
||||
mgr := manager.GetInstance()
|
||||
t := &task.MigrateBlobsJob{
|
||||
TxnManager: db,
|
||||
BlobStore: db.Blobs,
|
||||
Vacuumer: db,
|
||||
TxnManager: mgr.Database,
|
||||
BlobStore: mgr.Database.Blobs,
|
||||
Vacuumer: mgr.Database,
|
||||
DeleteOld: utils.IsTrue(input.DeleteOld),
|
||||
}
|
||||
jobID := manager.GetInstance().JobManager.Add(ctx, "Migrating blobs...", t)
|
||||
jobID := mgr.JobManager.Add(ctx, "Migrating blobs...", t)
|
||||
|
||||
return strconv.Itoa(jobID), nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/internal/static"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/plugin"
|
||||
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
|
||||
@@ -50,12 +51,6 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
|
||||
return nil, fmt.Errorf("converting studio id: %w", err)
|
||||
}
|
||||
|
||||
// HACK: if back image is being set, set the front image to the default.
|
||||
// This is because we can't have a null front image with a non-null back image.
|
||||
if input.FrontImage == nil && input.BackImage != nil {
|
||||
input.FrontImage = &models.DefaultMovieImage
|
||||
}
|
||||
|
||||
// Process the base 64 encoded image string
|
||||
var frontimageData []byte
|
||||
if input.FrontImage != nil {
|
||||
@@ -74,6 +69,12 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: if back image is being set, set the front image to the default.
|
||||
// This is because we can't have a null front image with a non-null back image.
|
||||
if len(frontimageData) == 0 && len(backimageData) != 0 {
|
||||
frontimageData = static.ReadAll(static.DefaultMovieImage)
|
||||
}
|
||||
|
||||
// Start the transaction and save the movie
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
|
||||
@@ -11,15 +11,6 @@ import (
|
||||
"github.com/stashapp/stash/pkg/scraper/stashbox"
|
||||
)
|
||||
|
||||
func (r *Resolver) stashboxRepository() stashbox.Repository {
|
||||
return stashbox.Repository{
|
||||
Scene: r.repository.Scene,
|
||||
Performer: r.repository.Performer,
|
||||
Tag: r.repository.Tag,
|
||||
Studio: r.repository.Studio,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SubmitStashBoxFingerprints(ctx context.Context, input StashBoxFingerprintSubmissionInput) (bool, error) {
|
||||
boxes := config.GetInstance().GetStashBoxes()
|
||||
|
||||
@@ -27,7 +18,7 @@ func (r *mutationResolver) SubmitStashBoxFingerprints(ctx context.Context, input
|
||||
return false, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex)
|
||||
}
|
||||
|
||||
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.txnManager, r.stashboxRepository())
|
||||
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.stashboxRepository())
|
||||
|
||||
return client.SubmitStashBoxFingerprints(ctx, input.SceneIds, boxes[input.StashBoxIndex].Endpoint)
|
||||
}
|
||||
@@ -49,7 +40,7 @@ func (r *mutationResolver) SubmitStashBoxSceneDraft(ctx context.Context, input S
|
||||
return nil, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex)
|
||||
}
|
||||
|
||||
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.txnManager, r.stashboxRepository())
|
||||
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.stashboxRepository())
|
||||
|
||||
id, err := strconv.Atoi(input.ID)
|
||||
if err != nil {
|
||||
@@ -91,7 +82,7 @@ func (r *mutationResolver) SubmitStashBoxPerformerDraft(ctx context.Context, inp
|
||||
return nil, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex)
|
||||
}
|
||||
|
||||
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.txnManager, r.stashboxRepository())
|
||||
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.stashboxRepository())
|
||||
|
||||
id, err := strconv.Atoi(input.ID)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/models/mocks"
|
||||
"github.com/stashapp/stash/pkg/plugin"
|
||||
@@ -15,14 +14,9 @@ import (
|
||||
)
|
||||
|
||||
// TODO - move this into a common area
|
||||
func newResolver() *Resolver {
|
||||
txnMgr := &mocks.TxnManager{}
|
||||
func newResolver(db *mocks.Database) *Resolver {
|
||||
return &Resolver{
|
||||
txnManager: txnMgr,
|
||||
repository: manager.Repository{
|
||||
TxnManager: txnMgr,
|
||||
Tag: &mocks.TagReaderWriter{},
|
||||
},
|
||||
repository: db.Repository(),
|
||||
hookExecutor: &mockHookExecutor{},
|
||||
}
|
||||
}
|
||||
@@ -45,9 +39,8 @@ func (*mockHookExecutor) ExecutePostHooks(ctx context.Context, id int, hookType
|
||||
}
|
||||
|
||||
func TestTagCreate(t *testing.T) {
|
||||
r := newResolver()
|
||||
|
||||
tagRW := r.repository.Tag.(*mocks.TagReaderWriter)
|
||||
db := mocks.NewDatabase()
|
||||
r := newResolver(db)
|
||||
|
||||
pp := 1
|
||||
findFilter := &models.FindFilterType{
|
||||
@@ -72,17 +65,17 @@ func TestTagCreate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
tagRW.On("Query", mock.Anything, tagFilterForName(existingTagName), findFilter).Return([]*models.Tag{
|
||||
db.Tag.On("Query", mock.Anything, tagFilterForName(existingTagName), findFilter).Return([]*models.Tag{
|
||||
{
|
||||
ID: existingTagID,
|
||||
Name: existingTagName,
|
||||
},
|
||||
}, 1, nil).Once()
|
||||
tagRW.On("Query", mock.Anything, tagFilterForName(errTagName), findFilter).Return(nil, 0, nil).Once()
|
||||
tagRW.On("Query", mock.Anything, tagFilterForAlias(errTagName), findFilter).Return(nil, 0, nil).Once()
|
||||
db.Tag.On("Query", mock.Anything, tagFilterForName(errTagName), findFilter).Return(nil, 0, nil).Once()
|
||||
db.Tag.On("Query", mock.Anything, tagFilterForAlias(errTagName), findFilter).Return(nil, 0, nil).Once()
|
||||
|
||||
expectedErr := errors.New("TagCreate error")
|
||||
tagRW.On("Create", mock.Anything, mock.AnythingOfType("*models.Tag")).Return(expectedErr)
|
||||
db.Tag.On("Create", mock.Anything, mock.AnythingOfType("*models.Tag")).Return(expectedErr)
|
||||
|
||||
// fails here because testCtx is empty
|
||||
// TODO: Fix this
|
||||
@@ -101,22 +94,22 @@ func TestTagCreate(t *testing.T) {
|
||||
})
|
||||
|
||||
assert.Equal(t, expectedErr, err)
|
||||
tagRW.AssertExpectations(t)
|
||||
db.AssertExpectations(t)
|
||||
|
||||
r = newResolver()
|
||||
tagRW = r.repository.Tag.(*mocks.TagReaderWriter)
|
||||
db = mocks.NewDatabase()
|
||||
r = newResolver(db)
|
||||
|
||||
tagRW.On("Query", mock.Anything, tagFilterForName(tagName), findFilter).Return(nil, 0, nil).Once()
|
||||
tagRW.On("Query", mock.Anything, tagFilterForAlias(tagName), findFilter).Return(nil, 0, nil).Once()
|
||||
db.Tag.On("Query", mock.Anything, tagFilterForName(tagName), findFilter).Return(nil, 0, nil).Once()
|
||||
db.Tag.On("Query", mock.Anything, tagFilterForAlias(tagName), findFilter).Return(nil, 0, nil).Once()
|
||||
newTag := &models.Tag{
|
||||
ID: newTagID,
|
||||
Name: tagName,
|
||||
}
|
||||
tagRW.On("Create", mock.Anything, mock.AnythingOfType("*models.Tag")).Run(func(args mock.Arguments) {
|
||||
db.Tag.On("Create", mock.Anything, mock.AnythingOfType("*models.Tag")).Run(func(args mock.Arguments) {
|
||||
arg := args.Get(1).(*models.Tag)
|
||||
arg.ID = newTagID
|
||||
}).Return(nil)
|
||||
tagRW.On("Find", mock.Anything, newTagID).Return(newTag, nil)
|
||||
db.Tag.On("Find", mock.Anything, newTagID).Return(newTag, nil)
|
||||
|
||||
tag, err := r.Mutation().TagCreate(testCtx, TagCreateInput{
|
||||
Name: tagName,
|
||||
@@ -124,4 +117,5 @@ func TestTagCreate(t *testing.T) {
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, tag)
|
||||
db.AssertExpectations(t)
|
||||
}
|
||||
|
||||
@@ -243,7 +243,9 @@ func makeConfigUIResult() map[string]interface{} {
|
||||
}
|
||||
|
||||
func (r *queryResolver) ValidateStashBoxCredentials(ctx context.Context, input config.StashBoxInput) (*StashBoxValidationResult, error) {
|
||||
client := stashbox.NewClient(models.StashBox{Endpoint: input.Endpoint, APIKey: input.APIKey}, r.txnManager, r.stashboxRepository())
|
||||
box := models.StashBox{Endpoint: input.Endpoint, APIKey: input.APIKey}
|
||||
client := stashbox.NewClient(box, r.stashboxRepository())
|
||||
|
||||
user, err := client.GetUser(ctx)
|
||||
|
||||
valid := user != nil && user.Me != nil
|
||||
|
||||
@@ -191,16 +191,11 @@ func (r *queryResolver) FindScenesByPathRegex(ctx context.Context, filter *model
|
||||
}
|
||||
|
||||
func (r *queryResolver) ParseSceneFilenames(ctx context.Context, filter *models.FindFilterType, config models.SceneParserInput) (ret *SceneParserResultType, err error) {
|
||||
parser := scene.NewFilenameParser(filter, config)
|
||||
repo := scene.NewFilenameParserRepository(r.repository)
|
||||
parser := scene.NewFilenameParser(filter, config, repo)
|
||||
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
result, count, err := parser.Parse(ctx, scene.FilenameParserRepository{
|
||||
Scene: r.repository.Scene,
|
||||
Performer: r.repository.Performer,
|
||||
Studio: r.repository.Studio,
|
||||
Movie: r.repository.Movie,
|
||||
Tag: r.repository.Tag,
|
||||
})
|
||||
result, count, err := parser.Parse(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -238,7 +238,7 @@ func (r *queryResolver) getStashBoxClient(index int) (*stashbox.Client, error) {
|
||||
return nil, fmt.Errorf("%w: invalid stash_box_index %d", ErrInput, index)
|
||||
}
|
||||
|
||||
return stashbox.NewClient(*boxes[index], r.txnManager, r.stashboxRepository()), nil
|
||||
return stashbox.NewClient(*boxes[index], r.stashboxRepository()), nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) ScrapeSingleScene(ctx context.Context, source scraper.Source, input ScrapeSingleSceneInput) ([]*scraper.ScrapedScene, error) {
|
||||
|
||||
15
internal/api/routes.go
Normal file
15
internal/api/routes.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
)
|
||||
|
||||
type routes struct {
|
||||
txnManager txn.Manager
|
||||
}
|
||||
|
||||
func (rs routes) withReadTxn(r *http.Request, fn txn.TxnFunc) error {
|
||||
return txn.WithReadTxn(r.Context(), rs.txnManager, fn)
|
||||
}
|
||||
@@ -12,6 +12,10 @@ type customRoutes struct {
|
||||
servedFolders config.URLMap
|
||||
}
|
||||
|
||||
func getCustomRoutes(servedFolders config.URLMap) chi.Router {
|
||||
return customRoutes{servedFolders: servedFolders}.Routes()
|
||||
}
|
||||
|
||||
func (rs customRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ import (
|
||||
|
||||
type downloadsRoutes struct{}
|
||||
|
||||
func getDownloadsRoutes() chi.Router {
|
||||
return downloadsRoutes{}.Routes()
|
||||
}
|
||||
|
||||
func (rs downloadsRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
@@ -17,7 +16,6 @@ import (
|
||||
"github.com/stashapp/stash/pkg/image"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -27,11 +25,19 @@ type ImageFinder interface {
|
||||
}
|
||||
|
||||
type imageRoutes struct {
|
||||
txnManager txn.Manager
|
||||
routes
|
||||
imageFinder ImageFinder
|
||||
fileGetter models.FileGetter
|
||||
}
|
||||
|
||||
func getImageRoutes(repo models.Repository) chi.Router {
|
||||
return imageRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
imageFinder: repo.Image,
|
||||
fileGetter: repo.File,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs imageRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -46,8 +52,6 @@ func (rs imageRoutes) Routes() chi.Router {
|
||||
return r
|
||||
}
|
||||
|
||||
// region Handlers
|
||||
|
||||
func (rs imageRoutes) Thumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
img := r.Context().Value(imageKey).(*models.Image)
|
||||
filepath := manager.GetInstance().Paths.Generated.GetThumbnailPath(img.Checksum, models.DefaultGthumbWidth)
|
||||
@@ -119,8 +123,6 @@ func (rs imageRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (rs imageRoutes) serveImage(w http.ResponseWriter, r *http.Request, i *models.Image, useDefault bool) {
|
||||
const defaultImageImage = "image/image.svg"
|
||||
|
||||
if i.Files.Primary() != nil {
|
||||
err := i.Files.Primary().Base().Serve(&file.OsFS{}, w, r)
|
||||
if err == nil {
|
||||
@@ -141,22 +143,18 @@ func (rs imageRoutes) serveImage(w http.ResponseWriter, r *http.Request, i *mode
|
||||
return
|
||||
}
|
||||
|
||||
// fall back to static image
|
||||
f, _ := static.Image.Open(defaultImageImage)
|
||||
defer f.Close()
|
||||
image, _ := io.ReadAll(f)
|
||||
// fallback to default image
|
||||
image := static.ReadAll(static.DefaultImageImage)
|
||||
utils.ServeImage(w, r, image)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
func (rs imageRoutes) ImageCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
imageIdentifierQueryParam := chi.URLParam(r, "imageId")
|
||||
imageID, _ := strconv.Atoi(imageIdentifierQueryParam)
|
||||
|
||||
var image *models.Image
|
||||
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
qb := rs.imageFinder
|
||||
if imageID == 0 {
|
||||
images, _ := qb.FindByChecksum(ctx, imageIdentifierQueryParam)
|
||||
|
||||
@@ -7,9 +7,10 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
"github.com/stashapp/stash/internal/static"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -20,10 +21,17 @@ type MovieFinder interface {
|
||||
}
|
||||
|
||||
type movieRoutes struct {
|
||||
txnManager txn.Manager
|
||||
routes
|
||||
movieFinder MovieFinder
|
||||
}
|
||||
|
||||
func getMovieRoutes(repo models.Repository) chi.Router {
|
||||
return movieRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
movieFinder: repo.Movie,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs movieRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -41,7 +49,7 @@ func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
||||
defaultParam := r.URL.Query().Get("default")
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.movieFinder.GetFrontImage(ctx, movie.ID)
|
||||
return err
|
||||
@@ -54,8 +62,9 @@ func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if len(image) == 0 {
|
||||
image, _ = utils.ProcessBase64Image(models.DefaultMovieImage)
|
||||
image = static.ReadAll(static.DefaultMovieImage)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
@@ -66,7 +75,7 @@ func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
||||
defaultParam := r.URL.Query().Get("default")
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.movieFinder.GetBackImage(ctx, movie.ID)
|
||||
return err
|
||||
@@ -79,8 +88,9 @@ func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if len(image) == 0 {
|
||||
image, _ = utils.ProcessBase64Image(models.DefaultMovieImage)
|
||||
image = static.ReadAll(static.DefaultMovieImage)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
@@ -95,7 +105,7 @@ func (rs movieRoutes) MovieCtx(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
var movie *models.Movie
|
||||
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
movie, _ = rs.movieFinder.Find(ctx, movieID)
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -7,10 +7,8 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -20,10 +18,17 @@ type PerformerFinder interface {
|
||||
}
|
||||
|
||||
type performerRoutes struct {
|
||||
txnManager txn.Manager
|
||||
routes
|
||||
performerFinder PerformerFinder
|
||||
}
|
||||
|
||||
func getPerformerRoutes(repo models.Repository) chi.Router {
|
||||
return performerRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
performerFinder: repo.Performer,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs performerRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -41,7 +46,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.performerFinder.GetImage(ctx, performer.ID)
|
||||
return err
|
||||
@@ -55,7 +60,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if len(image) == 0 {
|
||||
image, _ = getRandomPerformerImageUsingName(performer.Name, performer.Gender, config.GetInstance().GetCustomPerformerImageLocation())
|
||||
image = getDefaultPerformerImage(performer.Name, performer.Gender)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
@@ -70,7 +75,7 @@ func (rs performerRoutes) PerformerCtx(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
var performer *models.Performer
|
||||
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
performer, err = rs.performerFinder.Find(ctx, performerID)
|
||||
return err
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/stashapp/stash/pkg/fsutil"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -43,7 +42,7 @@ type CaptionFinder interface {
|
||||
}
|
||||
|
||||
type sceneRoutes struct {
|
||||
txnManager txn.Manager
|
||||
routes
|
||||
sceneFinder SceneFinder
|
||||
fileGetter models.FileGetter
|
||||
captionFinder CaptionFinder
|
||||
@@ -51,6 +50,17 @@ type sceneRoutes struct {
|
||||
tagFinder SceneMarkerTagFinder
|
||||
}
|
||||
|
||||
func getSceneRoutes(repo models.Repository) chi.Router {
|
||||
return sceneRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
sceneFinder: repo.Scene,
|
||||
fileGetter: repo.File,
|
||||
captionFinder: repo.File,
|
||||
sceneMarkerFinder: repo.SceneMarker,
|
||||
tagFinder: repo.Tag,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -89,8 +99,6 @@ func (rs sceneRoutes) Routes() chi.Router {
|
||||
return r
|
||||
}
|
||||
|
||||
// region Handlers
|
||||
|
||||
func (rs sceneRoutes) StreamDirect(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
ss := manager.SceneServer{
|
||||
@@ -270,13 +278,13 @@ func (rs sceneRoutes) Webp(w http.ResponseWriter, r *http.Request) {
|
||||
utils.ServeStaticFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.SceneMarker) (*string, error) {
|
||||
func (rs sceneRoutes) getChapterVttTitle(r *http.Request, marker *models.SceneMarker) (*string, error) {
|
||||
if marker.Title != "" {
|
||||
return &marker.Title, nil
|
||||
}
|
||||
|
||||
var title string
|
||||
if err := txn.WithReadTxn(ctx, rs.txnManager, func(ctx context.Context) error {
|
||||
if err := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
qb := rs.tagFinder
|
||||
primaryTag, err := qb.Find(ctx, marker.PrimaryTagID)
|
||||
if err != nil {
|
||||
@@ -305,7 +313,7 @@ func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.Sce
|
||||
func (rs sceneRoutes) VttChapter(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
var sceneMarkers []*models.SceneMarker
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarkers, err = rs.sceneMarkerFinder.FindBySceneID(ctx, scene.ID)
|
||||
return err
|
||||
@@ -325,7 +333,7 @@ func (rs sceneRoutes) VttChapter(w http.ResponseWriter, r *http.Request) {
|
||||
time := utils.GetVTTTime(marker.Seconds)
|
||||
vttLines = append(vttLines, time+" --> "+time)
|
||||
|
||||
vttTitle, err := rs.getChapterVttTitle(r.Context(), marker)
|
||||
vttTitle, err := rs.getChapterVttTitle(r, marker)
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
@@ -404,7 +412,7 @@ func (rs sceneRoutes) Caption(w http.ResponseWriter, r *http.Request, lang strin
|
||||
s := r.Context().Value(sceneKey).(*models.Scene)
|
||||
|
||||
var captions []*models.VideoCaption
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
primaryFile := s.Files.Primary()
|
||||
if primaryFile == nil {
|
||||
@@ -466,7 +474,7 @@ func (rs sceneRoutes) SceneMarkerStream(w http.ResponseWriter, r *http.Request)
|
||||
sceneHash := scene.GetHash(config.GetInstance().GetVideoFileNamingAlgorithm())
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
var sceneMarker *models.SceneMarker
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||
return err
|
||||
@@ -494,7 +502,7 @@ func (rs sceneRoutes) SceneMarkerPreview(w http.ResponseWriter, r *http.Request)
|
||||
sceneHash := scene.GetHash(config.GetInstance().GetVideoFileNamingAlgorithm())
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
var sceneMarker *models.SceneMarker
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||
return err
|
||||
@@ -530,7 +538,7 @@ func (rs sceneRoutes) SceneMarkerScreenshot(w http.ResponseWriter, r *http.Reque
|
||||
sceneHash := scene.GetHash(config.GetInstance().GetVideoFileNamingAlgorithm())
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
var sceneMarker *models.SceneMarker
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||
return err
|
||||
@@ -561,8 +569,6 @@ func (rs sceneRoutes) SceneMarkerScreenshot(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
func (rs sceneRoutes) SceneCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
sceneID, err := strconv.Atoi(chi.URLParam(r, "sceneId"))
|
||||
@@ -572,7 +578,7 @@ func (rs sceneRoutes) SceneCtx(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
var scene *models.Scene
|
||||
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
qb := rs.sceneFinder
|
||||
scene, _ = qb.Find(ctx, sceneID)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
"github.com/stashapp/stash/internal/static"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -21,10 +19,17 @@ type StudioFinder interface {
|
||||
}
|
||||
|
||||
type studioRoutes struct {
|
||||
txnManager txn.Manager
|
||||
routes
|
||||
studioFinder StudioFinder
|
||||
}
|
||||
|
||||
func getStudioRoutes(repo models.Repository) chi.Router {
|
||||
return studioRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
studioFinder: repo.Studio,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs studioRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -42,7 +47,7 @@ func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.studioFinder.GetImage(ctx, studio.ID)
|
||||
return err
|
||||
@@ -55,15 +60,9 @@ func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if len(image) == 0 {
|
||||
const defaultStudioImage = "studio/studio.svg"
|
||||
|
||||
// fall back to static image
|
||||
f, _ := static.Studio.Open(defaultStudioImage)
|
||||
defer f.Close()
|
||||
stat, _ := f.Stat()
|
||||
http.ServeContent(w, r, "studio.svg", stat.ModTime(), f.(io.ReadSeeker))
|
||||
return
|
||||
image = static.ReadAll(static.DefaultStudioImage)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
@@ -78,7 +77,7 @@ func (rs studioRoutes) StudioCtx(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
var studio *models.Studio
|
||||
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
studio, err = rs.studioFinder.Find(ctx, studioID)
|
||||
return err
|
||||
|
||||
@@ -3,7 +3,6 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
"github.com/stashapp/stash/internal/static"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/txn"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -21,8 +19,15 @@ type TagFinder interface {
|
||||
}
|
||||
|
||||
type tagRoutes struct {
|
||||
txnManager txn.Manager
|
||||
tagFinder TagFinder
|
||||
routes
|
||||
tagFinder TagFinder
|
||||
}
|
||||
|
||||
func getTagRoutes(repo models.Repository) chi.Router {
|
||||
return tagRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
tagFinder: repo.Tag,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs tagRoutes) Routes() chi.Router {
|
||||
@@ -42,7 +47,7 @@ func (rs tagRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.tagFinder.GetImage(ctx, tag.ID)
|
||||
return err
|
||||
@@ -55,15 +60,9 @@ func (rs tagRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if len(image) == 0 {
|
||||
const defaultTagImage = "tag/tag.svg"
|
||||
|
||||
// fall back to static image
|
||||
f, _ := static.Tag.Open(defaultTagImage)
|
||||
defer f.Close()
|
||||
stat, _ := f.Stat()
|
||||
http.ServeContent(w, r, "tag.svg", stat.ModTime(), f.(io.ReadSeeker))
|
||||
return
|
||||
image = static.ReadAll(static.DefaultTagImage)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
@@ -78,7 +77,7 @@ func (rs tagRoutes) TagCtx(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
var tag *models.Tag
|
||||
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
tag, err = rs.tagFinder.Find(ctx, tagID)
|
||||
return err
|
||||
|
||||
@@ -50,7 +50,9 @@ var uiBox = ui.UIBox
|
||||
var loginUIBox = ui.LoginUIBox
|
||||
|
||||
func Start() error {
|
||||
initialiseImages()
|
||||
c := config.GetInstance()
|
||||
|
||||
initCustomPerformerImages(c.GetCustomPerformerImageLocation())
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -62,7 +64,6 @@ func Start() error {
|
||||
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
c := config.GetInstance()
|
||||
if c.GetLogAccess() {
|
||||
httpLogger := httplog.NewLogger("Stash", httplog.Options{
|
||||
Concise: true,
|
||||
@@ -82,11 +83,10 @@ func Start() error {
|
||||
return errors.New(message)
|
||||
}
|
||||
|
||||
txnManager := manager.GetInstance().Repository
|
||||
repo := manager.GetInstance().Repository
|
||||
|
||||
dataloaders := loaders.Middleware{
|
||||
DatabaseProvider: txnManager,
|
||||
Repository: txnManager,
|
||||
Repository: repo,
|
||||
}
|
||||
|
||||
r.Use(dataloaders.Middleware)
|
||||
@@ -96,8 +96,7 @@ func Start() error {
|
||||
imageService := manager.GetInstance().ImageService
|
||||
galleryService := manager.GetInstance().GalleryService
|
||||
resolver := &Resolver{
|
||||
txnManager: txnManager,
|
||||
repository: txnManager,
|
||||
repository: repo,
|
||||
sceneService: sceneService,
|
||||
imageService: imageService,
|
||||
galleryService: galleryService,
|
||||
@@ -144,36 +143,13 @@ func Start() error {
|
||||
gqlPlayground.Handler("GraphQL playground", endpoint)(w, r)
|
||||
})
|
||||
|
||||
r.Mount("/performer", performerRoutes{
|
||||
txnManager: txnManager,
|
||||
performerFinder: txnManager.Performer,
|
||||
}.Routes())
|
||||
r.Mount("/scene", sceneRoutes{
|
||||
txnManager: txnManager,
|
||||
sceneFinder: txnManager.Scene,
|
||||
fileGetter: txnManager.File,
|
||||
captionFinder: txnManager.File,
|
||||
sceneMarkerFinder: txnManager.SceneMarker,
|
||||
tagFinder: txnManager.Tag,
|
||||
}.Routes())
|
||||
r.Mount("/image", imageRoutes{
|
||||
txnManager: txnManager,
|
||||
imageFinder: txnManager.Image,
|
||||
fileGetter: txnManager.File,
|
||||
}.Routes())
|
||||
r.Mount("/studio", studioRoutes{
|
||||
txnManager: txnManager,
|
||||
studioFinder: txnManager.Studio,
|
||||
}.Routes())
|
||||
r.Mount("/movie", movieRoutes{
|
||||
txnManager: txnManager,
|
||||
movieFinder: txnManager.Movie,
|
||||
}.Routes())
|
||||
r.Mount("/tag", tagRoutes{
|
||||
txnManager: txnManager,
|
||||
tagFinder: txnManager.Tag,
|
||||
}.Routes())
|
||||
r.Mount("/downloads", downloadsRoutes{}.Routes())
|
||||
r.Mount("/performer", getPerformerRoutes(repo))
|
||||
r.Mount("/scene", getSceneRoutes(repo))
|
||||
r.Mount("/image", getImageRoutes(repo))
|
||||
r.Mount("/studio", getStudioRoutes(repo))
|
||||
r.Mount("/movie", getMovieRoutes(repo))
|
||||
r.Mount("/tag", getTagRoutes(repo))
|
||||
r.Mount("/downloads", getDownloadsRoutes())
|
||||
|
||||
r.HandleFunc("/css", cssHandler(c, pluginCache))
|
||||
r.HandleFunc("/javascript", javascriptHandler(c, pluginCache))
|
||||
@@ -193,9 +169,7 @@ func Start() error {
|
||||
// Serve static folders
|
||||
customServedFolders := c.GetCustomServedFolders()
|
||||
if customServedFolders != nil {
|
||||
r.Mount("/custom", customRoutes{
|
||||
servedFolders: customServedFolders,
|
||||
}.Routes())
|
||||
r.Mount("/custom", getCustomRoutes(customServedFolders))
|
||||
}
|
||||
|
||||
customUILocation := c.GetCustomUILocation()
|
||||
|
||||
Reference in New Issue
Block a user