mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Movie group renames (#5039)
* Rename Movie and MoviePartial to Group/GroupPartial * Rename Movie interfaces * Update movie url builders to use group * Rename movieRoutes to groupRoutes * Update dataloader * Update names in sqlite package * Rename in resolvers * Add GroupByURL to scraper config * Scraper backward compatibility hacks
This commit is contained in:
parent
b69d9cc840
commit
15a7b8a859
83 changed files with 1765 additions and 1646 deletions
10
gqlgen.yml
10
gqlgen.yml
|
|
@ -51,11 +51,11 @@ models:
|
|||
fieldName: DurationFinite
|
||||
frame_rate:
|
||||
fieldName: FrameRateFinite
|
||||
# group is movie under the hood
|
||||
Group:
|
||||
model: github.com/stashapp/stash/pkg/models.Movie
|
||||
GroupFilterType:
|
||||
model: github.com/stashapp/stash/pkg/models.MovieFilterType
|
||||
# movie is group under the hood
|
||||
Movie:
|
||||
model: github.com/stashapp/stash/pkg/models.Group
|
||||
MovieFilterType:
|
||||
model: github.com/stashapp/stash/pkg/models.GroupFilterType
|
||||
# autobind on config causes generation issues
|
||||
BlobsStorageType:
|
||||
model: github.com/stashapp/stash/internal/manager/config.BlobsStorageType
|
||||
|
|
|
|||
|
|
@ -346,17 +346,17 @@ func (t changesetTranslator) updateStashIDs(value []models.StashID, field string
|
|||
}
|
||||
}
|
||||
|
||||
func (t changesetTranslator) relatedMovies(value []models.SceneMovieInput) (models.RelatedMovies, error) {
|
||||
moviesScenes, err := models.MoviesScenesFromInput(value)
|
||||
func (t changesetTranslator) relatedGroupsFromMovies(value []models.SceneMovieInput) (models.RelatedGroups, error) {
|
||||
groupsScenes, err := models.GroupsScenesFromInput(value)
|
||||
if err != nil {
|
||||
return models.RelatedMovies{}, err
|
||||
return models.RelatedGroups{}, err
|
||||
}
|
||||
|
||||
return models.NewRelatedMovies(moviesScenes), nil
|
||||
return models.NewRelatedGroups(groupsScenes), nil
|
||||
}
|
||||
|
||||
func moviesScenesFromGroupInput(input []models.SceneGroupInput) ([]models.MoviesScenes, error) {
|
||||
ret := make([]models.MoviesScenes, len(input))
|
||||
func groupsScenesFromGroupInput(input []models.SceneGroupInput) ([]models.GroupsScenes, error) {
|
||||
ret := make([]models.GroupsScenes, len(input))
|
||||
|
||||
for i, v := range input {
|
||||
mID, err := strconv.Atoi(v.GroupID)
|
||||
|
|
@ -364,8 +364,8 @@ func moviesScenesFromGroupInput(input []models.SceneGroupInput) ([]models.Movies
|
|||
return nil, fmt.Errorf("invalid group ID: %s", v.GroupID)
|
||||
}
|
||||
|
||||
ret[i] = models.MoviesScenes{
|
||||
MovieID: mID,
|
||||
ret[i] = models.GroupsScenes{
|
||||
GroupID: mID,
|
||||
SceneIndex: v.SceneIndex,
|
||||
}
|
||||
}
|
||||
|
|
@ -373,48 +373,48 @@ func moviesScenesFromGroupInput(input []models.SceneGroupInput) ([]models.Movies
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) relatedMoviesFromGroups(value []models.SceneGroupInput) (models.RelatedMovies, error) {
|
||||
moviesScenes, err := moviesScenesFromGroupInput(value)
|
||||
func (t changesetTranslator) relatedGroups(value []models.SceneGroupInput) (models.RelatedGroups, error) {
|
||||
groupsScenes, err := groupsScenesFromGroupInput(value)
|
||||
if err != nil {
|
||||
return models.RelatedMovies{}, err
|
||||
return models.RelatedGroups{}, err
|
||||
}
|
||||
|
||||
return models.NewRelatedMovies(moviesScenes), nil
|
||||
return models.NewRelatedGroups(groupsScenes), nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) updateMovieIDs(value []models.SceneMovieInput, field string) (*models.UpdateMovieIDs, error) {
|
||||
func (t changesetTranslator) updateGroupIDsFromMovies(value []models.SceneMovieInput, field string) (*models.UpdateGroupIDs, error) {
|
||||
if !t.hasField(field) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
moviesScenes, err := models.MoviesScenesFromInput(value)
|
||||
groupsScenes, err := models.GroupsScenesFromInput(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.UpdateMovieIDs{
|
||||
Movies: moviesScenes,
|
||||
return &models.UpdateGroupIDs{
|
||||
Groups: groupsScenes,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) updateMovieIDsFromGroups(value []models.SceneGroupInput, field string) (*models.UpdateMovieIDs, error) {
|
||||
func (t changesetTranslator) updateGroupIDs(value []models.SceneGroupInput, field string) (*models.UpdateGroupIDs, error) {
|
||||
if !t.hasField(field) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
moviesScenes, err := moviesScenesFromGroupInput(value)
|
||||
groupsScenes, err := groupsScenesFromGroupInput(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.UpdateMovieIDs{
|
||||
Movies: moviesScenes,
|
||||
return &models.UpdateGroupIDs{
|
||||
Groups: groupsScenes,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) updateMovieIDsBulk(value *BulkUpdateIds, field string) (*models.UpdateMovieIDs, error) {
|
||||
func (t changesetTranslator) updateGroupIDsBulk(value *BulkUpdateIds, field string) (*models.UpdateGroupIDs, error) {
|
||||
if !t.hasField(field) || value == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -424,13 +424,13 @@ func (t changesetTranslator) updateMovieIDsBulk(value *BulkUpdateIds, field stri
|
|||
return nil, fmt.Errorf("converting ids [%v]: %w", value.Ids, err)
|
||||
}
|
||||
|
||||
movies := make([]models.MoviesScenes, len(ids))
|
||||
groups := make([]models.GroupsScenes, len(ids))
|
||||
for i, id := range ids {
|
||||
movies[i] = models.MoviesScenes{MovieID: id}
|
||||
groups[i] = models.GroupsScenes{GroupID: id}
|
||||
}
|
||||
|
||||
return &models.UpdateMovieIDs{
|
||||
Movies: movies,
|
||||
return &models.UpdateGroupIDs{
|
||||
Groups: groups,
|
||||
Mode: value.Mode,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const (
|
|||
performerKey key = iota + 1
|
||||
sceneKey
|
||||
studioKey
|
||||
movieKey
|
||||
groupKey
|
||||
tagKey
|
||||
downloadKey
|
||||
imageKey
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
//go:generate go run github.com/vektah/dataloaden PerformerLoader int *github.com/stashapp/stash/pkg/models.Performer
|
||||
//go:generate go run github.com/vektah/dataloaden StudioLoader int *github.com/stashapp/stash/pkg/models.Studio
|
||||
//go:generate go run github.com/vektah/dataloaden TagLoader int *github.com/stashapp/stash/pkg/models.Tag
|
||||
//go:generate go run github.com/vektah/dataloaden MovieLoader int *github.com/stashapp/stash/pkg/models.Movie
|
||||
//go:generate go run github.com/vektah/dataloaden GroupLoader int *github.com/stashapp/stash/pkg/models.Group
|
||||
//go:generate go run github.com/vektah/dataloaden FileLoader github.com/stashapp/stash/pkg/models.FileID github.com/stashapp/stash/pkg/models.File
|
||||
//go:generate go run github.com/vektah/dataloaden SceneFileIDsLoader int []github.com/stashapp/stash/pkg/models.FileID
|
||||
//go:generate go run github.com/vektah/dataloaden ImageFileIDsLoader int []github.com/stashapp/stash/pkg/models.FileID
|
||||
|
|
@ -52,7 +52,7 @@ type Loaders struct {
|
|||
PerformerByID *PerformerLoader
|
||||
StudioByID *StudioLoader
|
||||
TagByID *TagLoader
|
||||
MovieByID *MovieLoader
|
||||
GroupByID *GroupLoader
|
||||
FileByID *FileLoader
|
||||
}
|
||||
|
||||
|
|
@ -94,10 +94,10 @@ func (m Middleware) Middleware(next http.Handler) http.Handler {
|
|||
maxBatch: maxBatch,
|
||||
fetch: m.fetchTags(ctx),
|
||||
},
|
||||
MovieByID: &MovieLoader{
|
||||
GroupByID: &GroupLoader{
|
||||
wait: wait,
|
||||
maxBatch: maxBatch,
|
||||
fetch: m.fetchMovies(ctx),
|
||||
fetch: m.fetchGroups(ctx),
|
||||
},
|
||||
FileByID: &FileLoader{
|
||||
wait: wait,
|
||||
|
|
@ -232,11 +232,11 @@ 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) {
|
||||
func (m Middleware) fetchGroups(ctx context.Context) func(keys []int) ([]*models.Group, []error) {
|
||||
return func(keys []int) (ret []*models.Group, errs []error) {
|
||||
err := m.Repository.WithDB(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = m.Repository.Movie.FindMany(ctx, keys)
|
||||
ret, err = m.Repository.Group.FindMany(ctx, keys)
|
||||
return err
|
||||
})
|
||||
return ret, toErrorSlice(err)
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
// MovieLoaderConfig captures the config to create a new MovieLoader
|
||||
type MovieLoaderConfig struct {
|
||||
// GroupLoaderConfig captures the config to create a new GroupLoader
|
||||
type GroupLoaderConfig struct {
|
||||
// Fetch is a method that provides the data for the loader
|
||||
Fetch func(keys []int) ([]*models.Movie, []error)
|
||||
Fetch func(keys []int) ([]*models.Group, []error)
|
||||
|
||||
// Wait is how long wait before sending a batch
|
||||
Wait time.Duration
|
||||
|
|
@ -21,19 +21,19 @@ type MovieLoaderConfig struct {
|
|||
MaxBatch int
|
||||
}
|
||||
|
||||
// NewMovieLoader creates a new MovieLoader given a fetch, wait, and maxBatch
|
||||
func NewMovieLoader(config MovieLoaderConfig) *MovieLoader {
|
||||
return &MovieLoader{
|
||||
// NewGroupLoader creates a new GroupLoader given a fetch, wait, and maxBatch
|
||||
func NewGroupLoader(config GroupLoaderConfig) *GroupLoader {
|
||||
return &GroupLoader{
|
||||
fetch: config.Fetch,
|
||||
wait: config.Wait,
|
||||
maxBatch: config.MaxBatch,
|
||||
}
|
||||
}
|
||||
|
||||
// MovieLoader batches and caches requests
|
||||
type MovieLoader struct {
|
||||
// GroupLoader batches and caches requests
|
||||
type GroupLoader struct {
|
||||
// this method provides the data for the loader
|
||||
fetch func(keys []int) ([]*models.Movie, []error)
|
||||
fetch func(keys []int) ([]*models.Group, []error)
|
||||
|
||||
// how long to done before sending a batch
|
||||
wait time.Duration
|
||||
|
|
@ -44,51 +44,51 @@ type MovieLoader struct {
|
|||
// INTERNAL
|
||||
|
||||
// lazily created cache
|
||||
cache map[int]*models.Movie
|
||||
cache map[int]*models.Group
|
||||
|
||||
// the current batch. keys will continue to be collected until timeout is hit,
|
||||
// then everything will be sent to the fetch method and out to the listeners
|
||||
batch *movieLoaderBatch
|
||||
batch *groupLoaderBatch
|
||||
|
||||
// mutex to prevent races
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type movieLoaderBatch struct {
|
||||
type groupLoaderBatch struct {
|
||||
keys []int
|
||||
data []*models.Movie
|
||||
data []*models.Group
|
||||
error []error
|
||||
closing bool
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// Load a Movie by key, batching and caching will be applied automatically
|
||||
func (l *MovieLoader) Load(key int) (*models.Movie, error) {
|
||||
// Load a Group by key, batching and caching will be applied automatically
|
||||
func (l *GroupLoader) Load(key int) (*models.Group, error) {
|
||||
return l.LoadThunk(key)()
|
||||
}
|
||||
|
||||
// LoadThunk returns a function that when called will block waiting for a Movie.
|
||||
// LoadThunk returns a function that when called will block waiting for a Group.
|
||||
// This method should be used if you want one goroutine to make requests to many
|
||||
// different data loaders without blocking until the thunk is called.
|
||||
func (l *MovieLoader) LoadThunk(key int) func() (*models.Movie, error) {
|
||||
func (l *GroupLoader) LoadThunk(key int) func() (*models.Group, error) {
|
||||
l.mu.Lock()
|
||||
if it, ok := l.cache[key]; ok {
|
||||
l.mu.Unlock()
|
||||
return func() (*models.Movie, error) {
|
||||
return func() (*models.Group, error) {
|
||||
return it, nil
|
||||
}
|
||||
}
|
||||
if l.batch == nil {
|
||||
l.batch = &movieLoaderBatch{done: make(chan struct{})}
|
||||
l.batch = &groupLoaderBatch{done: make(chan struct{})}
|
||||
}
|
||||
batch := l.batch
|
||||
pos := batch.keyIndex(l, key)
|
||||
l.mu.Unlock()
|
||||
|
||||
return func() (*models.Movie, error) {
|
||||
return func() (*models.Group, error) {
|
||||
<-batch.done
|
||||
|
||||
var data *models.Movie
|
||||
var data *models.Group
|
||||
if pos < len(batch.data) {
|
||||
data = batch.data[pos]
|
||||
}
|
||||
|
|
@ -113,43 +113,43 @@ func (l *MovieLoader) LoadThunk(key int) func() (*models.Movie, error) {
|
|||
|
||||
// LoadAll fetches many keys at once. It will be broken into appropriate sized
|
||||
// sub batches depending on how the loader is configured
|
||||
func (l *MovieLoader) LoadAll(keys []int) ([]*models.Movie, []error) {
|
||||
results := make([]func() (*models.Movie, error), len(keys))
|
||||
func (l *GroupLoader) LoadAll(keys []int) ([]*models.Group, []error) {
|
||||
results := make([]func() (*models.Group, error), len(keys))
|
||||
|
||||
for i, key := range keys {
|
||||
results[i] = l.LoadThunk(key)
|
||||
}
|
||||
|
||||
movies := make([]*models.Movie, len(keys))
|
||||
groups := make([]*models.Group, len(keys))
|
||||
errors := make([]error, len(keys))
|
||||
for i, thunk := range results {
|
||||
movies[i], errors[i] = thunk()
|
||||
groups[i], errors[i] = thunk()
|
||||
}
|
||||
return movies, errors
|
||||
return groups, errors
|
||||
}
|
||||
|
||||
// LoadAllThunk returns a function that when called will block waiting for a Movies.
|
||||
// LoadAllThunk returns a function that when called will block waiting for a Groups.
|
||||
// This method should be used if you want one goroutine to make requests to many
|
||||
// different data loaders without blocking until the thunk is called.
|
||||
func (l *MovieLoader) LoadAllThunk(keys []int) func() ([]*models.Movie, []error) {
|
||||
results := make([]func() (*models.Movie, error), len(keys))
|
||||
func (l *GroupLoader) LoadAllThunk(keys []int) func() ([]*models.Group, []error) {
|
||||
results := make([]func() (*models.Group, error), len(keys))
|
||||
for i, key := range keys {
|
||||
results[i] = l.LoadThunk(key)
|
||||
}
|
||||
return func() ([]*models.Movie, []error) {
|
||||
movies := make([]*models.Movie, len(keys))
|
||||
return func() ([]*models.Group, []error) {
|
||||
groups := make([]*models.Group, len(keys))
|
||||
errors := make([]error, len(keys))
|
||||
for i, thunk := range results {
|
||||
movies[i], errors[i] = thunk()
|
||||
groups[i], errors[i] = thunk()
|
||||
}
|
||||
return movies, errors
|
||||
return groups, errors
|
||||
}
|
||||
}
|
||||
|
||||
// Prime the cache with the provided key and value. If the key already exists, no change is made
|
||||
// and false is returned.
|
||||
// (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).)
|
||||
func (l *MovieLoader) Prime(key int, value *models.Movie) bool {
|
||||
func (l *GroupLoader) Prime(key int, value *models.Group) bool {
|
||||
l.mu.Lock()
|
||||
var found bool
|
||||
if _, found = l.cache[key]; !found {
|
||||
|
|
@ -163,22 +163,22 @@ func (l *MovieLoader) Prime(key int, value *models.Movie) bool {
|
|||
}
|
||||
|
||||
// Clear the value at key from the cache, if it exists
|
||||
func (l *MovieLoader) Clear(key int) {
|
||||
func (l *GroupLoader) Clear(key int) {
|
||||
l.mu.Lock()
|
||||
delete(l.cache, key)
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
func (l *MovieLoader) unsafeSet(key int, value *models.Movie) {
|
||||
func (l *GroupLoader) unsafeSet(key int, value *models.Group) {
|
||||
if l.cache == nil {
|
||||
l.cache = map[int]*models.Movie{}
|
||||
l.cache = map[int]*models.Group{}
|
||||
}
|
||||
l.cache[key] = value
|
||||
}
|
||||
|
||||
// keyIndex will return the location of the key in the batch, if its not found
|
||||
// it will add the key to the batch
|
||||
func (b *movieLoaderBatch) keyIndex(l *MovieLoader, key int) int {
|
||||
func (b *groupLoaderBatch) keyIndex(l *GroupLoader, key int) int {
|
||||
for i, existingKey := range b.keys {
|
||||
if key == existingKey {
|
||||
return i
|
||||
|
|
@ -202,7 +202,7 @@ func (b *movieLoaderBatch) keyIndex(l *MovieLoader, key int) int {
|
|||
return pos
|
||||
}
|
||||
|
||||
func (b *movieLoaderBatch) startTimer(l *MovieLoader) {
|
||||
func (b *groupLoaderBatch) startTimer(l *GroupLoader) {
|
||||
time.Sleep(l.wait)
|
||||
l.mu.Lock()
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ func (b *movieLoaderBatch) startTimer(l *MovieLoader) {
|
|||
b.end(l)
|
||||
}
|
||||
|
||||
func (b *movieLoaderBatch) end(l *MovieLoader) {
|
||||
func (b *groupLoaderBatch) end(l *GroupLoader) {
|
||||
b.data, b.error = l.fetch(b.keys)
|
||||
close(b.done)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,10 +74,10 @@ func (r *Resolver) Studio() StudioResolver {
|
|||
}
|
||||
|
||||
func (r *Resolver) Group() GroupResolver {
|
||||
return &groupResolver{&movieResolver{r}}
|
||||
return &groupResolver{r}
|
||||
}
|
||||
func (r *Resolver) Movie() MovieResolver {
|
||||
return &movieResolver{r}
|
||||
return &movieResolver{&groupResolver{r}}
|
||||
}
|
||||
|
||||
func (r *Resolver) Subscription() SubscriptionResolver {
|
||||
|
|
@ -117,9 +117,9 @@ type sceneMarkerResolver struct{ *Resolver }
|
|||
type imageResolver struct{ *Resolver }
|
||||
type studioResolver struct{ *Resolver }
|
||||
|
||||
// group is movie under the hood
|
||||
type movieResolver struct{ *Resolver }
|
||||
type groupResolver struct{ *movieResolver }
|
||||
// movie is group under the hood
|
||||
type groupResolver struct{ *Resolver }
|
||||
type movieResolver struct{ *groupResolver }
|
||||
|
||||
type tagResolver struct{ *Resolver }
|
||||
type galleryFileResolver struct{ *Resolver }
|
||||
|
|
@ -182,7 +182,7 @@ func (r *queryResolver) Stats(ctx context.Context) (*StatsResultType, error) {
|
|||
galleryQB := repo.Gallery
|
||||
studioQB := repo.Studio
|
||||
performerQB := repo.Performer
|
||||
movieQB := repo.Movie
|
||||
movieQB := repo.Group
|
||||
tagQB := repo.Tag
|
||||
|
||||
// embrace the error
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
func (r *movieResolver) Date(ctx context.Context, obj *models.Movie) (*string, error) {
|
||||
func (r *groupResolver) Date(ctx context.Context, obj *models.Group) (*string, error) {
|
||||
if obj.Date != nil {
|
||||
result := obj.Date.String()
|
||||
return &result, nil
|
||||
|
|
@ -16,14 +16,14 @@ func (r *movieResolver) Date(ctx context.Context, obj *models.Movie) (*string, e
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) Rating100(ctx context.Context, obj *models.Movie) (*int, error) {
|
||||
func (r *groupResolver) Rating100(ctx context.Context, obj *models.Group) (*int, error) {
|
||||
return obj.Rating, nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) URL(ctx context.Context, obj *models.Movie) (*string, error) {
|
||||
func (r *groupResolver) URL(ctx context.Context, obj *models.Group) (*string, error) {
|
||||
if !obj.URLs.Loaded() {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
return obj.LoadURLs(ctx, r.repository.Movie)
|
||||
return obj.LoadURLs(ctx, r.repository.Group)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -37,10 +37,10 @@ func (r *movieResolver) URL(ctx context.Context, obj *models.Movie) (*string, er
|
|||
return &urls[0], nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) Urls(ctx context.Context, obj *models.Movie) ([]string, error) {
|
||||
func (r *groupResolver) Urls(ctx context.Context, obj *models.Group) ([]string, error) {
|
||||
if !obj.URLs.Loaded() {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
return obj.LoadURLs(ctx, r.repository.Movie)
|
||||
return obj.LoadURLs(ctx, r.repository.Group)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ func (r *movieResolver) Urls(ctx context.Context, obj *models.Movie) ([]string,
|
|||
return obj.URLs.List(), nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) Studio(ctx context.Context, obj *models.Movie) (ret *models.Studio, err error) {
|
||||
func (r *groupResolver) Studio(ctx context.Context, obj *models.Group) (ret *models.Studio, err error) {
|
||||
if obj.StudioID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -57,10 +57,10 @@ func (r *movieResolver) Studio(ctx context.Context, obj *models.Movie) (ret *mod
|
|||
return loaders.From(ctx).StudioByID.Load(*obj.StudioID)
|
||||
}
|
||||
|
||||
func (r movieResolver) Tags(ctx context.Context, obj *models.Movie) (ret []*models.Tag, err error) {
|
||||
func (r groupResolver) Tags(ctx context.Context, obj *models.Group) (ret []*models.Tag, err error) {
|
||||
if !obj.TagIDs.Loaded() {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
return obj.LoadTagIDs(ctx, r.repository.Movie)
|
||||
return obj.LoadTagIDs(ctx, r.repository.Group)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -71,26 +71,26 @@ func (r movieResolver) Tags(ctx context.Context, obj *models.Movie) (ret []*mode
|
|||
return ret, firstError(errs)
|
||||
}
|
||||
|
||||
func (r *movieResolver) FrontImagePath(ctx context.Context, obj *models.Movie) (*string, error) {
|
||||
func (r *groupResolver) FrontImagePath(ctx context.Context, obj *models.Group) (*string, error) {
|
||||
var hasImage bool
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
hasImage, err = r.repository.Movie.HasFrontImage(ctx, obj.ID)
|
||||
hasImage, err = r.repository.Group.HasFrontImage(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
imagePath := urlbuilders.NewMovieURLBuilder(baseURL, obj).GetMovieFrontImageURL(hasImage)
|
||||
imagePath := urlbuilders.NewGroupURLBuilder(baseURL, obj).GetGroupFrontImageURL(hasImage)
|
||||
return &imagePath, nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) BackImagePath(ctx context.Context, obj *models.Movie) (*string, error) {
|
||||
func (r *groupResolver) BackImagePath(ctx context.Context, obj *models.Group) (*string, error) {
|
||||
var hasImage bool
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
hasImage, err = r.repository.Movie.HasBackImage(ctx, obj.ID)
|
||||
hasImage, err = r.repository.Group.HasBackImage(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -102,13 +102,13 @@ func (r *movieResolver) BackImagePath(ctx context.Context, obj *models.Movie) (*
|
|||
}
|
||||
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
imagePath := urlbuilders.NewMovieURLBuilder(baseURL, obj).GetMovieBackImageURL()
|
||||
imagePath := urlbuilders.NewGroupURLBuilder(baseURL, obj).GetGroupBackImageURL()
|
||||
return &imagePath, nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret int, err error) {
|
||||
func (r *groupResolver) SceneCount(ctx context.Context, obj *models.Group) (ret int, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Scene.CountByMovieID(ctx, obj.ID)
|
||||
ret, err = r.repository.Scene.CountByGroupID(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
|
|
@ -117,10 +117,10 @@ func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) Scenes(ctx context.Context, obj *models.Movie) (ret []*models.Scene, err error) {
|
||||
func (r *groupResolver) Scenes(ctx context.Context, obj *models.Group) (ret []*models.Scene, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
ret, err = r.repository.Scene.FindByMovieID(ctx, obj.ID)
|
||||
ret, err = r.repository.Scene.FindByGroupID(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ func (r *performerResolver) GalleryCount(ctx context.Context, obj *models.Perfor
|
|||
|
||||
func (r *performerResolver) GroupCount(ctx context.Context, obj *models.Performer) (ret int, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.CountByPerformerID(ctx, obj.ID)
|
||||
ret, err = r.repository.Group.CountByPerformerID(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
|
|
@ -257,9 +257,9 @@ func (r *performerResolver) DeathDate(ctx context.Context, obj *models.Performer
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Groups(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
||||
func (r *performerResolver) Groups(ctx context.Context, obj *models.Performer) (ret []*models.Group, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.FindByPerformerID(ctx, obj.ID)
|
||||
ret, err = r.repository.Group.FindByPerformerID(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -269,6 +269,6 @@ func (r *performerResolver) Groups(ctx context.Context, obj *models.Performer) (
|
|||
}
|
||||
|
||||
// deprecated
|
||||
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
||||
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Group, err error) {
|
||||
return r.Groups(ctx, obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,20 +184,20 @@ func (r *sceneResolver) Studio(ctx context.Context, obj *models.Scene) (ret *mod
|
|||
}
|
||||
|
||||
func (r *sceneResolver) Movies(ctx context.Context, obj *models.Scene) (ret []*SceneMovie, err error) {
|
||||
if !obj.Movies.Loaded() {
|
||||
if !obj.Groups.Loaded() {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Scene
|
||||
|
||||
return obj.LoadMovies(ctx, qb)
|
||||
return obj.LoadGroups(ctx, qb)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
loader := loaders.From(ctx).MovieByID
|
||||
loader := loaders.From(ctx).GroupByID
|
||||
|
||||
for _, sm := range obj.Movies.List() {
|
||||
movie, err := loader.Load(sm.MovieID)
|
||||
for _, sm := range obj.Groups.List() {
|
||||
movie, err := loader.Load(sm.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -215,27 +215,27 @@ func (r *sceneResolver) Movies(ctx context.Context, obj *models.Scene) (ret []*S
|
|||
}
|
||||
|
||||
func (r *sceneResolver) Groups(ctx context.Context, obj *models.Scene) (ret []*SceneGroup, err error) {
|
||||
if !obj.Movies.Loaded() {
|
||||
if !obj.Groups.Loaded() {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Scene
|
||||
|
||||
return obj.LoadMovies(ctx, qb)
|
||||
return obj.LoadGroups(ctx, qb)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
loader := loaders.From(ctx).MovieByID
|
||||
loader := loaders.From(ctx).GroupByID
|
||||
|
||||
for _, sm := range obj.Movies.List() {
|
||||
movie, err := loader.Load(sm.MovieID)
|
||||
for _, sm := range obj.Groups.List() {
|
||||
group, err := loader.Load(sm.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sceneIdx := sm.SceneIndex
|
||||
sceneGroup := &SceneGroup{
|
||||
Group: movie,
|
||||
Group: group,
|
||||
SceneIndex: sceneIdx,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func (r *studioResolver) PerformerCount(ctx context.Context, obj *models.Studio,
|
|||
|
||||
func (r *studioResolver) GroupCount(ctx context.Context, obj *models.Studio, depth *int) (ret int, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = movie.CountByStudioID(ctx, r.repository.Movie, obj.ID, depth)
|
||||
ret, err = movie.CountByStudioID(ctx, r.repository.Group, obj.ID, depth)
|
||||
return err
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
|
|
@ -149,9 +149,9 @@ func (r *studioResolver) Rating100(ctx context.Context, obj *models.Studio) (*in
|
|||
return obj.Rating, nil
|
||||
}
|
||||
|
||||
func (r *studioResolver) Groups(ctx context.Context, obj *models.Studio) (ret []*models.Movie, err error) {
|
||||
func (r *studioResolver) Groups(ctx context.Context, obj *models.Studio) (ret []*models.Group, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.FindByStudioID(ctx, obj.ID)
|
||||
ret, err = r.repository.Group.FindByStudioID(ctx, obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -161,6 +161,6 @@ func (r *studioResolver) Groups(ctx context.Context, obj *models.Studio) (ret []
|
|||
}
|
||||
|
||||
// deprecated
|
||||
func (r *studioResolver) Movies(ctx context.Context, obj *models.Studio) (ret []*models.Movie, err error) {
|
||||
func (r *studioResolver) Movies(ctx context.Context, obj *models.Studio) (ret []*models.Group, err error) {
|
||||
return r.Groups(ctx, obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ func (r *tagResolver) StudioCount(ctx context.Context, obj *models.Tag, depth *i
|
|||
|
||||
func (r *tagResolver) GroupCount(ctx context.Context, obj *models.Tag, depth *int) (ret int, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = movie.CountByTagID(ctx, r.repository.Movie, obj.ID, depth)
|
||||
ret, err = movie.CountByTagID(ctx, r.repository.Group, obj.ID, depth)
|
||||
return err
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -12,46 +12,46 @@ import (
|
|||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
func movieFromGroupCreateInput(ctx context.Context, input GroupCreateInput) (*models.Movie, error) {
|
||||
func groupFromGroupCreateInput(ctx context.Context, input GroupCreateInput) (*models.Group, error) {
|
||||
translator := changesetTranslator{
|
||||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate a new movie from the input
|
||||
newMovie := models.NewMovie()
|
||||
// Populate a new group from the input
|
||||
newGroup := models.NewGroup()
|
||||
|
||||
newMovie.Name = input.Name
|
||||
newMovie.Aliases = translator.string(input.Aliases)
|
||||
newMovie.Duration = input.Duration
|
||||
newMovie.Rating = input.Rating100
|
||||
newMovie.Director = translator.string(input.Director)
|
||||
newMovie.Synopsis = translator.string(input.Synopsis)
|
||||
newGroup.Name = input.Name
|
||||
newGroup.Aliases = translator.string(input.Aliases)
|
||||
newGroup.Duration = input.Duration
|
||||
newGroup.Rating = input.Rating100
|
||||
newGroup.Director = translator.string(input.Director)
|
||||
newGroup.Synopsis = translator.string(input.Synopsis)
|
||||
|
||||
var err error
|
||||
|
||||
newMovie.Date, err = translator.datePtr(input.Date)
|
||||
newGroup.Date, err = translator.datePtr(input.Date)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting date: %w", err)
|
||||
}
|
||||
newMovie.StudioID, err = translator.intPtrFromString(input.StudioID)
|
||||
newGroup.StudioID, err = translator.intPtrFromString(input.StudioID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting studio id: %w", err)
|
||||
}
|
||||
|
||||
newMovie.TagIDs, err = translator.relatedIds(input.TagIds)
|
||||
newGroup.TagIDs, err = translator.relatedIds(input.TagIds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
if input.Urls != nil {
|
||||
newMovie.URLs = models.NewRelatedStrings(input.Urls)
|
||||
newGroup.URLs = models.NewRelatedStrings(input.Urls)
|
||||
}
|
||||
|
||||
return &newMovie, nil
|
||||
return &newGroup, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) GroupCreate(ctx context.Context, input GroupCreateInput) (*models.Movie, error) {
|
||||
newMovie, err := movieFromGroupCreateInput(ctx, input)
|
||||
func (r *mutationResolver) GroupCreate(ctx context.Context, input GroupCreateInput) (*models.Group, error) {
|
||||
newGroup, err := groupFromGroupCreateInput(ctx, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -77,27 +77,27 @@ func (r *mutationResolver) GroupCreate(ctx context.Context, input GroupCreateInp
|
|||
// 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)
|
||||
frontimageData = static.ReadAll(static.DefaultGroupImage)
|
||||
}
|
||||
|
||||
// Start the transaction and save the movie
|
||||
// Start the transaction and save the group
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
qb := r.repository.Group
|
||||
|
||||
err = qb.Create(ctx, newMovie)
|
||||
err = qb.Create(ctx, newGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update image table
|
||||
if len(frontimageData) > 0 {
|
||||
if err := qb.UpdateFrontImage(ctx, newMovie.ID, frontimageData); err != nil {
|
||||
if err := qb.UpdateFrontImage(ctx, newGroup.ID, frontimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(backimageData) > 0 {
|
||||
if err := qb.UpdateBackImage(ctx, newMovie.ID, backimageData); err != nil {
|
||||
if err := qb.UpdateBackImage(ctx, newGroup.ID, backimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -108,46 +108,46 @@ func (r *mutationResolver) GroupCreate(ctx context.Context, input GroupCreateInp
|
|||
}
|
||||
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newMovie.ID, hook.GroupCreatePost, input, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newMovie.ID, hook.MovieCreatePost, input, nil)
|
||||
return r.getMovie(ctx, newMovie.ID)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newGroup.ID, hook.GroupCreatePost, input, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newGroup.ID, hook.MovieCreatePost, input, nil)
|
||||
return r.getGroup(ctx, newGroup.ID)
|
||||
}
|
||||
|
||||
func moviePartialFromGroupUpdateInput(translator changesetTranslator, input GroupUpdateInput) (ret models.MoviePartial, err error) {
|
||||
// Populate movie from the input
|
||||
updatedMovie := models.NewMoviePartial()
|
||||
func groupPartialFromGroupUpdateInput(translator changesetTranslator, input GroupUpdateInput) (ret models.GroupPartial, err error) {
|
||||
// Populate group from the input
|
||||
updatedGroup := models.NewGroupPartial()
|
||||
|
||||
updatedMovie.Name = translator.optionalString(input.Name, "name")
|
||||
updatedMovie.Aliases = translator.optionalString(input.Aliases, "aliases")
|
||||
updatedMovie.Duration = translator.optionalInt(input.Duration, "duration")
|
||||
updatedMovie.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedMovie.Director = translator.optionalString(input.Director, "director")
|
||||
updatedMovie.Synopsis = translator.optionalString(input.Synopsis, "synopsis")
|
||||
updatedGroup.Name = translator.optionalString(input.Name, "name")
|
||||
updatedGroup.Aliases = translator.optionalString(input.Aliases, "aliases")
|
||||
updatedGroup.Duration = translator.optionalInt(input.Duration, "duration")
|
||||
updatedGroup.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedGroup.Director = translator.optionalString(input.Director, "director")
|
||||
updatedGroup.Synopsis = translator.optionalString(input.Synopsis, "synopsis")
|
||||
|
||||
updatedMovie.Date, err = translator.optionalDate(input.Date, "date")
|
||||
updatedGroup.Date, err = translator.optionalDate(input.Date, "date")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("converting date: %w", err)
|
||||
return
|
||||
}
|
||||
updatedMovie.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
updatedGroup.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("converting studio id: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
updatedMovie.TagIDs, err = translator.updateIds(input.TagIds, "tag_ids")
|
||||
updatedGroup.TagIDs, err = translator.updateIds(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("converting tag ids: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
updatedMovie.URLs = translator.updateStrings(input.Urls, "urls")
|
||||
updatedGroup.URLs = translator.updateStrings(input.Urls, "urls")
|
||||
|
||||
return updatedMovie, nil
|
||||
return updatedGroup, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) GroupUpdate(ctx context.Context, input GroupUpdateInput) (*models.Movie, error) {
|
||||
movieID, err := strconv.Atoi(input.ID)
|
||||
func (r *mutationResolver) GroupUpdate(ctx context.Context, input GroupUpdateInput) (*models.Group, error) {
|
||||
groupID, err := strconv.Atoi(input.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting id: %w", err)
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ func (r *mutationResolver) GroupUpdate(ctx context.Context, input GroupUpdateInp
|
|||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
updatedMovie, err := moviePartialFromGroupUpdateInput(translator, input)
|
||||
updatedGroup, err := groupPartialFromGroupUpdateInput(translator, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -179,24 +179,24 @@ func (r *mutationResolver) GroupUpdate(ctx context.Context, input GroupUpdateInp
|
|||
}
|
||||
}
|
||||
|
||||
// Start the transaction and save the movie
|
||||
var movie *models.Movie
|
||||
// Start the transaction and save the group
|
||||
var group *models.Group
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
movie, err = qb.UpdatePartial(ctx, movieID, updatedMovie)
|
||||
qb := r.repository.Group
|
||||
group, err = qb.UpdatePartial(ctx, groupID, updatedGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update image table
|
||||
if frontImageIncluded {
|
||||
if err := qb.UpdateFrontImage(ctx, movie.ID, frontimageData); err != nil {
|
||||
if err := qb.UpdateFrontImage(ctx, group.ID, frontimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if backImageIncluded {
|
||||
if err := qb.UpdateBackImage(ctx, movie.ID, backimageData); err != nil {
|
||||
if err := qb.UpdateBackImage(ctx, group.ID, backimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -207,36 +207,36 @@ func (r *mutationResolver) GroupUpdate(ctx context.Context, input GroupUpdateInp
|
|||
}
|
||||
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
return r.getMovie(ctx, movie.ID)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
return r.getGroup(ctx, group.ID)
|
||||
}
|
||||
|
||||
func moviePartialFromBulkGroupUpdateInput(translator changesetTranslator, input BulkGroupUpdateInput) (ret models.MoviePartial, err error) {
|
||||
updatedMovie := models.NewMoviePartial()
|
||||
func groupPartialFromBulkGroupUpdateInput(translator changesetTranslator, input BulkGroupUpdateInput) (ret models.GroupPartial, err error) {
|
||||
updatedGroup := models.NewGroupPartial()
|
||||
|
||||
updatedMovie.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedMovie.Director = translator.optionalString(input.Director, "director")
|
||||
updatedGroup.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedGroup.Director = translator.optionalString(input.Director, "director")
|
||||
|
||||
updatedMovie.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
updatedGroup.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("converting studio id: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
updatedMovie.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids")
|
||||
updatedGroup.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("converting tag ids: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
updatedMovie.URLs = translator.optionalURLsBulk(input.Urls, nil)
|
||||
updatedGroup.URLs = translator.optionalURLsBulk(input.Urls, nil)
|
||||
|
||||
return updatedMovie, nil
|
||||
return updatedGroup, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) BulkGroupUpdate(ctx context.Context, input BulkGroupUpdateInput) ([]*models.Movie, error) {
|
||||
movieIDs, err := stringslice.StringSliceToIntSlice(input.Ids)
|
||||
func (r *mutationResolver) BulkGroupUpdate(ctx context.Context, input BulkGroupUpdateInput) ([]*models.Group, error) {
|
||||
groupIDs, err := stringslice.StringSliceToIntSlice(input.Ids)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting ids: %w", err)
|
||||
}
|
||||
|
|
@ -245,24 +245,24 @@ func (r *mutationResolver) BulkGroupUpdate(ctx context.Context, input BulkGroupU
|
|||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate movie from the input
|
||||
updatedMovie, err := moviePartialFromBulkGroupUpdateInput(translator, input)
|
||||
// Populate group from the input
|
||||
updatedGroup, err := groupPartialFromBulkGroupUpdateInput(translator, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := []*models.Movie{}
|
||||
ret := []*models.Group{}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
qb := r.repository.Group
|
||||
|
||||
for _, movieID := range movieIDs {
|
||||
movie, err := qb.UpdatePartial(ctx, movieID, updatedMovie)
|
||||
for _, groupID := range groupIDs {
|
||||
group, err := qb.UpdatePartial(ctx, groupID, updatedGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = append(ret, movie)
|
||||
ret = append(ret, group)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -270,18 +270,18 @@ func (r *mutationResolver) BulkGroupUpdate(ctx context.Context, input BulkGroupU
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var newRet []*models.Movie
|
||||
for _, movie := range ret {
|
||||
var newRet []*models.Group
|
||||
for _, group := range ret {
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
|
||||
movie, err = r.getMovie(ctx, movie.ID)
|
||||
group, err = r.getGroup(ctx, group.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newRet = append(newRet, movie)
|
||||
newRet = append(newRet, group)
|
||||
}
|
||||
|
||||
return newRet, nil
|
||||
|
|
@ -294,7 +294,7 @@ func (r *mutationResolver) GroupDestroy(ctx context.Context, input GroupDestroyI
|
|||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
return r.repository.Movie.Destroy(ctx, id)
|
||||
return r.repository.Group.Destroy(ctx, id)
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ func (r *mutationResolver) GroupsDestroy(ctx context.Context, groupIDs []string)
|
|||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
qb := r.repository.Group
|
||||
for _, id := range ids {
|
||||
if err := qb.Destroy(ctx, id); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import (
|
|||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
// used to refetch movie after hooks run
|
||||
func (r *mutationResolver) getMovie(ctx context.Context, id int) (ret *models.Movie, err error) {
|
||||
// used to refetch group after hooks run
|
||||
func (r *mutationResolver) getGroup(ctx context.Context, id int) (ret *models.Group, err error) {
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.Find(ctx, id)
|
||||
ret, err = r.repository.Group.Find(ctx, id)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -24,41 +24,41 @@ func (r *mutationResolver) getMovie(ctx context.Context, id int) (ret *models.Mo
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInput) (*models.Movie, error) {
|
||||
func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInput) (*models.Group, error) {
|
||||
translator := changesetTranslator{
|
||||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate a new movie from the input
|
||||
newMovie := models.NewMovie()
|
||||
// Populate a new group from the input
|
||||
newGroup := models.NewGroup()
|
||||
|
||||
newMovie.Name = input.Name
|
||||
newMovie.Aliases = translator.string(input.Aliases)
|
||||
newMovie.Duration = input.Duration
|
||||
newMovie.Rating = input.Rating100
|
||||
newMovie.Director = translator.string(input.Director)
|
||||
newMovie.Synopsis = translator.string(input.Synopsis)
|
||||
newGroup.Name = input.Name
|
||||
newGroup.Aliases = translator.string(input.Aliases)
|
||||
newGroup.Duration = input.Duration
|
||||
newGroup.Rating = input.Rating100
|
||||
newGroup.Director = translator.string(input.Director)
|
||||
newGroup.Synopsis = translator.string(input.Synopsis)
|
||||
|
||||
var err error
|
||||
|
||||
newMovie.Date, err = translator.datePtr(input.Date)
|
||||
newGroup.Date, err = translator.datePtr(input.Date)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting date: %w", err)
|
||||
}
|
||||
newMovie.StudioID, err = translator.intPtrFromString(input.StudioID)
|
||||
newGroup.StudioID, err = translator.intPtrFromString(input.StudioID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting studio id: %w", err)
|
||||
}
|
||||
|
||||
newMovie.TagIDs, err = translator.relatedIds(input.TagIds)
|
||||
newGroup.TagIDs, err = translator.relatedIds(input.TagIds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
if input.Urls != nil {
|
||||
newMovie.URLs = models.NewRelatedStrings(input.Urls)
|
||||
newGroup.URLs = models.NewRelatedStrings(input.Urls)
|
||||
} else if input.URL != nil {
|
||||
newMovie.URLs = models.NewRelatedStrings([]string{*input.URL})
|
||||
newGroup.URLs = models.NewRelatedStrings([]string{*input.URL})
|
||||
}
|
||||
|
||||
// Process the base 64 encoded image string
|
||||
|
|
@ -82,27 +82,27 @@ 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)
|
||||
frontimageData = static.ReadAll(static.DefaultGroupImage)
|
||||
}
|
||||
|
||||
// Start the transaction and save the movie
|
||||
// Start the transaction and save the group
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
qb := r.repository.Group
|
||||
|
||||
err = qb.Create(ctx, &newMovie)
|
||||
err = qb.Create(ctx, &newGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update image table
|
||||
if len(frontimageData) > 0 {
|
||||
if err := qb.UpdateFrontImage(ctx, newMovie.ID, frontimageData); err != nil {
|
||||
if err := qb.UpdateFrontImage(ctx, newGroup.ID, frontimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(backimageData) > 0 {
|
||||
if err := qb.UpdateBackImage(ctx, newMovie.ID, backimageData); err != nil {
|
||||
if err := qb.UpdateBackImage(ctx, newGroup.ID, backimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -113,13 +113,13 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
|
|||
}
|
||||
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newMovie.ID, hook.GroupCreatePost, input, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newMovie.ID, hook.MovieCreatePost, input, nil)
|
||||
return r.getMovie(ctx, newMovie.ID)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newGroup.ID, hook.GroupCreatePost, input, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, newGroup.ID, hook.MovieCreatePost, input, nil)
|
||||
return r.getGroup(ctx, newGroup.ID)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInput) (*models.Movie, error) {
|
||||
movieID, err := strconv.Atoi(input.ID)
|
||||
func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInput) (*models.Group, error) {
|
||||
groupID, err := strconv.Atoi(input.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting id: %w", err)
|
||||
}
|
||||
|
|
@ -128,31 +128,31 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInp
|
|||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate movie from the input
|
||||
updatedMovie := models.NewMoviePartial()
|
||||
// Populate group from the input
|
||||
updatedGroup := models.NewGroupPartial()
|
||||
|
||||
updatedMovie.Name = translator.optionalString(input.Name, "name")
|
||||
updatedMovie.Aliases = translator.optionalString(input.Aliases, "aliases")
|
||||
updatedMovie.Duration = translator.optionalInt(input.Duration, "duration")
|
||||
updatedMovie.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedMovie.Director = translator.optionalString(input.Director, "director")
|
||||
updatedMovie.Synopsis = translator.optionalString(input.Synopsis, "synopsis")
|
||||
updatedGroup.Name = translator.optionalString(input.Name, "name")
|
||||
updatedGroup.Aliases = translator.optionalString(input.Aliases, "aliases")
|
||||
updatedGroup.Duration = translator.optionalInt(input.Duration, "duration")
|
||||
updatedGroup.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedGroup.Director = translator.optionalString(input.Director, "director")
|
||||
updatedGroup.Synopsis = translator.optionalString(input.Synopsis, "synopsis")
|
||||
|
||||
updatedMovie.Date, err = translator.optionalDate(input.Date, "date")
|
||||
updatedGroup.Date, err = translator.optionalDate(input.Date, "date")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting date: %w", err)
|
||||
}
|
||||
updatedMovie.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
updatedGroup.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting studio id: %w", err)
|
||||
}
|
||||
|
||||
updatedMovie.TagIDs, err = translator.updateIds(input.TagIds, "tag_ids")
|
||||
updatedGroup.TagIDs, err = translator.updateIds(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
updatedMovie.URLs = translator.optionalURLs(input.Urls, input.URL)
|
||||
updatedGroup.URLs = translator.optionalURLs(input.Urls, input.URL)
|
||||
|
||||
var frontimageData []byte
|
||||
frontImageIncluded := translator.hasField("front_image")
|
||||
|
|
@ -172,24 +172,24 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInp
|
|||
}
|
||||
}
|
||||
|
||||
// Start the transaction and save the movie
|
||||
var movie *models.Movie
|
||||
// Start the transaction and save the group
|
||||
var group *models.Group
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
movie, err = qb.UpdatePartial(ctx, movieID, updatedMovie)
|
||||
qb := r.repository.Group
|
||||
group, err = qb.UpdatePartial(ctx, groupID, updatedGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update image table
|
||||
if frontImageIncluded {
|
||||
if err := qb.UpdateFrontImage(ctx, movie.ID, frontimageData); err != nil {
|
||||
if err := qb.UpdateFrontImage(ctx, group.ID, frontimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if backImageIncluded {
|
||||
if err := qb.UpdateBackImage(ctx, movie.ID, backimageData); err != nil {
|
||||
if err := qb.UpdateBackImage(ctx, group.ID, backimageData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -200,13 +200,13 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInp
|
|||
}
|
||||
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
return r.getMovie(ctx, movie.ID)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
return r.getGroup(ctx, group.ID)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) BulkMovieUpdate(ctx context.Context, input BulkMovieUpdateInput) ([]*models.Movie, error) {
|
||||
movieIDs, err := stringslice.StringSliceToIntSlice(input.Ids)
|
||||
func (r *mutationResolver) BulkMovieUpdate(ctx context.Context, input BulkMovieUpdateInput) ([]*models.Group, error) {
|
||||
groupIDs, err := stringslice.StringSliceToIntSlice(input.Ids)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting ids: %w", err)
|
||||
}
|
||||
|
|
@ -215,36 +215,36 @@ func (r *mutationResolver) BulkMovieUpdate(ctx context.Context, input BulkMovieU
|
|||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate movie from the input
|
||||
updatedMovie := models.NewMoviePartial()
|
||||
// Populate group from the input
|
||||
updatedGroup := models.NewGroupPartial()
|
||||
|
||||
updatedMovie.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedMovie.Director = translator.optionalString(input.Director, "director")
|
||||
updatedGroup.Rating = translator.optionalInt(input.Rating100, "rating100")
|
||||
updatedGroup.Director = translator.optionalString(input.Director, "director")
|
||||
|
||||
updatedMovie.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
updatedGroup.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting studio id: %w", err)
|
||||
}
|
||||
|
||||
updatedMovie.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids")
|
||||
updatedGroup.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
updatedMovie.URLs = translator.optionalURLsBulk(input.Urls, nil)
|
||||
updatedGroup.URLs = translator.optionalURLsBulk(input.Urls, nil)
|
||||
|
||||
ret := []*models.Movie{}
|
||||
ret := []*models.Group{}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
qb := r.repository.Group
|
||||
|
||||
for _, movieID := range movieIDs {
|
||||
movie, err := qb.UpdatePartial(ctx, movieID, updatedMovie)
|
||||
for _, groupID := range groupIDs {
|
||||
group, err := qb.UpdatePartial(ctx, groupID, updatedGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = append(ret, movie)
|
||||
ret = append(ret, group)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -252,18 +252,18 @@ func (r *mutationResolver) BulkMovieUpdate(ctx context.Context, input BulkMovieU
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var newRet []*models.Movie
|
||||
for _, movie := range ret {
|
||||
var newRet []*models.Group
|
||||
for _, group := range ret {
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.GroupUpdatePost, input, translator.getFields())
|
||||
r.hookExecutor.ExecutePostHooks(ctx, group.ID, hook.MovieUpdatePost, input, translator.getFields())
|
||||
|
||||
movie, err = r.getMovie(ctx, movie.ID)
|
||||
group, err = r.getGroup(ctx, group.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newRet = append(newRet, movie)
|
||||
newRet = append(newRet, group)
|
||||
}
|
||||
|
||||
return newRet, nil
|
||||
|
|
@ -276,7 +276,7 @@ func (r *mutationResolver) MovieDestroy(ctx context.Context, input MovieDestroyI
|
|||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
return r.repository.Movie.Destroy(ctx, id)
|
||||
return r.repository.Group.Destroy(ctx, id)
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -288,14 +288,14 @@ func (r *mutationResolver) MovieDestroy(ctx context.Context, input MovieDestroyI
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) MoviesDestroy(ctx context.Context, movieIDs []string) (bool, error) {
|
||||
ids, err := stringslice.StringSliceToIntSlice(movieIDs)
|
||||
func (r *mutationResolver) MoviesDestroy(ctx context.Context, groupIDs []string) (bool, error) {
|
||||
ids, err := stringslice.StringSliceToIntSlice(groupIDs)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("converting ids: %w", err)
|
||||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Movie
|
||||
qb := r.repository.Group
|
||||
for _, id := range ids {
|
||||
if err := qb.Destroy(ctx, id); err != nil {
|
||||
return err
|
||||
|
|
@ -309,8 +309,8 @@ func (r *mutationResolver) MoviesDestroy(ctx context.Context, movieIDs []string)
|
|||
|
||||
for _, id := range ids {
|
||||
// for backwards compatibility - run both movie and group hooks
|
||||
r.hookExecutor.ExecutePostHooks(ctx, id, hook.GroupDestroyPost, movieIDs, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, id, hook.MovieDestroyPost, movieIDs, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, id, hook.GroupDestroyPost, groupIDs, nil)
|
||||
r.hookExecutor.ExecutePostHooks(ctx, id, hook.MovieDestroyPost, groupIDs, nil)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
|
|
|||
|
|
@ -82,12 +82,12 @@ func (r *mutationResolver) SceneCreate(ctx context.Context, input models.SceneCr
|
|||
|
||||
// prefer groups over movies
|
||||
if len(input.Groups) > 0 {
|
||||
newScene.Movies, err = translator.relatedMoviesFromGroups(input.Groups)
|
||||
newScene.Groups, err = translator.relatedGroups(input.Groups)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting groups: %w", err)
|
||||
}
|
||||
} else if len(input.Movies) > 0 {
|
||||
newScene.Movies, err = translator.relatedMovies(input.Movies)
|
||||
newScene.Groups, err = translator.relatedGroupsFromMovies(input.Movies)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting movies: %w", err)
|
||||
}
|
||||
|
|
@ -225,12 +225,12 @@ func scenePartialFromInput(input models.SceneUpdateInput, translator changesetTr
|
|||
}
|
||||
|
||||
if translator.hasField("groups") {
|
||||
updatedScene.MovieIDs, err = translator.updateMovieIDsFromGroups(input.Groups, "groups")
|
||||
updatedScene.GroupIDs, err = translator.updateGroupIDs(input.Groups, "groups")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting movies: %w", err)
|
||||
return nil, fmt.Errorf("converting groups: %w", err)
|
||||
}
|
||||
} else if translator.hasField("movies") {
|
||||
updatedScene.MovieIDs, err = translator.updateMovieIDs(input.Movies, "movies")
|
||||
updatedScene.GroupIDs, err = translator.updateGroupIDsFromMovies(input.Movies, "movies")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting movies: %w", err)
|
||||
}
|
||||
|
|
@ -374,12 +374,12 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input BulkSceneU
|
|||
}
|
||||
|
||||
if translator.hasField("groups") {
|
||||
updatedScene.MovieIDs, err = translator.updateMovieIDsBulk(input.GroupIds, "group_ids")
|
||||
updatedScene.GroupIDs, err = translator.updateGroupIDsBulk(input.GroupIds, "group_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting group ids: %w", err)
|
||||
}
|
||||
} else if translator.hasField("movies") {
|
||||
updatedScene.MovieIDs, err = translator.updateMovieIDsBulk(input.MovieIds, "movie_ids")
|
||||
updatedScene.GroupIDs, err = translator.updateGroupIDsBulk(input.MovieIds, "movie_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting movie ids: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ import (
|
|||
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindGroup(ctx context.Context, id string) (ret *models.Movie, err error) {
|
||||
func (r *queryResolver) FindGroup(ctx context.Context, id string) (ret *models.Group, err error) {
|
||||
idInt, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.Find(ctx, idInt)
|
||||
ret, err = r.repository.Group.Find(ctx, idInt)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -24,22 +24,22 @@ func (r *queryResolver) FindGroup(ctx context.Context, id string) (ret *models.M
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindGroups(ctx context.Context, movieFilter *models.MovieFilterType, filter *models.FindFilterType, ids []string) (ret *FindGroupsResultType, err error) {
|
||||
func (r *queryResolver) FindGroups(ctx context.Context, groupFilter *models.GroupFilterType, filter *models.FindFilterType, ids []string) (ret *FindGroupsResultType, err error) {
|
||||
idInts, err := stringslice.StringSliceToIntSlice(ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
var movies []*models.Movie
|
||||
var groups []*models.Group
|
||||
var err error
|
||||
var total int
|
||||
|
||||
if len(idInts) > 0 {
|
||||
movies, err = r.repository.Movie.FindMany(ctx, idInts)
|
||||
total = len(movies)
|
||||
groups, err = r.repository.Group.FindMany(ctx, idInts)
|
||||
total = len(groups)
|
||||
} else {
|
||||
movies, total, err = r.repository.Movie.Query(ctx, movieFilter, filter)
|
||||
groups, total, err = r.repository.Group.Query(ctx, groupFilter, filter)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -48,7 +48,7 @@ func (r *queryResolver) FindGroups(ctx context.Context, movieFilter *models.Movi
|
|||
|
||||
ret = &FindGroupsResultType{
|
||||
Count: total,
|
||||
Groups: movies,
|
||||
Groups: groups,
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ import (
|
|||
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindMovie(ctx context.Context, id string) (ret *models.Movie, err error) {
|
||||
func (r *queryResolver) FindMovie(ctx context.Context, id string) (ret *models.Group, err error) {
|
||||
idInt, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.Find(ctx, idInt)
|
||||
ret, err = r.repository.Group.Find(ctx, idInt)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -24,22 +24,22 @@ func (r *queryResolver) FindMovie(ctx context.Context, id string) (ret *models.M
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.MovieFilterType, filter *models.FindFilterType, ids []string) (ret *FindMoviesResultType, err error) {
|
||||
func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.GroupFilterType, filter *models.FindFilterType, ids []string) (ret *FindMoviesResultType, err error) {
|
||||
idInts, err := stringslice.StringSliceToIntSlice(ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
var movies []*models.Movie
|
||||
var groups []*models.Group
|
||||
var err error
|
||||
var total int
|
||||
|
||||
if len(idInts) > 0 {
|
||||
movies, err = r.repository.Movie.FindMany(ctx, idInts)
|
||||
total = len(movies)
|
||||
groups, err = r.repository.Group.FindMany(ctx, idInts)
|
||||
total = len(groups)
|
||||
} else {
|
||||
movies, total, err = r.repository.Movie.Query(ctx, movieFilter, filter)
|
||||
groups, total, err = r.repository.Group.Query(ctx, movieFilter, filter)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -48,7 +48,7 @@ func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.Movi
|
|||
|
||||
ret = &FindMoviesResultType{
|
||||
Count: total,
|
||||
Movies: movies,
|
||||
Movies: groups,
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
|
@ -58,9 +58,9 @@ func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.Movi
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) AllMovies(ctx context.Context) (ret []*models.Movie, err error) {
|
||||
func (r *queryResolver) AllMovies(ctx context.Context) (ret []*models.Group, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Movie.All(ctx)
|
||||
ret, err = r.repository.Group.All(ctx)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -144,8 +144,8 @@ func filterPerformerTags(p []*models.ScrapedPerformer) {
|
|||
}
|
||||
}
|
||||
|
||||
// filterMovieTags removes tags matching excluded tag patterns from the provided scraped movies
|
||||
func filterMovieTags(p []*models.ScrapedMovie) {
|
||||
// filterGroupTags removes tags matching excluded tag patterns from the provided scraped movies
|
||||
func filterGroupTags(p []*models.ScrapedMovie) {
|
||||
excludeRegexps := compileRegexps(manager.GetInstance().Config.GetScraperExcludeTagPatterns())
|
||||
|
||||
var ignoredTags []string
|
||||
|
|
@ -208,7 +208,7 @@ func (r *queryResolver) ScrapeMovieURL(ctx context.Context, url string) (*models
|
|||
return nil, err
|
||||
}
|
||||
|
||||
filterMovieTags([]*models.ScrapedMovie{ret})
|
||||
filterGroupTags([]*models.ScrapedMovie{ret})
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ func (r *queryResolver) ScrapeGroupURL(ctx context.Context, url string) (*models
|
|||
return nil, err
|
||||
}
|
||||
|
||||
filterMovieTags([]*models.ScrapedMovie{ret})
|
||||
filterGroupTags([]*models.ScrapedMovie{ret})
|
||||
|
||||
// convert to scraped group
|
||||
group := &models.ScrapedGroup{
|
||||
|
|
|
|||
|
|
@ -14,22 +14,22 @@ import (
|
|||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
type MovieFinder interface {
|
||||
models.MovieGetter
|
||||
GetFrontImage(ctx context.Context, movieID int) ([]byte, error)
|
||||
GetBackImage(ctx context.Context, movieID int) ([]byte, error)
|
||||
type GroupFinder interface {
|
||||
models.GroupGetter
|
||||
GetFrontImage(ctx context.Context, groupID int) ([]byte, error)
|
||||
GetBackImage(ctx context.Context, groupID int) ([]byte, error)
|
||||
}
|
||||
|
||||
type movieRoutes struct {
|
||||
type groupRoutes struct {
|
||||
routes
|
||||
movieFinder MovieFinder
|
||||
groupFinder GroupFinder
|
||||
}
|
||||
|
||||
func (rs movieRoutes) Routes() chi.Router {
|
||||
func (rs groupRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Route("/{movieId}", func(r chi.Router) {
|
||||
r.Use(rs.MovieCtx)
|
||||
r.Route("/{groupId}", func(r chi.Router) {
|
||||
r.Use(rs.GroupCtx)
|
||||
r.Get("/frontimage", rs.FrontImage)
|
||||
r.Get("/backimage", rs.BackImage)
|
||||
})
|
||||
|
|
@ -37,77 +37,77 @@ func (rs movieRoutes) Routes() chi.Router {
|
|||
return r
|
||||
}
|
||||
|
||||
func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
||||
movie := r.Context().Value(movieKey).(*models.Movie)
|
||||
func (rs groupRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
||||
group := r.Context().Value(groupKey).(*models.Group)
|
||||
defaultParam := r.URL.Query().Get("default")
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.movieFinder.GetFrontImage(ctx, movie.ID)
|
||||
image, err = rs.groupFinder.GetFrontImage(ctx, group.ID)
|
||||
return err
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch movie front image: %v", readTxnErr)
|
||||
logger.Warnf("read transaction error on fetch group front image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if len(image) == 0 {
|
||||
image = static.ReadAll(static.DefaultMovieImage)
|
||||
image = static.ReadAll(static.DefaultGroupImage)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
}
|
||||
|
||||
func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
||||
movie := r.Context().Value(movieKey).(*models.Movie)
|
||||
func (rs groupRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
||||
group := r.Context().Value(groupKey).(*models.Group)
|
||||
defaultParam := r.URL.Query().Get("default")
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
readTxnErr := rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
var err error
|
||||
image, err = rs.movieFinder.GetBackImage(ctx, movie.ID)
|
||||
image, err = rs.groupFinder.GetBackImage(ctx, group.ID)
|
||||
return err
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch movie back image: %v", readTxnErr)
|
||||
logger.Warnf("read transaction error on fetch group back image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if len(image) == 0 {
|
||||
image = static.ReadAll(static.DefaultMovieImage)
|
||||
image = static.ReadAll(static.DefaultGroupImage)
|
||||
}
|
||||
|
||||
utils.ServeImage(w, r, image)
|
||||
}
|
||||
|
||||
func (rs movieRoutes) MovieCtx(next http.Handler) http.Handler {
|
||||
func (rs groupRoutes) GroupCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
movieID, err := strconv.Atoi(chi.URLParam(r, "movieId"))
|
||||
groupID, err := strconv.Atoi(chi.URLParam(r, "groupId"))
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
var movie *models.Movie
|
||||
var group *models.Group
|
||||
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
||||
movie, _ = rs.movieFinder.Find(ctx, movieID)
|
||||
group, _ = rs.groupFinder.Find(ctx, groupID)
|
||||
return nil
|
||||
})
|
||||
if movie == nil {
|
||||
if group == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), movieKey, movie)
|
||||
ctx := context.WithValue(r.Context(), groupKey, group)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ func Initialize() (*Server, error) {
|
|||
r.Mount("/scene", server.getSceneRoutes())
|
||||
r.Mount("/image", server.getImageRoutes())
|
||||
r.Mount("/studio", server.getStudioRoutes())
|
||||
r.Mount("/movie", server.getMovieRoutes())
|
||||
r.Mount("/group", server.getGroupRoutes())
|
||||
r.Mount("/tag", server.getTagRoutes())
|
||||
r.Mount("/downloads", server.getDownloadsRoutes())
|
||||
r.Mount("/plugin", server.getPluginRoutes())
|
||||
|
|
@ -343,11 +343,11 @@ func (s *Server) getStudioRoutes() chi.Router {
|
|||
}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getMovieRoutes() chi.Router {
|
||||
func (s *Server) getGroupRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return movieRoutes{
|
||||
return groupRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
movieFinder: repo.Movie,
|
||||
groupFinder: repo.Group,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,32 +1,33 @@
|
|||
package urlbuilders
|
||||
|
||||
import (
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
type MovieURLBuilder struct {
|
||||
type GroupURLBuilder struct {
|
||||
BaseURL string
|
||||
MovieID string
|
||||
GroupID string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
func NewMovieURLBuilder(baseURL string, movie *models.Movie) MovieURLBuilder {
|
||||
return MovieURLBuilder{
|
||||
func NewGroupURLBuilder(baseURL string, group *models.Group) GroupURLBuilder {
|
||||
return GroupURLBuilder{
|
||||
BaseURL: baseURL,
|
||||
MovieID: strconv.Itoa(movie.ID),
|
||||
UpdatedAt: strconv.FormatInt(movie.UpdatedAt.Unix(), 10),
|
||||
GroupID: strconv.Itoa(group.ID),
|
||||
UpdatedAt: strconv.FormatInt(group.UpdatedAt.Unix(), 10),
|
||||
}
|
||||
}
|
||||
|
||||
func (b MovieURLBuilder) GetMovieFrontImageURL(hasImage bool) string {
|
||||
url := b.BaseURL + "/movie/" + b.MovieID + "/frontimage?t=" + b.UpdatedAt
|
||||
func (b GroupURLBuilder) GetGroupFrontImageURL(hasImage bool) string {
|
||||
url := b.BaseURL + "/group/" + b.GroupID + "/frontimage?t=" + b.UpdatedAt
|
||||
if !hasImage {
|
||||
url += "&default=true"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
func (b MovieURLBuilder) GetMovieBackImageURL() string {
|
||||
return b.BaseURL + "/movie/" + b.MovieID + "/backimage?t=" + b.UpdatedAt
|
||||
func (b GroupURLBuilder) GetGroupBackImageURL() string {
|
||||
return b.BaseURL + "/group/" + b.GroupID + "/backimage?t=" + b.UpdatedAt
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,13 +316,13 @@ func (me *contentDirectoryService) handleBrowseDirectChildren(obj object, host s
|
|||
objs = me.getPerformerScenes(childPath(paths), host)
|
||||
}
|
||||
|
||||
// Movies
|
||||
if obj.Path == "movies" {
|
||||
objs = me.getMovies()
|
||||
// Groups - deprecated
|
||||
if obj.Path == "groups" {
|
||||
objs = me.getGroups()
|
||||
}
|
||||
|
||||
if strings.HasPrefix(obj.Path, "movies/") {
|
||||
objs = me.getMovieScenes(childPath(paths), host)
|
||||
if strings.HasPrefix(obj.Path, "groups/") {
|
||||
objs = me.getGroupScenes(childPath(paths), host)
|
||||
}
|
||||
|
||||
// Rating
|
||||
|
|
@ -433,7 +433,7 @@ func getRootObjects() []interface{} {
|
|||
objs = append(objs, makeStorageFolder("performers", "performers", rootID))
|
||||
objs = append(objs, makeStorageFolder("tags", "tags", rootID))
|
||||
objs = append(objs, makeStorageFolder("studios", "studios", rootID))
|
||||
objs = append(objs, makeStorageFolder("movies", "movies", rootID))
|
||||
objs = append(objs, makeStorageFolder("groups", "groups", rootID))
|
||||
objs = append(objs, makeStorageFolder("rating", "rating", rootID))
|
||||
|
||||
return objs
|
||||
|
|
@ -658,18 +658,18 @@ func (me *contentDirectoryService) getPerformerScenes(paths []string, host strin
|
|||
return me.getVideos(sceneFilter, parentID, host)
|
||||
}
|
||||
|
||||
func (me *contentDirectoryService) getMovies() []interface{} {
|
||||
func (me *contentDirectoryService) getGroups() []interface{} {
|
||||
var objs []interface{}
|
||||
|
||||
r := me.repository
|
||||
if err := r.WithReadTxn(context.TODO(), func(ctx context.Context) error {
|
||||
movies, err := r.MovieFinder.All(ctx)
|
||||
groups, err := r.GroupFinder.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, s := range movies {
|
||||
objs = append(objs, makeStorageFolder("movies/"+strconv.Itoa(s.ID), s.Name, "movies"))
|
||||
for _, s := range groups {
|
||||
objs = append(objs, makeStorageFolder("groups/"+strconv.Itoa(s.ID), s.Name, "groups"))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -680,15 +680,15 @@ func (me *contentDirectoryService) getMovies() []interface{} {
|
|||
return objs
|
||||
}
|
||||
|
||||
func (me *contentDirectoryService) getMovieScenes(paths []string, host string) []interface{} {
|
||||
func (me *contentDirectoryService) getGroupScenes(paths []string, host string) []interface{} {
|
||||
sceneFilter := &models.SceneFilterType{
|
||||
Movies: &models.MultiCriterionInput{
|
||||
Groups: &models.MultiCriterionInput{
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
Value: []string{paths[0]},
|
||||
},
|
||||
}
|
||||
|
||||
parentID := "movies/" + strings.Join(paths, "/")
|
||||
parentID := "groups/" + strings.Join(paths, "/")
|
||||
|
||||
page := getPageFromID(paths)
|
||||
if page != nil {
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ type PerformerFinder interface {
|
|||
All(ctx context.Context) ([]*models.Performer, error)
|
||||
}
|
||||
|
||||
type MovieFinder interface {
|
||||
All(ctx context.Context) ([]*models.Movie, error)
|
||||
type GroupFinder interface {
|
||||
All(ctx context.Context) ([]*models.Group, error)
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ type Repository struct {
|
|||
StudioFinder StudioFinder
|
||||
TagFinder TagFinder
|
||||
PerformerFinder PerformerFinder
|
||||
MovieFinder MovieFinder
|
||||
GroupFinder GroupFinder
|
||||
}
|
||||
|
||||
func NewRepository(repo models.Repository) Repository {
|
||||
|
|
@ -33,7 +33,7 @@ func NewRepository(repo models.Repository) Repository {
|
|||
StudioFinder: repo.Studio,
|
||||
TagFinder: repo.Tag,
|
||||
PerformerFinder: repo.Performer,
|
||||
MovieFinder: repo.Movie,
|
||||
GroupFinder: repo.Group,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ func (jp *jsonUtils) saveTag(fn string, tag *jsonschema.Tag) error {
|
|||
return jsonschema.SaveTagFile(filepath.Join(jp.json.Tags, fn), tag)
|
||||
}
|
||||
|
||||
func (jp *jsonUtils) saveMovie(fn string, movie *jsonschema.Movie) error {
|
||||
return jsonschema.SaveMovieFile(filepath.Join(jp.json.Movies, fn), movie)
|
||||
func (jp *jsonUtils) saveGroup(fn string, group *jsonschema.Group) error {
|
||||
return jsonschema.SaveGroupFile(filepath.Join(jp.json.Groups, fn), group)
|
||||
}
|
||||
|
||||
func (jp *jsonUtils) saveScene(fn string, scene *jsonschema.Scene) error {
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ func CreateExportTask(a models.HashAlgorithm, input ExportObjectsInput) *ExportT
|
|||
|
||||
func (t *ExportTask) Start(ctx context.Context, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
// @manager.total = Scene.count + Gallery.count + Performer.count + Studio.count + Movie.count
|
||||
// @manager.total = Scene.count + Gallery.count + Performer.count + Studio.count + Group.count
|
||||
workerCount := runtime.GOMAXPROCS(0) // set worker count to number of cpus available
|
||||
|
||||
startTime := time.Now()
|
||||
|
|
@ -156,11 +156,11 @@ func (t *ExportTask) Start(ctx context.Context, wg *sync.WaitGroup) {
|
|||
paths.EnsureJSONDirs(t.baseDir)
|
||||
|
||||
txnErr := t.repository.WithTxn(ctx, func(ctx context.Context) error {
|
||||
// include movie scenes and gallery images
|
||||
// include group scenes and gallery images
|
||||
if !t.full {
|
||||
// only include movie scenes if includeDependencies is also set
|
||||
// only include group scenes if includeDependencies is also set
|
||||
if !t.scenes.all && t.includeDependencies {
|
||||
t.populateMovieScenes(ctx)
|
||||
t.populateGroupScenes(ctx)
|
||||
}
|
||||
|
||||
// always export gallery images
|
||||
|
|
@ -172,7 +172,7 @@ func (t *ExportTask) Start(ctx context.Context, wg *sync.WaitGroup) {
|
|||
t.ExportScenes(ctx, workerCount)
|
||||
t.ExportImages(ctx, workerCount)
|
||||
t.ExportGalleries(ctx, workerCount)
|
||||
t.ExportMovies(ctx, workerCount)
|
||||
t.ExportGroups(ctx, workerCount)
|
||||
t.ExportPerformers(ctx, workerCount)
|
||||
t.ExportStudios(ctx, workerCount)
|
||||
t.ExportTags(ctx, workerCount)
|
||||
|
|
@ -229,7 +229,7 @@ func (t *ExportTask) zipFiles(w io.Writer) error {
|
|||
walkWarn(t.json.json.Galleries, t.zipWalkFunc(u.json.Galleries, z))
|
||||
walkWarn(t.json.json.Performers, t.zipWalkFunc(u.json.Performers, z))
|
||||
walkWarn(t.json.json.Studios, t.zipWalkFunc(u.json.Studios, z))
|
||||
walkWarn(t.json.json.Movies, t.zipWalkFunc(u.json.Movies, z))
|
||||
walkWarn(t.json.json.Groups, t.zipWalkFunc(u.json.Groups, z))
|
||||
walkWarn(t.json.json.Scenes, t.zipWalkFunc(u.json.Scenes, z))
|
||||
walkWarn(t.json.json.Images, t.zipWalkFunc(u.json.Images, z))
|
||||
|
||||
|
|
@ -282,28 +282,28 @@ func (t *ExportTask) zipFile(fn, outDir string, z *zip.Writer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *ExportTask) populateMovieScenes(ctx context.Context) {
|
||||
func (t *ExportTask) populateGroupScenes(ctx context.Context) {
|
||||
r := t.repository
|
||||
reader := r.Movie
|
||||
reader := r.Group
|
||||
sceneReader := r.Scene
|
||||
|
||||
var movies []*models.Movie
|
||||
var groups []*models.Group
|
||||
var err error
|
||||
all := t.full || (t.groups != nil && t.groups.all)
|
||||
if all {
|
||||
movies, err = reader.All(ctx)
|
||||
groups, err = reader.All(ctx)
|
||||
} else if t.groups != nil && len(t.groups.IDs) > 0 {
|
||||
movies, err = reader.FindMany(ctx, t.groups.IDs)
|
||||
groups, err = reader.FindMany(ctx, t.groups.IDs)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("[movies] failed to fetch movies: %v", err)
|
||||
logger.Errorf("[groups] failed to fetch groups: %v", err)
|
||||
}
|
||||
|
||||
for _, m := range movies {
|
||||
scenes, err := sceneReader.FindByMovieID(ctx, m.ID)
|
||||
for _, m := range groups {
|
||||
scenes, err := sceneReader.FindByGroupID(ctx, m.ID)
|
||||
if err != nil {
|
||||
logger.Errorf("[movies] <%s> failed to fetch scenes for movie: %v", m.Name, err)
|
||||
logger.Errorf("[groups] <%s> failed to fetch scenes for group: %v", m.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -488,7 +488,7 @@ func (t *ExportTask) exportScene(ctx context.Context, wg *sync.WaitGroup, jobCha
|
|||
r := t.repository
|
||||
sceneReader := r.Scene
|
||||
studioReader := r.Studio
|
||||
movieReader := r.Movie
|
||||
groupReader := r.Group
|
||||
galleryReader := r.Gallery
|
||||
performerReader := r.Performer
|
||||
tagReader := r.Tag
|
||||
|
|
@ -556,9 +556,9 @@ func (t *ExportTask) exportScene(ctx context.Context, wg *sync.WaitGroup, jobCha
|
|||
continue
|
||||
}
|
||||
|
||||
newSceneJSON.Movies, err = scene.GetSceneMoviesJSON(ctx, movieReader, s)
|
||||
newSceneJSON.Groups, err = scene.GetSceneGroupsJSON(ctx, groupReader, s)
|
||||
if err != nil {
|
||||
logger.Errorf("[scenes] <%s> error getting scene movies JSON: %v", sceneHash, err)
|
||||
logger.Errorf("[scenes] <%s> error getting scene groups JSON: %v", sceneHash, err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -576,12 +576,12 @@ func (t *ExportTask) exportScene(ctx context.Context, wg *sync.WaitGroup, jobCha
|
|||
}
|
||||
t.tags.IDs = sliceutil.AppendUniques(t.tags.IDs, tagIDs)
|
||||
|
||||
movieIDs, err := scene.GetDependentMovieIDs(ctx, s)
|
||||
groupIDs, err := scene.GetDependentGroupIDs(ctx, s)
|
||||
if err != nil {
|
||||
logger.Errorf("[scenes] <%s> error getting scene movies: %v", sceneHash, err)
|
||||
logger.Errorf("[scenes] <%s> error getting scene groups: %v", sceneHash, err)
|
||||
continue
|
||||
}
|
||||
t.groups.IDs = sliceutil.AppendUniques(t.groups.IDs, movieIDs)
|
||||
t.groups.IDs = sliceutil.AppendUniques(t.groups.IDs, groupIDs)
|
||||
|
||||
t.performers.IDs = sliceutil.AppendUniques(t.performers.IDs, performer.GetIDs(performers))
|
||||
}
|
||||
|
|
@ -1081,74 +1081,74 @@ func (t *ExportTask) exportTag(ctx context.Context, wg *sync.WaitGroup, jobChan
|
|||
}
|
||||
}
|
||||
|
||||
func (t *ExportTask) ExportMovies(ctx context.Context, workers int) {
|
||||
var moviesWg sync.WaitGroup
|
||||
func (t *ExportTask) ExportGroups(ctx context.Context, workers int) {
|
||||
var groupsWg sync.WaitGroup
|
||||
|
||||
reader := t.repository.Movie
|
||||
var movies []*models.Movie
|
||||
reader := t.repository.Group
|
||||
var groups []*models.Group
|
||||
var err error
|
||||
all := t.full || (t.groups != nil && t.groups.all)
|
||||
if all {
|
||||
movies, err = reader.All(ctx)
|
||||
groups, err = reader.All(ctx)
|
||||
} else if t.groups != nil && len(t.groups.IDs) > 0 {
|
||||
movies, err = reader.FindMany(ctx, t.groups.IDs)
|
||||
groups, err = reader.FindMany(ctx, t.groups.IDs)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("[movies] failed to fetch movies: %v", err)
|
||||
logger.Errorf("[groups] failed to fetch groups: %v", err)
|
||||
}
|
||||
|
||||
logger.Info("[movies] exporting")
|
||||
logger.Info("[groups] exporting")
|
||||
startTime := time.Now()
|
||||
|
||||
jobCh := make(chan *models.Movie, workers*2) // make a buffered channel to feed workers
|
||||
jobCh := make(chan *models.Group, workers*2) // make a buffered channel to feed workers
|
||||
|
||||
for w := 0; w < workers; w++ { // create export Studio workers
|
||||
moviesWg.Add(1)
|
||||
go t.exportMovie(ctx, &moviesWg, jobCh)
|
||||
groupsWg.Add(1)
|
||||
go t.exportGroup(ctx, &groupsWg, jobCh)
|
||||
}
|
||||
|
||||
for i, movie := range movies {
|
||||
for i, group := range groups {
|
||||
index := i + 1
|
||||
logger.Progressf("[movies] %d of %d", index, len(movies))
|
||||
logger.Progressf("[groups] %d of %d", index, len(groups))
|
||||
|
||||
jobCh <- movie // feed workers
|
||||
jobCh <- group // feed workers
|
||||
}
|
||||
|
||||
close(jobCh)
|
||||
moviesWg.Wait()
|
||||
groupsWg.Wait()
|
||||
|
||||
logger.Infof("[movies] export complete in %s. %d workers used.", time.Since(startTime), workers)
|
||||
logger.Infof("[groups] export complete in %s. %d workers used.", time.Since(startTime), workers)
|
||||
|
||||
}
|
||||
func (t *ExportTask) exportMovie(ctx context.Context, wg *sync.WaitGroup, jobChan <-chan *models.Movie) {
|
||||
func (t *ExportTask) exportGroup(ctx context.Context, wg *sync.WaitGroup, jobChan <-chan *models.Group) {
|
||||
defer wg.Done()
|
||||
|
||||
r := t.repository
|
||||
movieReader := r.Movie
|
||||
groupReader := r.Group
|
||||
studioReader := r.Studio
|
||||
tagReader := r.Tag
|
||||
|
||||
for m := range jobChan {
|
||||
if err := m.LoadURLs(ctx, r.Movie); err != nil {
|
||||
logger.Errorf("[movies] <%s> error getting movie urls: %v", m.Name, err)
|
||||
if err := m.LoadURLs(ctx, r.Group); err != nil {
|
||||
logger.Errorf("[groups] <%s> error getting group urls: %v", m.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
newMovieJSON, err := movie.ToJSON(ctx, movieReader, studioReader, m)
|
||||
newGroupJSON, err := movie.ToJSON(ctx, groupReader, studioReader, m)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("[movies] <%s> error getting tag JSON: %v", m.Name, err)
|
||||
logger.Errorf("[groups] <%s> error getting tag JSON: %v", m.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
tags, err := tagReader.FindByMovieID(ctx, m.ID)
|
||||
tags, err := tagReader.FindByGroupID(ctx, m.ID)
|
||||
if err != nil {
|
||||
logger.Errorf("[movies] <%s> error getting image tag names: %v", m.Name, err)
|
||||
logger.Errorf("[groups] <%s> error getting image tag names: %v", m.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
newMovieJSON.Tags = tag.GetNames(tags)
|
||||
newGroupJSON.Tags = tag.GetNames(tags)
|
||||
|
||||
if t.includeDependencies {
|
||||
if m.StudioID != nil {
|
||||
|
|
@ -1156,10 +1156,10 @@ func (t *ExportTask) exportMovie(ctx context.Context, wg *sync.WaitGroup, jobCha
|
|||
}
|
||||
}
|
||||
|
||||
fn := newMovieJSON.Filename()
|
||||
fn := newGroupJSON.Filename()
|
||||
|
||||
if err := t.json.saveMovie(fn, newMovieJSON); err != nil {
|
||||
logger.Errorf("[movies] <%s> failed to save json: %v", m.Name, err)
|
||||
if err := t.json.saveGroup(fn, newGroupJSON); err != nil {
|
||||
logger.Errorf("[groups] <%s> failed to save json: %v", m.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ func (t *ImportTask) Start(ctx context.Context) {
|
|||
t.ImportTags(ctx)
|
||||
t.ImportPerformers(ctx)
|
||||
t.ImportStudios(ctx)
|
||||
t.ImportMovies(ctx)
|
||||
t.ImportGroups(ctx)
|
||||
t.ImportFiles(ctx)
|
||||
t.ImportGalleries(ctx)
|
||||
|
||||
|
|
@ -325,14 +325,14 @@ func (t *ImportTask) importStudio(ctx context.Context, studioJSON *jsonschema.St
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *ImportTask) ImportMovies(ctx context.Context) {
|
||||
logger.Info("[movies] importing")
|
||||
func (t *ImportTask) ImportGroups(ctx context.Context) {
|
||||
logger.Info("[groups] importing")
|
||||
|
||||
path := t.json.json.Movies
|
||||
path := t.json.json.Groups
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
logger.Errorf("[movies] failed to read movies directory: %v", err)
|
||||
logger.Errorf("[groups] failed to read movies directory: %v", err)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
@ -342,31 +342,31 @@ func (t *ImportTask) ImportMovies(ctx context.Context) {
|
|||
|
||||
for i, fi := range files {
|
||||
index := i + 1
|
||||
movieJSON, err := jsonschema.LoadMovieFile(filepath.Join(path, fi.Name()))
|
||||
groupJSON, err := jsonschema.LoadGroupFile(filepath.Join(path, fi.Name()))
|
||||
if err != nil {
|
||||
logger.Errorf("[movies] failed to read json: %v", err)
|
||||
logger.Errorf("[groups] failed to read json: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Progressf("[movies] %d of %d", index, len(files))
|
||||
logger.Progressf("[groups] %d of %d", index, len(files))
|
||||
|
||||
if err := r.WithTxn(ctx, func(ctx context.Context) error {
|
||||
movieImporter := &movie.Importer{
|
||||
ReaderWriter: r.Movie,
|
||||
groupImporter := &movie.Importer{
|
||||
ReaderWriter: r.Group,
|
||||
StudioWriter: r.Studio,
|
||||
TagWriter: r.Tag,
|
||||
Input: *movieJSON,
|
||||
Input: *groupJSON,
|
||||
MissingRefBehaviour: t.MissingRefBehaviour,
|
||||
}
|
||||
|
||||
return performImport(ctx, movieImporter, t.DuplicateBehaviour)
|
||||
return performImport(ctx, groupImporter, t.DuplicateBehaviour)
|
||||
}); err != nil {
|
||||
logger.Errorf("[movies] <%s> import failed: %v", fi.Name(), err)
|
||||
logger.Errorf("[groups] <%s> import failed: %v", fi.Name(), err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("[movies] import complete")
|
||||
logger.Info("[groups] import complete")
|
||||
}
|
||||
|
||||
func (t *ImportTask) ImportFiles(ctx context.Context) {
|
||||
|
|
@ -648,7 +648,7 @@ func (t *ImportTask) ImportScenes(ctx context.Context) {
|
|||
MissingRefBehaviour: t.MissingRefBehaviour,
|
||||
|
||||
GalleryFinder: r.Gallery,
|
||||
MovieWriter: r.Movie,
|
||||
GroupWriter: r.Group,
|
||||
PerformerWriter: r.Performer,
|
||||
StudioWriter: r.Studio,
|
||||
TagWriter: r.Tag,
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ const (
|
|||
Studio = "studio"
|
||||
DefaultStudioImage = "studio/studio.svg"
|
||||
|
||||
Movie = "movie"
|
||||
DefaultMovieImage = "movie/movie.png"
|
||||
Group = "movie"
|
||||
DefaultGroupImage = "movie/movie.png"
|
||||
)
|
||||
|
||||
// Sub returns an FS rooted at path, using fs.Sub.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ type PerformerFinder interface {
|
|||
FindByStashID(ctx context.Context, stashID models.StashID) ([]*models.Performer, error)
|
||||
}
|
||||
|
||||
type MovieNamesFinder interface {
|
||||
FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Movie, error)
|
||||
type GroupNamesFinder interface {
|
||||
FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Group, error)
|
||||
}
|
||||
|
||||
// ScrapedPerformer matches the provided performer with the
|
||||
|
|
@ -118,27 +118,27 @@ func ScrapedStudio(ctx context.Context, qb StudioFinder, s *models.ScrapedStudio
|
|||
return nil
|
||||
}
|
||||
|
||||
// ScrapedMovie matches the provided movie with the movies
|
||||
// in the database and sets the ID field if one is found.
|
||||
func ScrapedMovie(ctx context.Context, qb MovieNamesFinder, m *models.ScrapedMovie) error {
|
||||
if m.StoredID != nil || m.Name == nil {
|
||||
return nil
|
||||
// ScrapedGroup matches the provided movie with the movies
|
||||
// in the database and returns the ID field if one is found.
|
||||
func ScrapedGroup(ctx context.Context, qb GroupNamesFinder, storedID *string, name *string) (matchedID *string, err error) {
|
||||
if storedID != nil || name == nil {
|
||||
return
|
||||
}
|
||||
|
||||
movies, err := qb.FindByNames(ctx, []string{*m.Name}, true)
|
||||
movies, err := qb.FindByNames(ctx, []string{*name}, true)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
|
||||
if len(movies) != 1 {
|
||||
// ignore - cannot match
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
id := strconv.Itoa(movies[0].ID)
|
||||
m.StoredID = &id
|
||||
return nil
|
||||
matchedID = &id
|
||||
return
|
||||
}
|
||||
|
||||
// ScrapedTag matches the provided tag with the tags
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models/json"
|
||||
)
|
||||
|
||||
type Movie struct {
|
||||
type Group struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Aliases string `json:"aliases,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
|
|
@ -31,7 +31,7 @@ type Movie struct {
|
|||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (s Movie) Filename() string {
|
||||
func (s Group) Filename() string {
|
||||
return fsutil.SanitiseBasename(s.Name) + ".json"
|
||||
}
|
||||
|
||||
|
|
@ -40,8 +40,8 @@ type MovieSynopsisBC struct {
|
|||
Synopsis string `json:"sypnopsis,omitempty"`
|
||||
}
|
||||
|
||||
func LoadMovieFile(filePath string) (*Movie, error) {
|
||||
var movie Movie
|
||||
func LoadGroupFile(filePath string) (*Group, error) {
|
||||
var movie Group
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -72,7 +72,7 @@ func LoadMovieFile(filePath string) (*Movie, error) {
|
|||
return &movie, nil
|
||||
}
|
||||
|
||||
func SaveMovieFile(filePath string, movie *Movie) error {
|
||||
func SaveGroupFile(filePath string, movie *Group) error {
|
||||
if movie == nil {
|
||||
return fmt.Errorf("movie must not be nil")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ type SceneFile struct {
|
|||
Bitrate int `json:"bitrate"`
|
||||
}
|
||||
|
||||
type SceneMovie struct {
|
||||
MovieName string `json:"movieName,omitempty"`
|
||||
type SceneGroup struct {
|
||||
GroupName string `json:"movieName,omitempty"`
|
||||
SceneIndex int `json:"scene_index,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ type Scene struct {
|
|||
Director string `json:"director,omitempty"`
|
||||
Galleries []GalleryRef `json:"galleries,omitempty"`
|
||||
Performers []string `json:"performers,omitempty"`
|
||||
Movies []SceneMovie `json:"movies,omitempty"`
|
||||
Groups []SceneGroup `json:"movies,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Markers []SceneMarker `json:"markers,omitempty"`
|
||||
Files []string `json:"files,omitempty"`
|
||||
|
|
|
|||
|
|
@ -9,21 +9,21 @@ import (
|
|||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MovieReaderWriter is an autogenerated mock type for the MovieReaderWriter type
|
||||
type MovieReaderWriter struct {
|
||||
// GroupReaderWriter is an autogenerated mock type for the GroupReaderWriter type
|
||||
type GroupReaderWriter struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// All provides a mock function with given fields: ctx
|
||||
func (_m *MovieReaderWriter) All(ctx context.Context) ([]*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) All(ctx context.Context) ([]*models.Group, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 []*models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []*models.Movie); ok {
|
||||
var r0 []*models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []*models.Group); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Movie)
|
||||
r0 = ret.Get(0).([]*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ func (_m *MovieReaderWriter) All(ctx context.Context) ([]*models.Movie, error) {
|
|||
}
|
||||
|
||||
// Count provides a mock function with given fields: ctx
|
||||
func (_m *MovieReaderWriter) Count(ctx context.Context) (int, error) {
|
||||
func (_m *GroupReaderWriter) Count(ctx context.Context) (int, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 int
|
||||
|
|
@ -59,7 +59,7 @@ func (_m *MovieReaderWriter) Count(ctx context.Context) (int, error) {
|
|||
}
|
||||
|
||||
// CountByPerformerID provides a mock function with given fields: ctx, performerID
|
||||
func (_m *MovieReaderWriter) CountByPerformerID(ctx context.Context, performerID int) (int, error) {
|
||||
func (_m *GroupReaderWriter) CountByPerformerID(ctx context.Context, performerID int) (int, error) {
|
||||
ret := _m.Called(ctx, performerID)
|
||||
|
||||
var r0 int
|
||||
|
|
@ -80,7 +80,7 @@ func (_m *MovieReaderWriter) CountByPerformerID(ctx context.Context, performerID
|
|||
}
|
||||
|
||||
// CountByStudioID provides a mock function with given fields: ctx, studioID
|
||||
func (_m *MovieReaderWriter) CountByStudioID(ctx context.Context, studioID int) (int, error) {
|
||||
func (_m *GroupReaderWriter) CountByStudioID(ctx context.Context, studioID int) (int, error) {
|
||||
ret := _m.Called(ctx, studioID)
|
||||
|
||||
var r0 int
|
||||
|
|
@ -100,13 +100,13 @@ func (_m *MovieReaderWriter) CountByStudioID(ctx context.Context, studioID int)
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: ctx, newMovie
|
||||
func (_m *MovieReaderWriter) Create(ctx context.Context, newMovie *models.Movie) error {
|
||||
ret := _m.Called(ctx, newMovie)
|
||||
// Create provides a mock function with given fields: ctx, newGroup
|
||||
func (_m *GroupReaderWriter) Create(ctx context.Context, newGroup *models.Group) error {
|
||||
ret := _m.Called(ctx, newGroup)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.Movie) error); ok {
|
||||
r0 = rf(ctx, newMovie)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.Group) error); ok {
|
||||
r0 = rf(ctx, newGroup)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ func (_m *MovieReaderWriter) Create(ctx context.Context, newMovie *models.Movie)
|
|||
}
|
||||
|
||||
// Destroy provides a mock function with given fields: ctx, id
|
||||
func (_m *MovieReaderWriter) Destroy(ctx context.Context, id int) error {
|
||||
func (_m *GroupReaderWriter) Destroy(ctx context.Context, id int) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 error
|
||||
|
|
@ -129,15 +129,15 @@ func (_m *MovieReaderWriter) Destroy(ctx context.Context, id int) error {
|
|||
}
|
||||
|
||||
// Find provides a mock function with given fields: ctx, id
|
||||
func (_m *MovieReaderWriter) Find(ctx context.Context, id int) (*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) Find(ctx context.Context, id int) (*models.Group, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 *models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) *models.Movie); ok {
|
||||
var r0 *models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) *models.Group); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*models.Movie)
|
||||
r0 = ret.Get(0).(*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,15 +152,15 @@ func (_m *MovieReaderWriter) Find(ctx context.Context, id int) (*models.Movie, e
|
|||
}
|
||||
|
||||
// FindByName provides a mock function with given fields: ctx, name, nocase
|
||||
func (_m *MovieReaderWriter) FindByName(ctx context.Context, name string, nocase bool) (*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) FindByName(ctx context.Context, name string, nocase bool) (*models.Group, error) {
|
||||
ret := _m.Called(ctx, name, nocase)
|
||||
|
||||
var r0 *models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, bool) *models.Movie); ok {
|
||||
var r0 *models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, bool) *models.Group); ok {
|
||||
r0 = rf(ctx, name, nocase)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*models.Movie)
|
||||
r0 = ret.Get(0).(*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,15 +175,15 @@ func (_m *MovieReaderWriter) FindByName(ctx context.Context, name string, nocase
|
|||
}
|
||||
|
||||
// FindByNames provides a mock function with given fields: ctx, names, nocase
|
||||
func (_m *MovieReaderWriter) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Group, error) {
|
||||
ret := _m.Called(ctx, names, nocase)
|
||||
|
||||
var r0 []*models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []string, bool) []*models.Movie); ok {
|
||||
var r0 []*models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []string, bool) []*models.Group); ok {
|
||||
r0 = rf(ctx, names, nocase)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Movie)
|
||||
r0 = ret.Get(0).([]*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,15 +198,15 @@ func (_m *MovieReaderWriter) FindByNames(ctx context.Context, names []string, no
|
|||
}
|
||||
|
||||
// FindByPerformerID provides a mock function with given fields: ctx, performerID
|
||||
func (_m *MovieReaderWriter) FindByPerformerID(ctx context.Context, performerID int) ([]*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) FindByPerformerID(ctx context.Context, performerID int) ([]*models.Group, error) {
|
||||
ret := _m.Called(ctx, performerID)
|
||||
|
||||
var r0 []*models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Movie); ok {
|
||||
var r0 []*models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Group); ok {
|
||||
r0 = rf(ctx, performerID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Movie)
|
||||
r0 = ret.Get(0).([]*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,15 +221,15 @@ func (_m *MovieReaderWriter) FindByPerformerID(ctx context.Context, performerID
|
|||
}
|
||||
|
||||
// FindByStudioID provides a mock function with given fields: ctx, studioID
|
||||
func (_m *MovieReaderWriter) FindByStudioID(ctx context.Context, studioID int) ([]*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) FindByStudioID(ctx context.Context, studioID int) ([]*models.Group, error) {
|
||||
ret := _m.Called(ctx, studioID)
|
||||
|
||||
var r0 []*models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Movie); ok {
|
||||
var r0 []*models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Group); ok {
|
||||
r0 = rf(ctx, studioID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Movie)
|
||||
r0 = ret.Get(0).([]*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,15 +244,15 @@ func (_m *MovieReaderWriter) FindByStudioID(ctx context.Context, studioID int) (
|
|||
}
|
||||
|
||||
// FindMany provides a mock function with given fields: ctx, ids
|
||||
func (_m *MovieReaderWriter) FindMany(ctx context.Context, ids []int) ([]*models.Movie, error) {
|
||||
func (_m *GroupReaderWriter) FindMany(ctx context.Context, ids []int) ([]*models.Group, error) {
|
||||
ret := _m.Called(ctx, ids)
|
||||
|
||||
var r0 []*models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []int) []*models.Movie); ok {
|
||||
var r0 []*models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []int) []*models.Group); ok {
|
||||
r0 = rf(ctx, ids)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Movie)
|
||||
r0 = ret.Get(0).([]*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,13 +266,13 @@ func (_m *MovieReaderWriter) FindMany(ctx context.Context, ids []int) ([]*models
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetBackImage provides a mock function with given fields: ctx, movieID
|
||||
func (_m *MovieReaderWriter) GetBackImage(ctx context.Context, movieID int) ([]byte, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
// GetBackImage provides a mock function with given fields: ctx, groupID
|
||||
func (_m *GroupReaderWriter) GetBackImage(ctx context.Context, groupID int) ([]byte, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 []byte
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []byte); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
|
|
@ -281,7 +281,7 @@ func (_m *MovieReaderWriter) GetBackImage(ctx context.Context, movieID int) ([]b
|
|||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -289,13 +289,13 @@ func (_m *MovieReaderWriter) GetBackImage(ctx context.Context, movieID int) ([]b
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetFrontImage provides a mock function with given fields: ctx, movieID
|
||||
func (_m *MovieReaderWriter) GetFrontImage(ctx context.Context, movieID int) ([]byte, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
// GetFrontImage provides a mock function with given fields: ctx, groupID
|
||||
func (_m *GroupReaderWriter) GetFrontImage(ctx context.Context, groupID int) ([]byte, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 []byte
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []byte); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
|
|
@ -304,7 +304,7 @@ func (_m *MovieReaderWriter) GetFrontImage(ctx context.Context, movieID int) ([]
|
|||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ func (_m *MovieReaderWriter) GetFrontImage(ctx context.Context, movieID int) ([]
|
|||
}
|
||||
|
||||
// GetTagIDs provides a mock function with given fields: ctx, relatedID
|
||||
func (_m *MovieReaderWriter) GetTagIDs(ctx context.Context, relatedID int) ([]int, error) {
|
||||
func (_m *GroupReaderWriter) GetTagIDs(ctx context.Context, relatedID int) ([]int, error) {
|
||||
ret := _m.Called(ctx, relatedID)
|
||||
|
||||
var r0 []int
|
||||
|
|
@ -336,7 +336,7 @@ func (_m *MovieReaderWriter) GetTagIDs(ctx context.Context, relatedID int) ([]in
|
|||
}
|
||||
|
||||
// GetURLs provides a mock function with given fields: ctx, relatedID
|
||||
func (_m *MovieReaderWriter) GetURLs(ctx context.Context, relatedID int) ([]string, error) {
|
||||
func (_m *GroupReaderWriter) GetURLs(ctx context.Context, relatedID int) ([]string, error) {
|
||||
ret := _m.Called(ctx, relatedID)
|
||||
|
||||
var r0 []string
|
||||
|
|
@ -358,20 +358,20 @@ func (_m *MovieReaderWriter) GetURLs(ctx context.Context, relatedID int) ([]stri
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// HasBackImage provides a mock function with given fields: ctx, movieID
|
||||
func (_m *MovieReaderWriter) HasBackImage(ctx context.Context, movieID int) (bool, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
// HasBackImage provides a mock function with given fields: ctx, groupID
|
||||
func (_m *GroupReaderWriter) HasBackImage(ctx context.Context, groupID int) (bool, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) bool); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -379,20 +379,20 @@ func (_m *MovieReaderWriter) HasBackImage(ctx context.Context, movieID int) (boo
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// HasFrontImage provides a mock function with given fields: ctx, movieID
|
||||
func (_m *MovieReaderWriter) HasFrontImage(ctx context.Context, movieID int) (bool, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
// HasFrontImage provides a mock function with given fields: ctx, groupID
|
||||
func (_m *GroupReaderWriter) HasFrontImage(ctx context.Context, groupID int) (bool, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) bool); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -400,29 +400,29 @@ func (_m *MovieReaderWriter) HasFrontImage(ctx context.Context, movieID int) (bo
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// Query provides a mock function with given fields: ctx, movieFilter, findFilter
|
||||
func (_m *MovieReaderWriter) Query(ctx context.Context, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) ([]*models.Movie, int, error) {
|
||||
ret := _m.Called(ctx, movieFilter, findFilter)
|
||||
// Query provides a mock function with given fields: ctx, groupFilter, findFilter
|
||||
func (_m *GroupReaderWriter) Query(ctx context.Context, groupFilter *models.GroupFilterType, findFilter *models.FindFilterType) ([]*models.Group, int, error) {
|
||||
ret := _m.Called(ctx, groupFilter, findFilter)
|
||||
|
||||
var r0 []*models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.MovieFilterType, *models.FindFilterType) []*models.Movie); ok {
|
||||
r0 = rf(ctx, movieFilter, findFilter)
|
||||
var r0 []*models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.GroupFilterType, *models.FindFilterType) []*models.Group); ok {
|
||||
r0 = rf(ctx, groupFilter, findFilter)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Movie)
|
||||
r0 = ret.Get(0).([]*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 int
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *models.MovieFilterType, *models.FindFilterType) int); ok {
|
||||
r1 = rf(ctx, movieFilter, findFilter)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *models.GroupFilterType, *models.FindFilterType) int); ok {
|
||||
r1 = rf(ctx, groupFilter, findFilter)
|
||||
} else {
|
||||
r1 = ret.Get(1).(int)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *models.MovieFilterType, *models.FindFilterType) error); ok {
|
||||
r2 = rf(ctx, movieFilter, findFilter)
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *models.GroupFilterType, *models.FindFilterType) error); ok {
|
||||
r2 = rf(ctx, groupFilter, findFilter)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
|
@ -430,20 +430,20 @@ func (_m *MovieReaderWriter) Query(ctx context.Context, movieFilter *models.Movi
|
|||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// QueryCount provides a mock function with given fields: ctx, movieFilter, findFilter
|
||||
func (_m *MovieReaderWriter) QueryCount(ctx context.Context, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) (int, error) {
|
||||
ret := _m.Called(ctx, movieFilter, findFilter)
|
||||
// QueryCount provides a mock function with given fields: ctx, groupFilter, findFilter
|
||||
func (_m *GroupReaderWriter) QueryCount(ctx context.Context, groupFilter *models.GroupFilterType, findFilter *models.FindFilterType) (int, error) {
|
||||
ret := _m.Called(ctx, groupFilter, findFilter)
|
||||
|
||||
var r0 int
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.MovieFilterType, *models.FindFilterType) int); ok {
|
||||
r0 = rf(ctx, movieFilter, findFilter)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.GroupFilterType, *models.FindFilterType) int); ok {
|
||||
r0 = rf(ctx, groupFilter, findFilter)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *models.MovieFilterType, *models.FindFilterType) error); ok {
|
||||
r1 = rf(ctx, movieFilter, findFilter)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *models.GroupFilterType, *models.FindFilterType) error); ok {
|
||||
r1 = rf(ctx, groupFilter, findFilter)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -451,13 +451,13 @@ func (_m *MovieReaderWriter) QueryCount(ctx context.Context, movieFilter *models
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, updatedMovie
|
||||
func (_m *MovieReaderWriter) Update(ctx context.Context, updatedMovie *models.Movie) error {
|
||||
ret := _m.Called(ctx, updatedMovie)
|
||||
// Update provides a mock function with given fields: ctx, updatedGroup
|
||||
func (_m *GroupReaderWriter) Update(ctx context.Context, updatedGroup *models.Group) error {
|
||||
ret := _m.Called(ctx, updatedGroup)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.Movie) error); ok {
|
||||
r0 = rf(ctx, updatedMovie)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.Group) error); ok {
|
||||
r0 = rf(ctx, updatedGroup)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
|
@ -465,13 +465,13 @@ func (_m *MovieReaderWriter) Update(ctx context.Context, updatedMovie *models.Mo
|
|||
return r0
|
||||
}
|
||||
|
||||
// UpdateBackImage provides a mock function with given fields: ctx, movieID, backImage
|
||||
func (_m *MovieReaderWriter) UpdateBackImage(ctx context.Context, movieID int, backImage []byte) error {
|
||||
ret := _m.Called(ctx, movieID, backImage)
|
||||
// UpdateBackImage provides a mock function with given fields: ctx, groupID, backImage
|
||||
func (_m *GroupReaderWriter) UpdateBackImage(ctx context.Context, groupID int, backImage []byte) error {
|
||||
ret := _m.Called(ctx, groupID, backImage)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, []byte) error); ok {
|
||||
r0 = rf(ctx, movieID, backImage)
|
||||
r0 = rf(ctx, groupID, backImage)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
|
@ -479,13 +479,13 @@ func (_m *MovieReaderWriter) UpdateBackImage(ctx context.Context, movieID int, b
|
|||
return r0
|
||||
}
|
||||
|
||||
// UpdateFrontImage provides a mock function with given fields: ctx, movieID, frontImage
|
||||
func (_m *MovieReaderWriter) UpdateFrontImage(ctx context.Context, movieID int, frontImage []byte) error {
|
||||
ret := _m.Called(ctx, movieID, frontImage)
|
||||
// UpdateFrontImage provides a mock function with given fields: ctx, groupID, frontImage
|
||||
func (_m *GroupReaderWriter) UpdateFrontImage(ctx context.Context, groupID int, frontImage []byte) error {
|
||||
ret := _m.Called(ctx, groupID, frontImage)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, []byte) error); ok {
|
||||
r0 = rf(ctx, movieID, frontImage)
|
||||
r0 = rf(ctx, groupID, frontImage)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
|
@ -493,22 +493,22 @@ func (_m *MovieReaderWriter) UpdateFrontImage(ctx context.Context, movieID int,
|
|||
return r0
|
||||
}
|
||||
|
||||
// UpdatePartial provides a mock function with given fields: ctx, id, updatedMovie
|
||||
func (_m *MovieReaderWriter) UpdatePartial(ctx context.Context, id int, updatedMovie models.MoviePartial) (*models.Movie, error) {
|
||||
ret := _m.Called(ctx, id, updatedMovie)
|
||||
// UpdatePartial provides a mock function with given fields: ctx, id, updatedGroup
|
||||
func (_m *GroupReaderWriter) UpdatePartial(ctx context.Context, id int, updatedGroup models.GroupPartial) (*models.Group, error) {
|
||||
ret := _m.Called(ctx, id, updatedGroup)
|
||||
|
||||
var r0 *models.Movie
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, models.MoviePartial) *models.Movie); ok {
|
||||
r0 = rf(ctx, id, updatedMovie)
|
||||
var r0 *models.Group
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, models.GroupPartial) *models.Group); ok {
|
||||
r0 = rf(ctx, id, updatedGroup)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*models.Movie)
|
||||
r0 = ret.Get(0).(*models.Group)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int, models.MoviePartial) error); ok {
|
||||
r1 = rf(ctx, id, updatedMovie)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int, models.GroupPartial) error); ok {
|
||||
r1 = rf(ctx, id, updatedGroup)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -111,29 +111,6 @@ func (_m *SavedFilterReaderWriter) FindByMode(ctx context.Context, mode models.F
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// FindDefault provides a mock function with given fields: ctx, mode
|
||||
func (_m *SavedFilterReaderWriter) FindDefault(ctx context.Context, mode models.FilterMode) (*models.SavedFilter, error) {
|
||||
ret := _m.Called(ctx, mode)
|
||||
|
||||
var r0 *models.SavedFilter
|
||||
if rf, ok := ret.Get(0).(func(context.Context, models.FilterMode) *models.SavedFilter); ok {
|
||||
r0 = rf(ctx, mode)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*models.SavedFilter)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, models.FilterMode) error); ok {
|
||||
r1 = rf(ctx, mode)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindMany provides a mock function with given fields: ctx, ids, ignoreNotFound
|
||||
func (_m *SavedFilterReaderWriter) FindMany(ctx context.Context, ids []int, ignoreNotFound bool) ([]*models.SavedFilter, error) {
|
||||
ret := _m.Called(ctx, ids, ignoreNotFound)
|
||||
|
|
@ -157,20 +134,6 @@ func (_m *SavedFilterReaderWriter) FindMany(ctx context.Context, ids []int, igno
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// SetDefault provides a mock function with given fields: ctx, obj
|
||||
func (_m *SavedFilterReaderWriter) SetDefault(ctx context.Context, obj *models.SavedFilter) error {
|
||||
ret := _m.Called(ctx, obj)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.SavedFilter) error); ok {
|
||||
r0 = rf(ctx, obj)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, obj
|
||||
func (_m *SavedFilterReaderWriter) Update(ctx context.Context, obj *models.SavedFilter) error {
|
||||
ret := _m.Called(ctx, obj)
|
||||
|
|
|
|||
|
|
@ -190,20 +190,20 @@ func (_m *SceneReaderWriter) CountByFileID(ctx context.Context, fileID models.Fi
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// CountByMovieID provides a mock function with given fields: ctx, movieID
|
||||
func (_m *SceneReaderWriter) CountByMovieID(ctx context.Context, movieID int) (int, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
// CountByGroupID provides a mock function with given fields: ctx, groupID
|
||||
func (_m *SceneReaderWriter) CountByGroupID(ctx context.Context, groupID int) (int, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 int
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) int); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -589,13 +589,13 @@ func (_m *SceneReaderWriter) FindByGalleryID(ctx context.Context, performerID in
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// FindByMovieID provides a mock function with given fields: ctx, movieID
|
||||
func (_m *SceneReaderWriter) FindByMovieID(ctx context.Context, movieID int) ([]*models.Scene, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
// FindByGroupID provides a mock function with given fields: ctx, groupID
|
||||
func (_m *SceneReaderWriter) FindByGroupID(ctx context.Context, groupID int) ([]*models.Scene, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 []*models.Scene
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Scene); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Scene)
|
||||
|
|
@ -604,7 +604,7 @@ func (_m *SceneReaderWriter) FindByMovieID(ctx context.Context, movieID int) ([]
|
|||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
@ -840,6 +840,29 @@ func (_m *SceneReaderWriter) GetGalleryIDs(ctx context.Context, relatedID int) (
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetGroups provides a mock function with given fields: ctx, id
|
||||
func (_m *SceneReaderWriter) GetGroups(ctx context.Context, id int) ([]models.GroupsScenes, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 []models.GroupsScenes
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []models.GroupsScenes); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]models.GroupsScenes)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetManyFileIDs provides a mock function with given fields: ctx, ids
|
||||
func (_m *SceneReaderWriter) GetManyFileIDs(ctx context.Context, ids []int) ([][]models.FileID, error) {
|
||||
ret := _m.Called(ctx, ids)
|
||||
|
|
@ -978,29 +1001,6 @@ func (_m *SceneReaderWriter) GetManyViewDates(ctx context.Context, ids []int) ([
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetMovies provides a mock function with given fields: ctx, id
|
||||
func (_m *SceneReaderWriter) GetMovies(ctx context.Context, id int) ([]models.MoviesScenes, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 []models.MoviesScenes
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []models.MoviesScenes); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]models.MoviesScenes)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetOCount provides a mock function with given fields: ctx, id
|
||||
func (_m *SceneReaderWriter) GetOCount(ctx context.Context, id int) (int, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
|
|
|||
|
|
@ -243,6 +243,29 @@ func (_m *TagReaderWriter) FindByGalleryID(ctx context.Context, galleryID int) (
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// FindByGroupID provides a mock function with given fields: ctx, groupID
|
||||
func (_m *TagReaderWriter) FindByGroupID(ctx context.Context, groupID int) ([]*models.Tag, error) {
|
||||
ret := _m.Called(ctx, groupID)
|
||||
|
||||
var r0 []*models.Tag
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Tag); ok {
|
||||
r0 = rf(ctx, groupID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, groupID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindByImageID provides a mock function with given fields: ctx, imageID
|
||||
func (_m *TagReaderWriter) FindByImageID(ctx context.Context, imageID int) ([]*models.Tag, error) {
|
||||
ret := _m.Called(ctx, imageID)
|
||||
|
|
@ -266,29 +289,6 @@ func (_m *TagReaderWriter) FindByImageID(ctx context.Context, imageID int) ([]*m
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// FindByMovieID provides a mock function with given fields: ctx, movieID
|
||||
func (_m *TagReaderWriter) FindByMovieID(ctx context.Context, movieID int) ([]*models.Tag, error) {
|
||||
ret := _m.Called(ctx, movieID)
|
||||
|
||||
var r0 []*models.Tag
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Tag); ok {
|
||||
r0 = rf(ctx, movieID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
||||
r1 = rf(ctx, movieID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindByName provides a mock function with given fields: ctx, name, nocase
|
||||
func (_m *TagReaderWriter) FindByName(ctx context.Context, name string, nocase bool) (*models.Tag, error) {
|
||||
ret := _m.Called(ctx, name, nocase)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ type Database struct {
|
|||
Gallery *GalleryReaderWriter
|
||||
GalleryChapter *GalleryChapterReaderWriter
|
||||
Image *ImageReaderWriter
|
||||
Movie *MovieReaderWriter
|
||||
Group *GroupReaderWriter
|
||||
Performer *PerformerReaderWriter
|
||||
Scene *SceneReaderWriter
|
||||
SceneMarker *SceneMarkerReaderWriter
|
||||
|
|
@ -63,7 +63,7 @@ func NewDatabase() *Database {
|
|||
Gallery: &GalleryReaderWriter{},
|
||||
GalleryChapter: &GalleryChapterReaderWriter{},
|
||||
Image: &ImageReaderWriter{},
|
||||
Movie: &MovieReaderWriter{},
|
||||
Group: &GroupReaderWriter{},
|
||||
Performer: &PerformerReaderWriter{},
|
||||
Scene: &SceneReaderWriter{},
|
||||
SceneMarker: &SceneMarkerReaderWriter{},
|
||||
|
|
@ -79,7 +79,7 @@ func (db *Database) AssertExpectations(t mock.TestingT) {
|
|||
db.Gallery.AssertExpectations(t)
|
||||
db.GalleryChapter.AssertExpectations(t)
|
||||
db.Image.AssertExpectations(t)
|
||||
db.Movie.AssertExpectations(t)
|
||||
db.Group.AssertExpectations(t)
|
||||
db.Performer.AssertExpectations(t)
|
||||
db.Scene.AssertExpectations(t)
|
||||
db.SceneMarker.AssertExpectations(t)
|
||||
|
|
@ -96,7 +96,7 @@ func (db *Database) Repository() models.Repository {
|
|||
Gallery: db.Gallery,
|
||||
GalleryChapter: db.GalleryChapter,
|
||||
Image: db.Image,
|
||||
Movie: db.Movie,
|
||||
Group: db.Group,
|
||||
Performer: db.Performer,
|
||||
Scene: db.Scene,
|
||||
SceneMarker: db.SceneMarker,
|
||||
|
|
|
|||
|
|
@ -5,54 +5,54 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
type MoviesScenes struct {
|
||||
MovieID int `json:"movie_id"`
|
||||
type GroupsScenes struct {
|
||||
GroupID int `json:"movie_id"`
|
||||
// SceneID int `json:"scene_id"`
|
||||
SceneIndex *int `json:"scene_index"`
|
||||
}
|
||||
|
||||
func (s MoviesScenes) SceneMovieInput() SceneMovieInput {
|
||||
func (s GroupsScenes) SceneMovieInput() SceneMovieInput {
|
||||
return SceneMovieInput{
|
||||
MovieID: strconv.Itoa(s.MovieID),
|
||||
MovieID: strconv.Itoa(s.GroupID),
|
||||
SceneIndex: s.SceneIndex,
|
||||
}
|
||||
}
|
||||
|
||||
func (s MoviesScenes) Equal(o MoviesScenes) bool {
|
||||
return o.MovieID == s.MovieID && ((o.SceneIndex == nil && s.SceneIndex == nil) ||
|
||||
func (s GroupsScenes) Equal(o GroupsScenes) bool {
|
||||
return o.GroupID == s.GroupID && ((o.SceneIndex == nil && s.SceneIndex == nil) ||
|
||||
(o.SceneIndex != nil && s.SceneIndex != nil && *o.SceneIndex == *s.SceneIndex))
|
||||
}
|
||||
|
||||
type UpdateMovieIDs struct {
|
||||
Movies []MoviesScenes `json:"movies"`
|
||||
type UpdateGroupIDs struct {
|
||||
Groups []GroupsScenes `json:"movies"`
|
||||
Mode RelationshipUpdateMode `json:"mode"`
|
||||
}
|
||||
|
||||
func (u *UpdateMovieIDs) SceneMovieInputs() []SceneMovieInput {
|
||||
func (u *UpdateGroupIDs) SceneMovieInputs() []SceneMovieInput {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := make([]SceneMovieInput, len(u.Movies))
|
||||
for _, id := range u.Movies {
|
||||
ret := make([]SceneMovieInput, len(u.Groups))
|
||||
for _, id := range u.Groups {
|
||||
ret = append(ret, id.SceneMovieInput())
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (u *UpdateMovieIDs) AddUnique(v MoviesScenes) {
|
||||
for _, vv := range u.Movies {
|
||||
if vv.MovieID == v.MovieID {
|
||||
func (u *UpdateGroupIDs) AddUnique(v GroupsScenes) {
|
||||
for _, vv := range u.Groups {
|
||||
if vv.GroupID == v.GroupID {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
u.Movies = append(u.Movies, v)
|
||||
u.Groups = append(u.Groups, v)
|
||||
}
|
||||
|
||||
func MoviesScenesFromInput(input []SceneMovieInput) ([]MoviesScenes, error) {
|
||||
ret := make([]MoviesScenes, len(input))
|
||||
func GroupsScenesFromInput(input []SceneMovieInput) ([]GroupsScenes, error) {
|
||||
ret := make([]GroupsScenes, len(input))
|
||||
|
||||
for i, v := range input {
|
||||
mID, err := strconv.Atoi(v.MovieID)
|
||||
|
|
@ -60,8 +60,8 @@ func MoviesScenesFromInput(input []SceneMovieInput) ([]MoviesScenes, error) {
|
|||
return nil, fmt.Errorf("invalid movie ID: %s", v.MovieID)
|
||||
}
|
||||
|
||||
ret[i] = MoviesScenes{
|
||||
MovieID: mID,
|
||||
ret[i] = GroupsScenes{
|
||||
GroupID: mID,
|
||||
SceneIndex: v.SceneIndex,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type Movie struct {
|
||||
type Group struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Aliases string `json:"aliases"`
|
||||
|
|
@ -23,27 +23,27 @@ type Movie struct {
|
|||
TagIDs RelatedIDs `json:"tag_ids"`
|
||||
}
|
||||
|
||||
func NewMovie() Movie {
|
||||
func NewGroup() Group {
|
||||
currentTime := time.Now()
|
||||
return Movie{
|
||||
return Group{
|
||||
CreatedAt: currentTime,
|
||||
UpdatedAt: currentTime,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Movie) LoadURLs(ctx context.Context, l URLLoader) error {
|
||||
func (m *Group) LoadURLs(ctx context.Context, l URLLoader) error {
|
||||
return m.URLs.load(func() ([]string, error) {
|
||||
return l.GetURLs(ctx, m.ID)
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Movie) LoadTagIDs(ctx context.Context, l TagIDLoader) error {
|
||||
func (m *Group) LoadTagIDs(ctx context.Context, l TagIDLoader) error {
|
||||
return m.TagIDs.load(func() ([]int, error) {
|
||||
return l.GetTagIDs(ctx, m.ID)
|
||||
})
|
||||
}
|
||||
|
||||
type MoviePartial struct {
|
||||
type GroupPartial struct {
|
||||
Name OptionalString
|
||||
Aliases OptionalString
|
||||
Duration OptionalInt
|
||||
|
|
@ -59,9 +59,9 @@ type MoviePartial struct {
|
|||
UpdatedAt OptionalTime
|
||||
}
|
||||
|
||||
func NewMoviePartial() MoviePartial {
|
||||
func NewGroupPartial() GroupPartial {
|
||||
currentTime := time.Now()
|
||||
return MoviePartial{
|
||||
return GroupPartial{
|
||||
UpdatedAt: NewOptionalTime(currentTime),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ type Scene struct {
|
|||
GalleryIDs RelatedIDs `json:"gallery_ids"`
|
||||
TagIDs RelatedIDs `json:"tag_ids"`
|
||||
PerformerIDs RelatedIDs `json:"performer_ids"`
|
||||
Movies RelatedMovies `json:"movies"`
|
||||
Groups RelatedGroups `json:"groups"`
|
||||
StashIDs RelatedStashIDs `json:"stash_ids"`
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ type ScenePartial struct {
|
|||
GalleryIDs *UpdateIDs
|
||||
TagIDs *UpdateIDs
|
||||
PerformerIDs *UpdateIDs
|
||||
MovieIDs *UpdateMovieIDs
|
||||
GroupIDs *UpdateGroupIDs
|
||||
StashIDs *UpdateStashIDs
|
||||
PrimaryFileID *FileID
|
||||
}
|
||||
|
|
@ -139,9 +139,9 @@ func (s *Scene) LoadTagIDs(ctx context.Context, l TagIDLoader) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (s *Scene) LoadMovies(ctx context.Context, l SceneMovieLoader) error {
|
||||
return s.Movies.load(func() ([]MoviesScenes, error) {
|
||||
return l.GetMovies(ctx, s.ID)
|
||||
func (s *Scene) LoadGroups(ctx context.Context, l SceneGroupLoader) error {
|
||||
return s.Groups.load(func() ([]GroupsScenes, error) {
|
||||
return l.GetGroups(ctx, s.ID)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ func (s *Scene) LoadRelationships(ctx context.Context, l SceneReader) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := s.LoadMovies(ctx, l); err != nil {
|
||||
if err := s.LoadGroups(ctx, l); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ func (s ScenePartial) UpdateInput(id int) SceneUpdateInput {
|
|||
StudioID: s.StudioID.StringPtr(),
|
||||
GalleryIds: s.GalleryIDs.IDStrings(),
|
||||
PerformerIds: s.PerformerIDs.IDStrings(),
|
||||
Movies: s.MovieIDs.SceneMovieInputs(),
|
||||
Movies: s.GroupIDs.SceneMovieInputs(),
|
||||
TagIds: s.TagIDs.IDStrings(),
|
||||
StashIds: stashIDs,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,6 +415,30 @@ type ScrapedMovie struct {
|
|||
|
||||
func (ScrapedMovie) IsScrapedContent() {}
|
||||
|
||||
func (m ScrapedMovie) ScrapedGroup() ScrapedGroup {
|
||||
ret := ScrapedGroup{
|
||||
StoredID: m.StoredID,
|
||||
Name: m.Name,
|
||||
Aliases: m.Aliases,
|
||||
Duration: m.Duration,
|
||||
Date: m.Date,
|
||||
Rating: m.Rating,
|
||||
Director: m.Director,
|
||||
URLs: m.URLs,
|
||||
Synopsis: m.Synopsis,
|
||||
Studio: m.Studio,
|
||||
Tags: m.Tags,
|
||||
FrontImage: m.FrontImage,
|
||||
BackImage: m.BackImage,
|
||||
}
|
||||
|
||||
if len(m.URLs) == 0 && m.URL != nil {
|
||||
ret.URLs = []string{*m.URL}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// ScrapedGroup is a group from a scraping operation
|
||||
type ScrapedGroup struct {
|
||||
StoredID *string `json:"stored_id"`
|
||||
|
|
@ -435,3 +459,27 @@ type ScrapedGroup struct {
|
|||
}
|
||||
|
||||
func (ScrapedGroup) IsScrapedContent() {}
|
||||
|
||||
func (g ScrapedGroup) ScrapedMovie() ScrapedMovie {
|
||||
ret := ScrapedMovie{
|
||||
StoredID: g.StoredID,
|
||||
Name: g.Name,
|
||||
Aliases: g.Aliases,
|
||||
Duration: g.Duration,
|
||||
Date: g.Date,
|
||||
Rating: g.Rating,
|
||||
Director: g.Director,
|
||||
URLs: g.URLs,
|
||||
Synopsis: g.Synopsis,
|
||||
Studio: g.Studio,
|
||||
Tags: g.Tags,
|
||||
FrontImage: g.FrontImage,
|
||||
BackImage: g.BackImage,
|
||||
}
|
||||
|
||||
if len(g.URLs) > 0 {
|
||||
ret.URL = &g.URLs[0]
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package models
|
||||
|
||||
type MovieFilterType struct {
|
||||
OperatorFilter[MovieFilterType]
|
||||
type GroupFilterType struct {
|
||||
OperatorFilter[GroupFilterType]
|
||||
Name *StringCriterionInput `json:"name"`
|
||||
Director *StringCriterionInput `json:"director"`
|
||||
Synopsis *StringCriterionInput `json:"synopsis"`
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ type JSONPaths struct {
|
|||
Galleries string
|
||||
Studios string
|
||||
Tags string
|
||||
Movies string
|
||||
Groups string
|
||||
Files string
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ func newJSONPaths(baseDir string) *JSONPaths {
|
|||
jp.Images = filepath.Join(baseDir, "images")
|
||||
jp.Galleries = filepath.Join(baseDir, "galleries")
|
||||
jp.Studios = filepath.Join(baseDir, "studios")
|
||||
jp.Movies = filepath.Join(baseDir, "movies")
|
||||
jp.Groups = filepath.Join(baseDir, "movies")
|
||||
jp.Tags = filepath.Join(baseDir, "tags")
|
||||
jp.Files = filepath.Join(baseDir, "files")
|
||||
return &jp
|
||||
|
|
@ -49,7 +49,7 @@ func EmptyJSONDirs(baseDir string) {
|
|||
_ = fsutil.EmptyDir(jsonPaths.Galleries)
|
||||
_ = fsutil.EmptyDir(jsonPaths.Performers)
|
||||
_ = fsutil.EmptyDir(jsonPaths.Studios)
|
||||
_ = fsutil.EmptyDir(jsonPaths.Movies)
|
||||
_ = fsutil.EmptyDir(jsonPaths.Groups)
|
||||
_ = fsutil.EmptyDir(jsonPaths.Tags)
|
||||
_ = fsutil.EmptyDir(jsonPaths.Files)
|
||||
}
|
||||
|
|
@ -74,8 +74,8 @@ func EnsureJSONDirs(baseDir string) {
|
|||
if err := fsutil.EnsureDir(jsonPaths.Studios); err != nil {
|
||||
logger.Warnf("couldn't create directories for Studios: %v", err)
|
||||
}
|
||||
if err := fsutil.EnsureDir(jsonPaths.Movies); err != nil {
|
||||
logger.Warnf("couldn't create directories for Movies: %v", err)
|
||||
if err := fsutil.EnsureDir(jsonPaths.Groups); err != nil {
|
||||
logger.Warnf("couldn't create directories for Groups: %v", err)
|
||||
}
|
||||
if err := fsutil.EnsureDir(jsonPaths.Tags); err != nil {
|
||||
logger.Warnf("couldn't create directories for Tags: %v", err)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ type FileIDLoader interface {
|
|||
GetManyFileIDs(ctx context.Context, ids []int) ([][]FileID, error)
|
||||
}
|
||||
|
||||
type SceneMovieLoader interface {
|
||||
GetMovies(ctx context.Context, id int) ([]MoviesScenes, error)
|
||||
type SceneGroupLoader interface {
|
||||
GetGroups(ctx context.Context, id int) ([]GroupsScenes, error)
|
||||
}
|
||||
|
||||
type StashIDLoader interface {
|
||||
|
|
@ -115,50 +115,50 @@ func (r *RelatedIDs) load(fn func() ([]int, error)) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RelatedMovies represents a list of related Movies.
|
||||
type RelatedMovies struct {
|
||||
list []MoviesScenes
|
||||
// RelatedGroups represents a list of related Groups.
|
||||
type RelatedGroups struct {
|
||||
list []GroupsScenes
|
||||
}
|
||||
|
||||
// NewRelatedMovies returns a loaded RelatedMovies object with the provided movies.
|
||||
// NewRelatedGroups returns a loaded RelateGroups object with the provided groups.
|
||||
// Loaded will return true when called on the returned object if the provided slice is not nil.
|
||||
func NewRelatedMovies(list []MoviesScenes) RelatedMovies {
|
||||
return RelatedMovies{
|
||||
func NewRelatedGroups(list []GroupsScenes) RelatedGroups {
|
||||
return RelatedGroups{
|
||||
list: list,
|
||||
}
|
||||
}
|
||||
|
||||
// Loaded returns true if the relationship has been loaded.
|
||||
func (r RelatedMovies) Loaded() bool {
|
||||
func (r RelatedGroups) Loaded() bool {
|
||||
return r.list != nil
|
||||
}
|
||||
|
||||
func (r RelatedMovies) mustLoaded() {
|
||||
func (r RelatedGroups) mustLoaded() {
|
||||
if !r.Loaded() {
|
||||
panic("list has not been loaded")
|
||||
}
|
||||
}
|
||||
|
||||
// List returns the related Movies. Panics if the relationship has not been loaded.
|
||||
func (r RelatedMovies) List() []MoviesScenes {
|
||||
// List returns the related Groups. Panics if the relationship has not been loaded.
|
||||
func (r RelatedGroups) List() []GroupsScenes {
|
||||
r.mustLoaded()
|
||||
|
||||
return r.list
|
||||
}
|
||||
|
||||
// Add adds the provided ids to the list. Panics if the relationship has not been loaded.
|
||||
func (r *RelatedMovies) Add(movies ...MoviesScenes) {
|
||||
func (r *RelatedGroups) Add(groups ...GroupsScenes) {
|
||||
r.mustLoaded()
|
||||
|
||||
r.list = append(r.list, movies...)
|
||||
r.list = append(r.list, groups...)
|
||||
}
|
||||
|
||||
// ForID returns the MoviesScenes object for the given movie ID. Returns nil if not found.
|
||||
func (r *RelatedMovies) ForID(id int) *MoviesScenes {
|
||||
// ForID returns the GroupsScenes object for the given group ID. Returns nil if not found.
|
||||
func (r *RelatedGroups) ForID(id int) *GroupsScenes {
|
||||
r.mustLoaded()
|
||||
|
||||
for _, v := range r.list {
|
||||
if v.MovieID == id {
|
||||
if v.GroupID == id {
|
||||
return &v
|
||||
}
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ func (r *RelatedMovies) ForID(id int) *MoviesScenes {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *RelatedMovies) load(fn func() ([]MoviesScenes, error)) error {
|
||||
func (r *RelatedGroups) load(fn func() ([]GroupsScenes, error)) error {
|
||||
if r.Loaded() {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ func (r *RelatedMovies) load(fn func() ([]MoviesScenes, error)) error {
|
|||
}
|
||||
|
||||
if ids == nil {
|
||||
ids = []MoviesScenes{}
|
||||
ids = []GroupsScenes{}
|
||||
}
|
||||
|
||||
r.list = ids
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ type Repository struct {
|
|||
Gallery GalleryReaderWriter
|
||||
GalleryChapter GalleryChapterReaderWriter
|
||||
Image ImageReaderWriter
|
||||
Movie MovieReaderWriter
|
||||
Group GroupReaderWriter
|
||||
Performer PerformerReaderWriter
|
||||
Scene SceneReaderWriter
|
||||
SceneMarker SceneMarkerReaderWriter
|
||||
|
|
|
|||
|
|
@ -2,87 +2,87 @@ package models
|
|||
|
||||
import "context"
|
||||
|
||||
// MovieGetter provides methods to get movies by ID.
|
||||
type MovieGetter interface {
|
||||
// GroupGetter provides methods to get groups by ID.
|
||||
type GroupGetter interface {
|
||||
// TODO - rename this to Find and remove existing method
|
||||
FindMany(ctx context.Context, ids []int) ([]*Movie, error)
|
||||
Find(ctx context.Context, id int) (*Movie, error)
|
||||
FindMany(ctx context.Context, ids []int) ([]*Group, error)
|
||||
Find(ctx context.Context, id int) (*Group, error)
|
||||
}
|
||||
|
||||
// MovieFinder provides methods to find movies.
|
||||
type MovieFinder interface {
|
||||
MovieGetter
|
||||
FindByPerformerID(ctx context.Context, performerID int) ([]*Movie, error)
|
||||
FindByStudioID(ctx context.Context, studioID int) ([]*Movie, error)
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*Movie, error)
|
||||
FindByNames(ctx context.Context, names []string, nocase bool) ([]*Movie, error)
|
||||
// GroupFinder provides methods to find groups.
|
||||
type GroupFinder interface {
|
||||
GroupGetter
|
||||
FindByPerformerID(ctx context.Context, performerID int) ([]*Group, error)
|
||||
FindByStudioID(ctx context.Context, studioID int) ([]*Group, error)
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*Group, error)
|
||||
FindByNames(ctx context.Context, names []string, nocase bool) ([]*Group, error)
|
||||
}
|
||||
|
||||
// MovieQueryer provides methods to query movies.
|
||||
type MovieQueryer interface {
|
||||
Query(ctx context.Context, movieFilter *MovieFilterType, findFilter *FindFilterType) ([]*Movie, int, error)
|
||||
QueryCount(ctx context.Context, movieFilter *MovieFilterType, findFilter *FindFilterType) (int, error)
|
||||
// GroupQueryer provides methods to query groups.
|
||||
type GroupQueryer interface {
|
||||
Query(ctx context.Context, groupFilter *GroupFilterType, findFilter *FindFilterType) ([]*Group, int, error)
|
||||
QueryCount(ctx context.Context, groupFilter *GroupFilterType, findFilter *FindFilterType) (int, error)
|
||||
}
|
||||
|
||||
// MovieCounter provides methods to count movies.
|
||||
type MovieCounter interface {
|
||||
// GroupCounter provides methods to count groups.
|
||||
type GroupCounter interface {
|
||||
Count(ctx context.Context) (int, error)
|
||||
CountByPerformerID(ctx context.Context, performerID int) (int, error)
|
||||
CountByStudioID(ctx context.Context, studioID int) (int, error)
|
||||
}
|
||||
|
||||
// MovieCreator provides methods to create movies.
|
||||
type MovieCreator interface {
|
||||
Create(ctx context.Context, newMovie *Movie) error
|
||||
// GroupCreator provides methods to create groups.
|
||||
type GroupCreator interface {
|
||||
Create(ctx context.Context, newGroup *Group) error
|
||||
}
|
||||
|
||||
// MovieUpdater provides methods to update movies.
|
||||
type MovieUpdater interface {
|
||||
Update(ctx context.Context, updatedMovie *Movie) error
|
||||
UpdatePartial(ctx context.Context, id int, updatedMovie MoviePartial) (*Movie, error)
|
||||
UpdateFrontImage(ctx context.Context, movieID int, frontImage []byte) error
|
||||
UpdateBackImage(ctx context.Context, movieID int, backImage []byte) error
|
||||
// GroupUpdater provides methods to update groups.
|
||||
type GroupUpdater interface {
|
||||
Update(ctx context.Context, updatedGroup *Group) error
|
||||
UpdatePartial(ctx context.Context, id int, updatedGroup GroupPartial) (*Group, error)
|
||||
UpdateFrontImage(ctx context.Context, groupID int, frontImage []byte) error
|
||||
UpdateBackImage(ctx context.Context, groupID int, backImage []byte) error
|
||||
}
|
||||
|
||||
// MovieDestroyer provides methods to destroy movies.
|
||||
type MovieDestroyer interface {
|
||||
// GroupDestroyer provides methods to destroy groups.
|
||||
type GroupDestroyer interface {
|
||||
Destroy(ctx context.Context, id int) error
|
||||
}
|
||||
|
||||
type MovieCreatorUpdater interface {
|
||||
MovieCreator
|
||||
MovieUpdater
|
||||
type GroupCreatorUpdater interface {
|
||||
GroupCreator
|
||||
GroupUpdater
|
||||
}
|
||||
|
||||
type MovieFinderCreator interface {
|
||||
MovieFinder
|
||||
MovieCreator
|
||||
type GroupFinderCreator interface {
|
||||
GroupFinder
|
||||
GroupCreator
|
||||
}
|
||||
|
||||
// MovieReader provides all methods to read movies.
|
||||
type MovieReader interface {
|
||||
MovieFinder
|
||||
MovieQueryer
|
||||
MovieCounter
|
||||
// GroupReader provides all methods to read groups.
|
||||
type GroupReader interface {
|
||||
GroupFinder
|
||||
GroupQueryer
|
||||
GroupCounter
|
||||
URLLoader
|
||||
TagIDLoader
|
||||
|
||||
All(ctx context.Context) ([]*Movie, error)
|
||||
GetFrontImage(ctx context.Context, movieID int) ([]byte, error)
|
||||
HasFrontImage(ctx context.Context, movieID int) (bool, error)
|
||||
GetBackImage(ctx context.Context, movieID int) ([]byte, error)
|
||||
HasBackImage(ctx context.Context, movieID int) (bool, error)
|
||||
All(ctx context.Context) ([]*Group, error)
|
||||
GetFrontImage(ctx context.Context, groupID int) ([]byte, error)
|
||||
HasFrontImage(ctx context.Context, groupID int) (bool, error)
|
||||
GetBackImage(ctx context.Context, groupID int) ([]byte, error)
|
||||
HasBackImage(ctx context.Context, groupID int) (bool, error)
|
||||
}
|
||||
|
||||
// MovieWriter provides all methods to modify movies.
|
||||
type MovieWriter interface {
|
||||
MovieCreator
|
||||
MovieUpdater
|
||||
MovieDestroyer
|
||||
// GroupWriter provides all methods to modify groups.
|
||||
type GroupWriter interface {
|
||||
GroupCreator
|
||||
GroupUpdater
|
||||
GroupDestroyer
|
||||
}
|
||||
|
||||
// MovieReaderWriter provides all movie methods.
|
||||
type MovieReaderWriter interface {
|
||||
MovieReader
|
||||
MovieWriter
|
||||
// GroupReaderWriter provides all group methods.
|
||||
type GroupReaderWriter interface {
|
||||
GroupReader
|
||||
GroupWriter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ type SceneFinder interface {
|
|||
FindByPrimaryFileID(ctx context.Context, fileID FileID) ([]*Scene, error)
|
||||
FindByPerformerID(ctx context.Context, performerID int) ([]*Scene, error)
|
||||
FindByGalleryID(ctx context.Context, performerID int) ([]*Scene, error)
|
||||
FindByMovieID(ctx context.Context, movieID int) ([]*Scene, error)
|
||||
FindByGroupID(ctx context.Context, groupID int) ([]*Scene, error)
|
||||
FindDuplicates(ctx context.Context, distance int, durationDiff float64) ([][]*Scene, error)
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ type SceneQueryer interface {
|
|||
type SceneCounter interface {
|
||||
Count(ctx context.Context) (int, error)
|
||||
CountByPerformerID(ctx context.Context, performerID int) (int, error)
|
||||
CountByMovieID(ctx context.Context, movieID int) (int, error)
|
||||
CountByGroupID(ctx context.Context, groupID int) (int, error)
|
||||
CountByFileID(ctx context.Context, fileID FileID) (int, error)
|
||||
CountByStudioID(ctx context.Context, studioID int) (int, error)
|
||||
CountByTagID(ctx context.Context, tagID int) (int, error)
|
||||
|
|
@ -99,7 +99,7 @@ type SceneReader interface {
|
|||
GalleryIDLoader
|
||||
PerformerIDLoader
|
||||
TagIDLoader
|
||||
SceneMovieLoader
|
||||
SceneGroupLoader
|
||||
StashIDLoader
|
||||
VideoFileLoader
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ type TagFinder interface {
|
|||
FindByImageID(ctx context.Context, imageID int) ([]*Tag, error)
|
||||
FindByGalleryID(ctx context.Context, galleryID int) ([]*Tag, error)
|
||||
FindByPerformerID(ctx context.Context, performerID int) ([]*Tag, error)
|
||||
FindByMovieID(ctx context.Context, movieID int) ([]*Tag, error)
|
||||
FindByGroupID(ctx context.Context, groupID int) ([]*Tag, error)
|
||||
FindBySceneMarkerID(ctx context.Context, sceneMarkerID int) ([]*Tag, error)
|
||||
FindByStudioID(ctx context.Context, studioID int) ([]*Tag, error)
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*Tag, error)
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ type SceneFilterType struct {
|
|||
// Filter by related tags that meet this criteria
|
||||
TagsFilter *TagFilterType `json:"tags_filter"`
|
||||
// Filter by related groups that meet this criteria
|
||||
GroupsFilter *MovieFilterType `json:"groups_filter"`
|
||||
GroupsFilter *GroupFilterType `json:"groups_filter"`
|
||||
// Filter by related movies that meet this criteria
|
||||
MoviesFilter *MovieFilterType `json:"movies_filter"`
|
||||
MoviesFilter *GroupFilterType `json:"movies_filter"`
|
||||
// Filter by related markers that meet this criteria
|
||||
MarkersFilter *SceneMarkerFilterType `json:"markers_filter"`
|
||||
// Filter by created at
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ type ImageGetter interface {
|
|||
}
|
||||
|
||||
// ToJSON converts a Movie into its JSON equivalent.
|
||||
func ToJSON(ctx context.Context, reader ImageGetter, studioReader models.StudioGetter, movie *models.Movie) (*jsonschema.Movie, error) {
|
||||
newMovieJSON := jsonschema.Movie{
|
||||
func ToJSON(ctx context.Context, reader ImageGetter, studioReader models.StudioGetter, movie *models.Group) (*jsonschema.Group, error) {
|
||||
newMovieJSON := jsonschema.Group{
|
||||
Name: movie.Name,
|
||||
Aliases: movie.Aliases,
|
||||
Director: movie.Director,
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ var (
|
|||
updateTime = time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC)
|
||||
)
|
||||
|
||||
func createFullMovie(id int, studioID int) models.Movie {
|
||||
return models.Movie{
|
||||
func createFullMovie(id int, studioID int) models.Group {
|
||||
return models.Group{
|
||||
ID: id,
|
||||
Name: movieName,
|
||||
Aliases: movieAliases,
|
||||
|
|
@ -79,8 +79,8 @@ func createFullMovie(id int, studioID int) models.Movie {
|
|||
}
|
||||
}
|
||||
|
||||
func createEmptyMovie(id int) models.Movie {
|
||||
return models.Movie{
|
||||
func createEmptyMovie(id int) models.Group {
|
||||
return models.Group{
|
||||
ID: id,
|
||||
URLs: models.NewRelatedStrings([]string{}),
|
||||
CreatedAt: createTime,
|
||||
|
|
@ -88,8 +88,8 @@ func createEmptyMovie(id int) models.Movie {
|
|||
}
|
||||
}
|
||||
|
||||
func createFullJSONMovie(studio, frontImage, backImage string) *jsonschema.Movie {
|
||||
return &jsonschema.Movie{
|
||||
func createFullJSONMovie(studio, frontImage, backImage string) *jsonschema.Group {
|
||||
return &jsonschema.Group{
|
||||
Name: movieName,
|
||||
Aliases: movieAliases,
|
||||
Date: date,
|
||||
|
|
@ -110,8 +110,8 @@ func createFullJSONMovie(studio, frontImage, backImage string) *jsonschema.Movie
|
|||
}
|
||||
}
|
||||
|
||||
func createEmptyJSONMovie() *jsonschema.Movie {
|
||||
return &jsonschema.Movie{
|
||||
func createEmptyJSONMovie() *jsonschema.Group {
|
||||
return &jsonschema.Group{
|
||||
URLs: []string{},
|
||||
CreatedAt: json.JSONTime{
|
||||
Time: createTime,
|
||||
|
|
@ -123,8 +123,8 @@ func createEmptyJSONMovie() *jsonschema.Movie {
|
|||
}
|
||||
|
||||
type testScenario struct {
|
||||
movie models.Movie
|
||||
expected *jsonschema.Movie
|
||||
movie models.Group
|
||||
expected *jsonschema.Group
|
||||
err bool
|
||||
}
|
||||
|
||||
|
|
@ -174,18 +174,18 @@ func TestToJSON(t *testing.T) {
|
|||
|
||||
imageErr := errors.New("error getting image")
|
||||
|
||||
db.Movie.On("GetFrontImage", testCtx, movieID).Return(frontImageBytes, nil).Once()
|
||||
db.Movie.On("GetFrontImage", testCtx, missingStudioMovieID).Return(frontImageBytes, nil).Once()
|
||||
db.Movie.On("GetFrontImage", testCtx, emptyID).Return(nil, nil).Once().Maybe()
|
||||
db.Movie.On("GetFrontImage", testCtx, errFrontImageID).Return(nil, imageErr).Once()
|
||||
db.Movie.On("GetFrontImage", testCtx, errBackImageID).Return(frontImageBytes, nil).Once()
|
||||
db.Group.On("GetFrontImage", testCtx, movieID).Return(frontImageBytes, nil).Once()
|
||||
db.Group.On("GetFrontImage", testCtx, missingStudioMovieID).Return(frontImageBytes, nil).Once()
|
||||
db.Group.On("GetFrontImage", testCtx, emptyID).Return(nil, nil).Once().Maybe()
|
||||
db.Group.On("GetFrontImage", testCtx, errFrontImageID).Return(nil, imageErr).Once()
|
||||
db.Group.On("GetFrontImage", testCtx, errBackImageID).Return(frontImageBytes, nil).Once()
|
||||
|
||||
db.Movie.On("GetBackImage", testCtx, movieID).Return(backImageBytes, nil).Once()
|
||||
db.Movie.On("GetBackImage", testCtx, missingStudioMovieID).Return(backImageBytes, nil).Once()
|
||||
db.Movie.On("GetBackImage", testCtx, emptyID).Return(nil, nil).Once()
|
||||
db.Movie.On("GetBackImage", testCtx, errBackImageID).Return(nil, imageErr).Once()
|
||||
db.Movie.On("GetBackImage", testCtx, errFrontImageID).Return(backImageBytes, nil).Maybe()
|
||||
db.Movie.On("GetBackImage", testCtx, errStudioMovieID).Return(backImageBytes, nil).Maybe()
|
||||
db.Group.On("GetBackImage", testCtx, movieID).Return(backImageBytes, nil).Once()
|
||||
db.Group.On("GetBackImage", testCtx, missingStudioMovieID).Return(backImageBytes, nil).Once()
|
||||
db.Group.On("GetBackImage", testCtx, emptyID).Return(nil, nil).Once()
|
||||
db.Group.On("GetBackImage", testCtx, errBackImageID).Return(nil, imageErr).Once()
|
||||
db.Group.On("GetBackImage", testCtx, errFrontImageID).Return(backImageBytes, nil).Maybe()
|
||||
db.Group.On("GetBackImage", testCtx, errStudioMovieID).Return(backImageBytes, nil).Maybe()
|
||||
|
||||
studioErr := errors.New("error getting studio")
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ func TestToJSON(t *testing.T) {
|
|||
|
||||
for i, s := range scenarios {
|
||||
movie := s.movie
|
||||
json, err := ToJSON(testCtx, db.Movie, db.Studio, &movie)
|
||||
json, err := ToJSON(testCtx, db.Group, db.Studio, &movie)
|
||||
|
||||
switch {
|
||||
case !s.err && err != nil:
|
||||
|
|
|
|||
|
|
@ -12,24 +12,24 @@ import (
|
|||
)
|
||||
|
||||
type ImporterReaderWriter interface {
|
||||
models.MovieCreatorUpdater
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*models.Movie, error)
|
||||
models.GroupCreatorUpdater
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*models.Group, error)
|
||||
}
|
||||
|
||||
type Importer struct {
|
||||
ReaderWriter ImporterReaderWriter
|
||||
StudioWriter models.StudioFinderCreator
|
||||
TagWriter models.TagFinderCreator
|
||||
Input jsonschema.Movie
|
||||
Input jsonschema.Group
|
||||
MissingRefBehaviour models.ImportMissingRefEnum
|
||||
|
||||
movie models.Movie
|
||||
group models.Group
|
||||
frontImageData []byte
|
||||
backImageData []byte
|
||||
}
|
||||
|
||||
func (i *Importer) PreImport(ctx context.Context) error {
|
||||
i.movie = i.movieJSONToMovie(i.Input)
|
||||
i.group = i.groupJSONToGroup(i.Input)
|
||||
|
||||
if err := i.populateStudio(ctx); err != nil {
|
||||
return err
|
||||
|
|
@ -65,7 +65,7 @@ func (i *Importer) populateTags(ctx context.Context) error {
|
|||
}
|
||||
|
||||
for _, p := range tags {
|
||||
i.movie.TagIDs.Add(p.ID)
|
||||
i.group.TagIDs.Add(p.ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,38 +124,38 @@ func createTags(ctx context.Context, tagWriter models.TagFinderCreator, names []
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (i *Importer) movieJSONToMovie(movieJSON jsonschema.Movie) models.Movie {
|
||||
newMovie := models.Movie{
|
||||
Name: movieJSON.Name,
|
||||
Aliases: movieJSON.Aliases,
|
||||
Director: movieJSON.Director,
|
||||
Synopsis: movieJSON.Synopsis,
|
||||
CreatedAt: movieJSON.CreatedAt.GetTime(),
|
||||
UpdatedAt: movieJSON.UpdatedAt.GetTime(),
|
||||
func (i *Importer) groupJSONToGroup(groupJSON jsonschema.Group) models.Group {
|
||||
newGroup := models.Group{
|
||||
Name: groupJSON.Name,
|
||||
Aliases: groupJSON.Aliases,
|
||||
Director: groupJSON.Director,
|
||||
Synopsis: groupJSON.Synopsis,
|
||||
CreatedAt: groupJSON.CreatedAt.GetTime(),
|
||||
UpdatedAt: groupJSON.UpdatedAt.GetTime(),
|
||||
|
||||
TagIDs: models.NewRelatedIDs([]int{}),
|
||||
}
|
||||
|
||||
if len(movieJSON.URLs) > 0 {
|
||||
newMovie.URLs = models.NewRelatedStrings(movieJSON.URLs)
|
||||
} else if movieJSON.URL != "" {
|
||||
newMovie.URLs = models.NewRelatedStrings([]string{movieJSON.URL})
|
||||
if len(groupJSON.URLs) > 0 {
|
||||
newGroup.URLs = models.NewRelatedStrings(groupJSON.URLs)
|
||||
} else if groupJSON.URL != "" {
|
||||
newGroup.URLs = models.NewRelatedStrings([]string{groupJSON.URL})
|
||||
}
|
||||
if movieJSON.Date != "" {
|
||||
d, err := models.ParseDate(movieJSON.Date)
|
||||
if groupJSON.Date != "" {
|
||||
d, err := models.ParseDate(groupJSON.Date)
|
||||
if err == nil {
|
||||
newMovie.Date = &d
|
||||
newGroup.Date = &d
|
||||
}
|
||||
}
|
||||
if movieJSON.Rating != 0 {
|
||||
newMovie.Rating = &movieJSON.Rating
|
||||
if groupJSON.Rating != 0 {
|
||||
newGroup.Rating = &groupJSON.Rating
|
||||
}
|
||||
|
||||
if movieJSON.Duration != 0 {
|
||||
newMovie.Duration = &movieJSON.Duration
|
||||
if groupJSON.Duration != 0 {
|
||||
newGroup.Duration = &groupJSON.Duration
|
||||
}
|
||||
|
||||
return newMovie
|
||||
return newGroup
|
||||
}
|
||||
|
||||
func (i *Importer) populateStudio(ctx context.Context) error {
|
||||
|
|
@ -167,7 +167,7 @@ func (i *Importer) populateStudio(ctx context.Context) error {
|
|||
|
||||
if studio == nil {
|
||||
if i.MissingRefBehaviour == models.ImportMissingRefEnumFail {
|
||||
return fmt.Errorf("movie studio '%s' not found", i.Input.Studio)
|
||||
return fmt.Errorf("group studio '%s' not found", i.Input.Studio)
|
||||
}
|
||||
|
||||
if i.MissingRefBehaviour == models.ImportMissingRefEnumIgnore {
|
||||
|
|
@ -179,10 +179,10 @@ func (i *Importer) populateStudio(ctx context.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.movie.StudioID = &studioID
|
||||
i.group.StudioID = &studioID
|
||||
}
|
||||
} else {
|
||||
i.movie.StudioID = &studio.ID
|
||||
i.group.StudioID = &studio.ID
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -204,13 +204,13 @@ func (i *Importer) createStudio(ctx context.Context, name string) (int, error) {
|
|||
func (i *Importer) PostImport(ctx context.Context, id int) error {
|
||||
if len(i.frontImageData) > 0 {
|
||||
if err := i.ReaderWriter.UpdateFrontImage(ctx, id, i.frontImageData); err != nil {
|
||||
return fmt.Errorf("error setting movie front image: %v", err)
|
||||
return fmt.Errorf("error setting group front image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(i.backImageData) > 0 {
|
||||
if err := i.ReaderWriter.UpdateBackImage(ctx, id, i.backImageData); err != nil {
|
||||
return fmt.Errorf("error setting movie back image: %v", err)
|
||||
return fmt.Errorf("error setting group back image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,21 +237,21 @@ func (i *Importer) FindExistingID(ctx context.Context) (*int, error) {
|
|||
}
|
||||
|
||||
func (i *Importer) Create(ctx context.Context) (*int, error) {
|
||||
err := i.ReaderWriter.Create(ctx, &i.movie)
|
||||
err := i.ReaderWriter.Create(ctx, &i.group)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating movie: %v", err)
|
||||
return nil, fmt.Errorf("error creating group: %v", err)
|
||||
}
|
||||
|
||||
id := i.movie.ID
|
||||
id := i.group.ID
|
||||
return &id, nil
|
||||
}
|
||||
|
||||
func (i *Importer) Update(ctx context.Context, id int) error {
|
||||
movie := i.movie
|
||||
movie.ID = id
|
||||
err := i.ReaderWriter.Update(ctx, &movie)
|
||||
group := i.group
|
||||
group.ID = id
|
||||
err := i.ReaderWriter.Update(ctx, &group)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating existing movie: %v", err)
|
||||
return fmt.Errorf("error updating existing group: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ var testCtx = context.Background()
|
|||
|
||||
func TestImporterName(t *testing.T) {
|
||||
i := Importer{
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Name: movieName,
|
||||
},
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ func TestImporterName(t *testing.T) {
|
|||
|
||||
func TestImporterPreImport(t *testing.T) {
|
||||
i := Importer{
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Name: movieName,
|
||||
FrontImage: invalidImage,
|
||||
},
|
||||
|
|
@ -79,9 +79,9 @@ func TestImporterPreImportWithStudio(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Name: movieName,
|
||||
FrontImage: frontImage,
|
||||
Studio: existingStudioName,
|
||||
|
|
@ -97,7 +97,7 @@ func TestImporterPreImportWithStudio(t *testing.T) {
|
|||
|
||||
err := i.PreImport(testCtx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, existingStudioID, *i.movie.StudioID)
|
||||
assert.Equal(t, existingStudioID, *i.group.StudioID)
|
||||
|
||||
i.Input.Studio = existingStudioErr
|
||||
err = i.PreImport(testCtx)
|
||||
|
|
@ -110,9 +110,9 @@ func TestImporterPreImportWithMissingStudio(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Name: movieName,
|
||||
FrontImage: frontImage,
|
||||
Studio: missingStudioName,
|
||||
|
|
@ -136,7 +136,7 @@ func TestImporterPreImportWithMissingStudio(t *testing.T) {
|
|||
i.MissingRefBehaviour = models.ImportMissingRefEnumCreate
|
||||
err = i.PreImport(testCtx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, existingStudioID, *i.movie.StudioID)
|
||||
assert.Equal(t, existingStudioID, *i.group.StudioID)
|
||||
|
||||
db.AssertExpectations(t)
|
||||
}
|
||||
|
|
@ -145,9 +145,9 @@ func TestImporterPreImportWithMissingStudioCreateErr(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Name: movieName,
|
||||
FrontImage: frontImage,
|
||||
Studio: missingStudioName,
|
||||
|
|
@ -168,10 +168,10 @@ func TestImporterPreImportWithTag(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
TagWriter: db.Tag,
|
||||
MissingRefBehaviour: models.ImportMissingRefEnumFail,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Tags: []string{
|
||||
existingTagName,
|
||||
},
|
||||
|
|
@ -188,7 +188,7 @@ func TestImporterPreImportWithTag(t *testing.T) {
|
|||
|
||||
err := i.PreImport(testCtx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, existingTagID, i.movie.TagIDs.List()[0])
|
||||
assert.Equal(t, existingTagID, i.group.TagIDs.List()[0])
|
||||
|
||||
i.Input.Tags = []string{existingTagErr}
|
||||
err = i.PreImport(testCtx)
|
||||
|
|
@ -201,9 +201,9 @@ func TestImporterPreImportWithMissingTag(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
TagWriter: db.Tag,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Tags: []string{
|
||||
missingTagName,
|
||||
},
|
||||
|
|
@ -227,7 +227,7 @@ func TestImporterPreImportWithMissingTag(t *testing.T) {
|
|||
i.MissingRefBehaviour = models.ImportMissingRefEnumCreate
|
||||
err = i.PreImport(testCtx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, existingTagID, i.movie.TagIDs.List()[0])
|
||||
assert.Equal(t, existingTagID, i.group.TagIDs.List()[0])
|
||||
|
||||
db.AssertExpectations(t)
|
||||
}
|
||||
|
|
@ -236,9 +236,9 @@ func TestImporterPreImportWithMissingTagCreateErr(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
TagWriter: db.Tag,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Tags: []string{
|
||||
missingTagName,
|
||||
},
|
||||
|
|
@ -259,7 +259,7 @@ func TestImporterPostImport(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
frontImageData: frontImageBytes,
|
||||
backImageData: backImageBytes,
|
||||
|
|
@ -267,9 +267,9 @@ func TestImporterPostImport(t *testing.T) {
|
|||
|
||||
updateMovieImageErr := errors.New("UpdateImages error")
|
||||
|
||||
db.Movie.On("UpdateFrontImage", testCtx, movieID, frontImageBytes).Return(nil).Once()
|
||||
db.Movie.On("UpdateBackImage", testCtx, movieID, backImageBytes).Return(nil).Once()
|
||||
db.Movie.On("UpdateFrontImage", testCtx, errImageID, frontImageBytes).Return(updateMovieImageErr).Once()
|
||||
db.Group.On("UpdateFrontImage", testCtx, movieID, frontImageBytes).Return(nil).Once()
|
||||
db.Group.On("UpdateBackImage", testCtx, movieID, backImageBytes).Return(nil).Once()
|
||||
db.Group.On("UpdateFrontImage", testCtx, errImageID, frontImageBytes).Return(updateMovieImageErr).Once()
|
||||
|
||||
err := i.PostImport(testCtx, movieID)
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -284,19 +284,19 @@ func TestImporterFindExistingID(t *testing.T) {
|
|||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
Input: jsonschema.Movie{
|
||||
Input: jsonschema.Group{
|
||||
Name: movieName,
|
||||
},
|
||||
}
|
||||
|
||||
errFindByName := errors.New("FindByName error")
|
||||
db.Movie.On("FindByName", testCtx, movieName, false).Return(nil, nil).Once()
|
||||
db.Movie.On("FindByName", testCtx, existingMovieName, false).Return(&models.Movie{
|
||||
db.Group.On("FindByName", testCtx, movieName, false).Return(nil, nil).Once()
|
||||
db.Group.On("FindByName", testCtx, existingMovieName, false).Return(&models.Group{
|
||||
ID: existingMovieID,
|
||||
}, nil).Once()
|
||||
db.Movie.On("FindByName", testCtx, movieNameErr, false).Return(nil, errFindByName).Once()
|
||||
db.Group.On("FindByName", testCtx, movieNameErr, false).Return(nil, errFindByName).Once()
|
||||
|
||||
id, err := i.FindExistingID(testCtx)
|
||||
assert.Nil(t, id)
|
||||
|
|
@ -318,32 +318,32 @@ func TestImporterFindExistingID(t *testing.T) {
|
|||
func TestCreate(t *testing.T) {
|
||||
db := mocks.NewDatabase()
|
||||
|
||||
movie := models.Movie{
|
||||
movie := models.Group{
|
||||
Name: movieName,
|
||||
}
|
||||
|
||||
movieErr := models.Movie{
|
||||
movieErr := models.Group{
|
||||
Name: movieNameErr,
|
||||
}
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
movie: movie,
|
||||
group: movie,
|
||||
}
|
||||
|
||||
errCreate := errors.New("Create error")
|
||||
db.Movie.On("Create", testCtx, &movie).Run(func(args mock.Arguments) {
|
||||
m := args.Get(1).(*models.Movie)
|
||||
db.Group.On("Create", testCtx, &movie).Run(func(args mock.Arguments) {
|
||||
m := args.Get(1).(*models.Group)
|
||||
m.ID = movieID
|
||||
}).Return(nil).Once()
|
||||
db.Movie.On("Create", testCtx, &movieErr).Return(errCreate).Once()
|
||||
db.Group.On("Create", testCtx, &movieErr).Return(errCreate).Once()
|
||||
|
||||
id, err := i.Create(testCtx)
|
||||
assert.Equal(t, movieID, *id)
|
||||
assert.Nil(t, err)
|
||||
|
||||
i.movie = movieErr
|
||||
i.group = movieErr
|
||||
id, err = i.Create(testCtx)
|
||||
assert.Nil(t, id)
|
||||
assert.NotNil(t, err)
|
||||
|
|
@ -354,34 +354,34 @@ func TestCreate(t *testing.T) {
|
|||
func TestUpdate(t *testing.T) {
|
||||
db := mocks.NewDatabase()
|
||||
|
||||
movie := models.Movie{
|
||||
movie := models.Group{
|
||||
Name: movieName,
|
||||
}
|
||||
|
||||
movieErr := models.Movie{
|
||||
movieErr := models.Group{
|
||||
Name: movieNameErr,
|
||||
}
|
||||
|
||||
i := Importer{
|
||||
ReaderWriter: db.Movie,
|
||||
ReaderWriter: db.Group,
|
||||
StudioWriter: db.Studio,
|
||||
movie: movie,
|
||||
group: movie,
|
||||
}
|
||||
|
||||
errUpdate := errors.New("Update error")
|
||||
|
||||
// id needs to be set for the mock input
|
||||
movie.ID = movieID
|
||||
db.Movie.On("Update", testCtx, &movie).Return(nil).Once()
|
||||
db.Group.On("Update", testCtx, &movie).Return(nil).Once()
|
||||
|
||||
err := i.Update(testCtx, movieID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
i.movie = movieErr
|
||||
i.group = movieErr
|
||||
|
||||
// need to set id separately
|
||||
movieErr.ID = errImageID
|
||||
db.Movie.On("Update", testCtx, &movieErr).Return(errUpdate).Once()
|
||||
db.Group.On("Update", testCtx, &movieErr).Return(errUpdate).Once()
|
||||
|
||||
err = i.Update(testCtx, errImageID)
|
||||
assert.NotNil(t, err)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
func CountByStudioID(ctx context.Context, r models.MovieQueryer, id int, depth *int) (int, error) {
|
||||
filter := &models.MovieFilterType{
|
||||
func CountByStudioID(ctx context.Context, r models.GroupQueryer, id int, depth *int) (int, error) {
|
||||
filter := &models.GroupFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(id)},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
|
|
@ -19,8 +19,8 @@ func CountByStudioID(ctx context.Context, r models.MovieQueryer, id int, depth *
|
|||
return r.QueryCount(ctx, filter, nil)
|
||||
}
|
||||
|
||||
func CountByTagID(ctx context.Context, r models.MovieQueryer, id int, depth *int) (int, error) {
|
||||
filter := &models.MovieFilterType{
|
||||
func CountByTagID(ctx context.Context, r models.GroupQueryer, id int, depth *int) (int, error) {
|
||||
filter := &models.GroupFilterType{
|
||||
Tags: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(id)},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
|
|
|
|||
|
|
@ -167,39 +167,39 @@ func GetDependentTagIDs(ctx context.Context, tags TagFinder, markerReader models
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
// GetSceneMoviesJSON returns a slice of SceneMovie JSON representation objects
|
||||
// corresponding to the provided scene's scene movie relationships.
|
||||
func GetSceneMoviesJSON(ctx context.Context, movieReader models.MovieGetter, scene *models.Scene) ([]jsonschema.SceneMovie, error) {
|
||||
sceneMovies := scene.Movies.List()
|
||||
// GetSceneGroupsJSON returns a slice of SceneGroup JSON representation objects
|
||||
// corresponding to the provided scene's scene group relationships.
|
||||
func GetSceneGroupsJSON(ctx context.Context, groupReader models.GroupGetter, scene *models.Scene) ([]jsonschema.SceneGroup, error) {
|
||||
sceneGroups := scene.Groups.List()
|
||||
|
||||
var results []jsonschema.SceneMovie
|
||||
for _, sceneMovie := range sceneMovies {
|
||||
movie, err := movieReader.Find(ctx, sceneMovie.MovieID)
|
||||
var results []jsonschema.SceneGroup
|
||||
for _, sceneGroup := range sceneGroups {
|
||||
group, err := groupReader.Find(ctx, sceneGroup.GroupID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting movie: %v", err)
|
||||
return nil, fmt.Errorf("error getting group: %v", err)
|
||||
}
|
||||
|
||||
if movie != nil {
|
||||
sceneMovieJSON := jsonschema.SceneMovie{
|
||||
MovieName: movie.Name,
|
||||
if group != nil {
|
||||
sceneGroupJSON := jsonschema.SceneGroup{
|
||||
GroupName: group.Name,
|
||||
}
|
||||
if sceneMovie.SceneIndex != nil {
|
||||
sceneMovieJSON.SceneIndex = *sceneMovie.SceneIndex
|
||||
if sceneGroup.SceneIndex != nil {
|
||||
sceneGroupJSON.SceneIndex = *sceneGroup.SceneIndex
|
||||
}
|
||||
results = append(results, sceneMovieJSON)
|
||||
results = append(results, sceneGroupJSON)
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetDependentMovieIDs returns a slice of movie IDs that this scene references.
|
||||
func GetDependentMovieIDs(ctx context.Context, scene *models.Scene) ([]int, error) {
|
||||
// GetDependentGroupIDs returns a slice of group IDs that this scene references.
|
||||
func GetDependentGroupIDs(ctx context.Context, scene *models.Scene) ([]int, error) {
|
||||
var ret []int
|
||||
|
||||
m := scene.Movies.List()
|
||||
m := scene.Groups.List()
|
||||
for _, mm := range m {
|
||||
ret = append(ret, mm.MovieID)
|
||||
ret = append(ret, mm.GroupID)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ const (
|
|||
noTagsID = 11
|
||||
errTagsID = 12
|
||||
|
||||
noMoviesID = 13
|
||||
errFindMovieID = 15
|
||||
noGroupsID = 13
|
||||
errFindGroupID = 15
|
||||
|
||||
noMarkersID = 16
|
||||
errMarkersID = 17
|
||||
|
|
@ -49,15 +49,15 @@ var (
|
|||
studioName = "studioName"
|
||||
// galleryChecksum = "galleryChecksum"
|
||||
|
||||
validMovie1 = 1
|
||||
validMovie2 = 2
|
||||
invalidMovie = 3
|
||||
validGroup1 = 1
|
||||
validGroup2 = 2
|
||||
invalidGroup = 3
|
||||
|
||||
movie1Name = "movie1Name"
|
||||
movie2Name = "movie2Name"
|
||||
group1Name = "group1Name"
|
||||
group2Name = "group2Name"
|
||||
|
||||
movie1Scene = 1
|
||||
movie2Scene = 2
|
||||
group1Scene = 1
|
||||
group2Scene = 2
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
|
|
@ -330,82 +330,82 @@ func TestGetTagNames(t *testing.T) {
|
|||
db.AssertExpectations(t)
|
||||
}
|
||||
|
||||
type sceneMoviesTestScenario struct {
|
||||
type sceneGroupsTestScenario struct {
|
||||
input models.Scene
|
||||
expected []jsonschema.SceneMovie
|
||||
expected []jsonschema.SceneGroup
|
||||
err bool
|
||||
}
|
||||
|
||||
var validMovies = models.NewRelatedMovies([]models.MoviesScenes{
|
||||
var validGroups = models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: validMovie1,
|
||||
SceneIndex: &movie1Scene,
|
||||
GroupID: validGroup1,
|
||||
SceneIndex: &group1Scene,
|
||||
},
|
||||
{
|
||||
MovieID: validMovie2,
|
||||
SceneIndex: &movie2Scene,
|
||||
GroupID: validGroup2,
|
||||
SceneIndex: &group2Scene,
|
||||
},
|
||||
})
|
||||
|
||||
var invalidMovies = models.NewRelatedMovies([]models.MoviesScenes{
|
||||
var invalidGroups = models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: invalidMovie,
|
||||
SceneIndex: &movie1Scene,
|
||||
GroupID: invalidGroup,
|
||||
SceneIndex: &group1Scene,
|
||||
},
|
||||
})
|
||||
|
||||
var getSceneMoviesJSONScenarios = []sceneMoviesTestScenario{
|
||||
var getSceneGroupsJSONScenarios = []sceneGroupsTestScenario{
|
||||
{
|
||||
models.Scene{
|
||||
ID: sceneID,
|
||||
Movies: validMovies,
|
||||
Groups: validGroups,
|
||||
},
|
||||
[]jsonschema.SceneMovie{
|
||||
[]jsonschema.SceneGroup{
|
||||
{
|
||||
MovieName: movie1Name,
|
||||
SceneIndex: movie1Scene,
|
||||
GroupName: group1Name,
|
||||
SceneIndex: group1Scene,
|
||||
},
|
||||
{
|
||||
MovieName: movie2Name,
|
||||
SceneIndex: movie2Scene,
|
||||
GroupName: group2Name,
|
||||
SceneIndex: group2Scene,
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
models.Scene{
|
||||
ID: noMoviesID,
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
|
||||
ID: noGroupsID,
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{}),
|
||||
},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
models.Scene{
|
||||
ID: errFindMovieID,
|
||||
Movies: invalidMovies,
|
||||
ID: errFindGroupID,
|
||||
Groups: invalidGroups,
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestGetSceneMoviesJSON(t *testing.T) {
|
||||
func TestGetSceneGroupsJSON(t *testing.T) {
|
||||
db := mocks.NewDatabase()
|
||||
|
||||
movieErr := errors.New("error getting movie")
|
||||
groupErr := errors.New("error getting group")
|
||||
|
||||
db.Movie.On("Find", testCtx, validMovie1).Return(&models.Movie{
|
||||
Name: movie1Name,
|
||||
db.Group.On("Find", testCtx, validGroup1).Return(&models.Group{
|
||||
Name: group1Name,
|
||||
}, nil).Once()
|
||||
db.Movie.On("Find", testCtx, validMovie2).Return(&models.Movie{
|
||||
Name: movie2Name,
|
||||
db.Group.On("Find", testCtx, validGroup2).Return(&models.Group{
|
||||
Name: group2Name,
|
||||
}, nil).Once()
|
||||
db.Movie.On("Find", testCtx, invalidMovie).Return(nil, movieErr).Once()
|
||||
db.Group.On("Find", testCtx, invalidGroup).Return(nil, groupErr).Once()
|
||||
|
||||
for i, s := range getSceneMoviesJSONScenarios {
|
||||
for i, s := range getSceneGroupsJSONScenarios {
|
||||
scene := s.input
|
||||
json, err := GetSceneMoviesJSON(testCtx, db.Movie, &scene)
|
||||
json, err := GetSceneGroupsJSON(testCtx, db.Group, &scene)
|
||||
|
||||
switch {
|
||||
case !s.err && err != nil:
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ type sceneHolder struct {
|
|||
mm string
|
||||
dd string
|
||||
performers []string
|
||||
movies []string
|
||||
groups []string
|
||||
studio string
|
||||
tags []string
|
||||
}
|
||||
|
|
@ -340,7 +340,7 @@ func (h *sceneHolder) setField(field parserField, value interface{}) {
|
|||
case "studio":
|
||||
h.studio = value.(string)
|
||||
case "movie":
|
||||
h.movies = append(h.movies, value.(string))
|
||||
h.groups = append(h.groups, value.(string))
|
||||
case "tag":
|
||||
h.tags = append(h.tags, value.(string))
|
||||
case "yyyy":
|
||||
|
|
@ -413,7 +413,7 @@ type FilenameParser struct {
|
|||
repository FilenameParserRepository
|
||||
performerCache map[string]*models.Performer
|
||||
studioCache map[string]*models.Studio
|
||||
movieCache map[string]*models.Movie
|
||||
groupCache map[string]*models.Group
|
||||
tagCache map[string]*models.Tag
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +427,7 @@ func NewFilenameParser(filter *models.FindFilterType, config models.SceneParserI
|
|||
|
||||
p.performerCache = make(map[string]*models.Performer)
|
||||
p.studioCache = make(map[string]*models.Studio)
|
||||
p.movieCache = make(map[string]*models.Movie)
|
||||
p.groupCache = make(map[string]*models.Group)
|
||||
p.tagCache = make(map[string]*models.Tag)
|
||||
|
||||
p.initWhiteSpaceRegex()
|
||||
|
|
@ -455,7 +455,7 @@ type FilenameParserRepository struct {
|
|||
Scene models.SceneQueryer
|
||||
Performer PerformerNamesFinder
|
||||
Studio models.StudioQueryer
|
||||
Movie MovieNameFinder
|
||||
Group GroupNameFinder
|
||||
Tag models.TagQueryer
|
||||
}
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ func NewFilenameParserRepository(repo models.Repository) FilenameParserRepositor
|
|||
Scene: repo.Scene,
|
||||
Performer: repo.Performer,
|
||||
Studio: repo.Studio,
|
||||
Movie: repo.Movie,
|
||||
Group: repo.Group,
|
||||
Tag: repo.Tag,
|
||||
}
|
||||
}
|
||||
|
|
@ -578,23 +578,23 @@ func (p *FilenameParser) queryStudio(ctx context.Context, qb models.StudioQuerye
|
|||
return ret
|
||||
}
|
||||
|
||||
type MovieNameFinder interface {
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*models.Movie, error)
|
||||
type GroupNameFinder interface {
|
||||
FindByName(ctx context.Context, name string, nocase bool) (*models.Group, error)
|
||||
}
|
||||
|
||||
func (p *FilenameParser) queryMovie(ctx context.Context, qb MovieNameFinder, movieName string) *models.Movie {
|
||||
// massage the movie name
|
||||
movieName = delimiterRE.ReplaceAllString(movieName, " ")
|
||||
func (p *FilenameParser) queryGroup(ctx context.Context, qb GroupNameFinder, groupName string) *models.Group {
|
||||
// massage the group name
|
||||
groupName = delimiterRE.ReplaceAllString(groupName, " ")
|
||||
|
||||
// check cache first
|
||||
if ret, found := p.movieCache[movieName]; found {
|
||||
if ret, found := p.groupCache[groupName]; found {
|
||||
return ret
|
||||
}
|
||||
|
||||
ret, _ := qb.FindByName(ctx, movieName, true)
|
||||
ret, _ := qb.FindByName(ctx, groupName, true)
|
||||
|
||||
// add result to cache
|
||||
p.movieCache[movieName] = ret
|
||||
p.groupCache[groupName] = ret
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
@ -665,18 +665,18 @@ func (p *FilenameParser) setStudio(ctx context.Context, qb models.StudioQueryer,
|
|||
}
|
||||
}
|
||||
|
||||
func (p *FilenameParser) setMovies(ctx context.Context, qb MovieNameFinder, h sceneHolder, result *models.SceneParserResult) {
|
||||
// query for each movie
|
||||
moviesSet := make(map[int]bool)
|
||||
for _, movieName := range h.movies {
|
||||
if movieName != "" {
|
||||
movie := p.queryMovie(ctx, qb, movieName)
|
||||
if movie != nil {
|
||||
if _, found := moviesSet[movie.ID]; !found {
|
||||
func (p *FilenameParser) setGroups(ctx context.Context, qb GroupNameFinder, h sceneHolder, result *models.SceneParserResult) {
|
||||
// query for each group
|
||||
groupsSet := make(map[int]bool)
|
||||
for _, groupName := range h.groups {
|
||||
if groupName != "" {
|
||||
group := p.queryGroup(ctx, qb, groupName)
|
||||
if group != nil {
|
||||
if _, found := groupsSet[group.ID]; !found {
|
||||
result.Movies = append(result.Movies, &models.SceneMovieID{
|
||||
MovieID: strconv.Itoa(movie.ID),
|
||||
MovieID: strconv.Itoa(group.ID),
|
||||
})
|
||||
moviesSet[movie.ID] = true
|
||||
groupsSet[group.ID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -714,7 +714,7 @@ func (p *FilenameParser) setParserResult(ctx context.Context, h sceneHolder, res
|
|||
}
|
||||
p.setStudio(ctx, r.Studio, h, result)
|
||||
|
||||
if len(h.movies) > 0 {
|
||||
p.setMovies(ctx, r.Movie, h, result)
|
||||
if len(h.groups) > 0 {
|
||||
p.setGroups(ctx, r.Group, h, result)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ type Importer struct {
|
|||
StudioWriter models.StudioFinderCreator
|
||||
GalleryFinder models.GalleryFinder
|
||||
PerformerWriter models.PerformerFinderCreator
|
||||
MovieWriter models.MovieFinderCreator
|
||||
GroupWriter models.GroupFinderCreator
|
||||
TagWriter models.TagFinderCreator
|
||||
Input jsonschema.Scene
|
||||
MissingRefBehaviour models.ImportMissingRefEnum
|
||||
|
|
@ -62,7 +62,7 @@ func (i *Importer) PreImport(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := i.populateMovies(ctx); err != nil {
|
||||
if err := i.populateGroups(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ func (i *Importer) sceneJSONToScene(sceneJSON jsonschema.Scene) models.Scene {
|
|||
PerformerIDs: models.NewRelatedIDs([]int{}),
|
||||
TagIDs: models.NewRelatedIDs([]int{}),
|
||||
GalleryIDs: models.NewRelatedIDs([]int{}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{}),
|
||||
StashIDs: models.NewRelatedStashIDs(sceneJSON.StashIDs),
|
||||
}
|
||||
|
||||
|
|
@ -335,24 +335,24 @@ func (i *Importer) createPerformers(ctx context.Context, names []string) ([]*mod
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (i *Importer) populateMovies(ctx context.Context) error {
|
||||
if len(i.Input.Movies) > 0 {
|
||||
for _, inputMovie := range i.Input.Movies {
|
||||
movie, err := i.MovieWriter.FindByName(ctx, inputMovie.MovieName, false)
|
||||
func (i *Importer) populateGroups(ctx context.Context) error {
|
||||
if len(i.Input.Groups) > 0 {
|
||||
for _, inputGroup := range i.Input.Groups {
|
||||
group, err := i.GroupWriter.FindByName(ctx, inputGroup.GroupName, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding scene movie: %v", err)
|
||||
return fmt.Errorf("error finding scene group: %v", err)
|
||||
}
|
||||
|
||||
var movieID int
|
||||
if movie == nil {
|
||||
var groupID int
|
||||
if group == nil {
|
||||
if i.MissingRefBehaviour == models.ImportMissingRefEnumFail {
|
||||
return fmt.Errorf("scene movie [%s] not found", inputMovie.MovieName)
|
||||
return fmt.Errorf("scene group [%s] not found", inputGroup.GroupName)
|
||||
}
|
||||
|
||||
if i.MissingRefBehaviour == models.ImportMissingRefEnumCreate {
|
||||
movieID, err = i.createMovie(ctx, inputMovie.MovieName)
|
||||
groupID, err = i.createGroup(ctx, inputGroup.GroupName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating scene movie: %v", err)
|
||||
return fmt.Errorf("error creating scene group: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -361,35 +361,35 @@ func (i *Importer) populateMovies(ctx context.Context) error {
|
|||
continue
|
||||
}
|
||||
} else {
|
||||
movieID = movie.ID
|
||||
groupID = group.ID
|
||||
}
|
||||
|
||||
toAdd := models.MoviesScenes{
|
||||
MovieID: movieID,
|
||||
toAdd := models.GroupsScenes{
|
||||
GroupID: groupID,
|
||||
}
|
||||
|
||||
if inputMovie.SceneIndex != 0 {
|
||||
index := inputMovie.SceneIndex
|
||||
if inputGroup.SceneIndex != 0 {
|
||||
index := inputGroup.SceneIndex
|
||||
toAdd.SceneIndex = &index
|
||||
}
|
||||
|
||||
i.scene.Movies.Add(toAdd)
|
||||
i.scene.Groups.Add(toAdd)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Importer) createMovie(ctx context.Context, name string) (int, error) {
|
||||
newMovie := models.NewMovie()
|
||||
newMovie.Name = name
|
||||
func (i *Importer) createGroup(ctx context.Context, name string) (int, error) {
|
||||
newGroup := models.NewGroup()
|
||||
newGroup.Name = name
|
||||
|
||||
err := i.MovieWriter.Create(ctx, &newMovie)
|
||||
err := i.GroupWriter.Create(ctx, &newGroup)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return newMovie.ID, nil
|
||||
return newGroup.ID, nil
|
||||
}
|
||||
|
||||
func (i *Importer) populateTags(ctx context.Context) error {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const invalidImage = "aW1hZ2VCeXRlcw&&"
|
|||
var (
|
||||
existingStudioID = 101
|
||||
existingPerformerID = 103
|
||||
existingMovieID = 104
|
||||
existingGroupID = 104
|
||||
existingTagID = 105
|
||||
|
||||
existingStudioName = "existingStudioName"
|
||||
|
|
@ -28,9 +28,9 @@ var (
|
|||
existingPerformerErr = "existingPerformerErr"
|
||||
missingPerformerName = "missingPerformerName"
|
||||
|
||||
existingMovieName = "existingMovieName"
|
||||
existingMovieErr = "existingMovieErr"
|
||||
missingMovieName = "missingMovieName"
|
||||
existingGroupName = "existingGroupName"
|
||||
existingGroupErr = "existingGroupErr"
|
||||
missingGroupName = "missingGroupName"
|
||||
|
||||
existingTagName = "existingTagName"
|
||||
existingTagErr = "existingTagErr"
|
||||
|
|
@ -221,58 +221,58 @@ func TestImporterPreImportWithMissingPerformerCreateErr(t *testing.T) {
|
|||
db.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestImporterPreImportWithMovie(t *testing.T) {
|
||||
func TestImporterPreImportWithGroup(t *testing.T) {
|
||||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
MovieWriter: db.Movie,
|
||||
GroupWriter: db.Group,
|
||||
MissingRefBehaviour: models.ImportMissingRefEnumFail,
|
||||
Input: jsonschema.Scene{
|
||||
Movies: []jsonschema.SceneMovie{
|
||||
Groups: []jsonschema.SceneGroup{
|
||||
{
|
||||
MovieName: existingMovieName,
|
||||
GroupName: existingGroupName,
|
||||
SceneIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
db.Movie.On("FindByName", testCtx, existingMovieName, false).Return(&models.Movie{
|
||||
ID: existingMovieID,
|
||||
Name: existingMovieName,
|
||||
db.Group.On("FindByName", testCtx, existingGroupName, false).Return(&models.Group{
|
||||
ID: existingGroupID,
|
||||
Name: existingGroupName,
|
||||
}, nil).Once()
|
||||
db.Movie.On("FindByName", testCtx, existingMovieErr, false).Return(nil, errors.New("FindByName error")).Once()
|
||||
db.Group.On("FindByName", testCtx, existingGroupErr, false).Return(nil, errors.New("FindByName error")).Once()
|
||||
|
||||
err := i.PreImport(testCtx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, existingMovieID, i.scene.Movies.List()[0].MovieID)
|
||||
assert.Equal(t, existingGroupID, i.scene.Groups.List()[0].GroupID)
|
||||
|
||||
i.Input.Movies[0].MovieName = existingMovieErr
|
||||
i.Input.Groups[0].GroupName = existingGroupErr
|
||||
err = i.PreImport(testCtx)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
db.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestImporterPreImportWithMissingMovie(t *testing.T) {
|
||||
func TestImporterPreImportWithMissingGroup(t *testing.T) {
|
||||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
MovieWriter: db.Movie,
|
||||
GroupWriter: db.Group,
|
||||
Input: jsonschema.Scene{
|
||||
Movies: []jsonschema.SceneMovie{
|
||||
Groups: []jsonschema.SceneGroup{
|
||||
{
|
||||
MovieName: missingMovieName,
|
||||
GroupName: missingGroupName,
|
||||
},
|
||||
},
|
||||
},
|
||||
MissingRefBehaviour: models.ImportMissingRefEnumFail,
|
||||
}
|
||||
|
||||
db.Movie.On("FindByName", testCtx, missingMovieName, false).Return(nil, nil).Times(3)
|
||||
db.Movie.On("Create", testCtx, mock.AnythingOfType("*models.Movie")).Run(func(args mock.Arguments) {
|
||||
m := args.Get(1).(*models.Movie)
|
||||
m.ID = existingMovieID
|
||||
db.Group.On("FindByName", testCtx, missingGroupName, false).Return(nil, nil).Times(3)
|
||||
db.Group.On("Create", testCtx, mock.AnythingOfType("*models.Group")).Run(func(args mock.Arguments) {
|
||||
m := args.Get(1).(*models.Group)
|
||||
m.ID = existingGroupID
|
||||
}).Return(nil)
|
||||
|
||||
err := i.PreImport(testCtx)
|
||||
|
|
@ -285,28 +285,28 @@ func TestImporterPreImportWithMissingMovie(t *testing.T) {
|
|||
i.MissingRefBehaviour = models.ImportMissingRefEnumCreate
|
||||
err = i.PreImport(testCtx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, existingMovieID, i.scene.Movies.List()[0].MovieID)
|
||||
assert.Equal(t, existingGroupID, i.scene.Groups.List()[0].GroupID)
|
||||
|
||||
db.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestImporterPreImportWithMissingMovieCreateErr(t *testing.T) {
|
||||
func TestImporterPreImportWithMissingGroupCreateErr(t *testing.T) {
|
||||
db := mocks.NewDatabase()
|
||||
|
||||
i := Importer{
|
||||
MovieWriter: db.Movie,
|
||||
GroupWriter: db.Group,
|
||||
Input: jsonschema.Scene{
|
||||
Movies: []jsonschema.SceneMovie{
|
||||
Groups: []jsonschema.SceneGroup{
|
||||
{
|
||||
MovieName: missingMovieName,
|
||||
GroupName: missingGroupName,
|
||||
},
|
||||
},
|
||||
},
|
||||
MissingRefBehaviour: models.ImportMissingRefEnumCreate,
|
||||
}
|
||||
|
||||
db.Movie.On("FindByName", testCtx, missingMovieName, false).Return(nil, nil).Once()
|
||||
db.Movie.On("Create", testCtx, mock.AnythingOfType("*models.Movie")).Return(errors.New("Create error"))
|
||||
db.Group.On("FindByName", testCtx, missingGroupName, false).Return(nil, nil).Once()
|
||||
db.Group.On("Create", testCtx, mock.AnythingOfType("*models.Group")).Return(errors.New("Create error"))
|
||||
|
||||
err := i.PreImport(testCtx)
|
||||
assert.NotNil(t, err)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ type Repository struct {
|
|||
GalleryFinder GalleryFinder
|
||||
TagFinder TagFinder
|
||||
PerformerFinder PerformerFinder
|
||||
MovieFinder match.MovieNamesFinder
|
||||
GroupFinder match.GroupNamesFinder
|
||||
StudioFinder StudioFinder
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ func NewRepository(repo models.Repository) Repository {
|
|||
GalleryFinder: repo.Gallery,
|
||||
TagFinder: repo.Tag,
|
||||
PerformerFinder: repo.Performer,
|
||||
MovieFinder: repo.Movie,
|
||||
GroupFinder: repo.Group,
|
||||
StudioFinder: repo.Studio,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,8 +45,9 @@ type config struct {
|
|||
// Configuration for querying a gallery by a URL
|
||||
GalleryByURL []*scrapeByURLConfig `yaml:"galleryByURL"`
|
||||
|
||||
// Configuration for querying a movie by a URL
|
||||
// Configuration for querying a movie by a URL - deprecated, use GroupByURL
|
||||
MovieByURL []*scrapeByURLConfig `yaml:"movieByURL"`
|
||||
GroupByURL []*scrapeByURLConfig `yaml:"groupByURL"`
|
||||
|
||||
// Scraper debugging options
|
||||
DebugOptions *scraperDebugOptions `yaml:"debug"`
|
||||
|
|
@ -99,7 +100,11 @@ func (c config) validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
for _, s := range c.MovieByURL {
|
||||
if len(c.MovieByURL) > 0 && len(c.GroupByURL) > 0 {
|
||||
return errors.New("movieByURL disallowed if groupByURL is present")
|
||||
}
|
||||
|
||||
for _, s := range append(c.MovieByURL, c.GroupByURL...) {
|
||||
if err := s.validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -289,17 +294,17 @@ func (c config) spec() Scraper {
|
|||
ret.Gallery = &gallery
|
||||
}
|
||||
|
||||
movie := ScraperSpec{}
|
||||
if len(c.MovieByURL) > 0 {
|
||||
movie.SupportedScrapes = append(movie.SupportedScrapes, ScrapeTypeURL)
|
||||
for _, v := range c.MovieByURL {
|
||||
movie.Urls = append(movie.Urls, v.URL...)
|
||||
group := ScraperSpec{}
|
||||
if len(c.MovieByURL) > 0 || len(c.GroupByURL) > 0 {
|
||||
group.SupportedScrapes = append(group.SupportedScrapes, ScrapeTypeURL)
|
||||
for _, v := range append(c.MovieByURL, c.GroupByURL...) {
|
||||
group.Urls = append(group.Urls, v.URL...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(movie.SupportedScrapes) > 0 {
|
||||
ret.Movie = &movie
|
||||
ret.Group = &movie
|
||||
if len(group.SupportedScrapes) > 0 {
|
||||
ret.Movie = &group
|
||||
ret.Group = &group
|
||||
}
|
||||
|
||||
return ret
|
||||
|
|
@ -314,7 +319,7 @@ func (c config) supports(ty ScrapeContentType) bool {
|
|||
case ScrapeContentTypeGallery:
|
||||
return c.GalleryByFragment != nil || len(c.GalleryByURL) > 0
|
||||
case ScrapeContentTypeMovie, ScrapeContentTypeGroup:
|
||||
return len(c.MovieByURL) > 0
|
||||
return len(c.MovieByURL) > 0 || len(c.GroupByURL) > 0
|
||||
}
|
||||
|
||||
panic("Unhandled ScrapeContentType")
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func loadUrlCandidates(c config, ty ScrapeContentType) []*scrapeByURLConfig {
|
|||
case ScrapeContentTypeScene:
|
||||
return c.SceneByURL
|
||||
case ScrapeContentTypeMovie, ScrapeContentTypeGroup:
|
||||
return c.MovieByURL
|
||||
return append(c.MovieByURL, c.GroupByURL...)
|
||||
case ScrapeContentTypeGallery:
|
||||
return c.GalleryByURL
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,40 @@ func setMovieBackImage(ctx context.Context, client *http.Client, m *models.Scrap
|
|||
return nil
|
||||
}
|
||||
|
||||
func setGroupFrontImage(ctx context.Context, client *http.Client, m *models.ScrapedGroup, globalConfig GlobalConfig) error {
|
||||
// don't try to get the image if it doesn't appear to be a URL
|
||||
if m.FrontImage == nil || !strings.HasPrefix(*m.FrontImage, "http") {
|
||||
// nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
img, err := getImage(ctx, *m.FrontImage, client, globalConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.FrontImage = img
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setGroupBackImage(ctx context.Context, client *http.Client, m *models.ScrapedGroup, globalConfig GlobalConfig) error {
|
||||
// don't try to get the image if it doesn't appear to be a URL
|
||||
if m.BackImage == nil || !strings.HasPrefix(*m.BackImage, "http") {
|
||||
// nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
img, err := getImage(ctx, *m.BackImage, client, globalConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.BackImage = img
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getImage(ctx context.Context, url string, client *http.Client, globalConfig GlobalConfig) (*string, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func (s *jsonScraper) scrapeByURL(ctx context.Context, url string, ty ScrapeCont
|
|||
}
|
||||
return ret, nil
|
||||
case ScrapeContentTypeMovie, ScrapeContentTypeGroup:
|
||||
ret, err := scraper.scrapeMovie(ctx, q)
|
||||
ret, err := scraper.scrapeGroup(ctx, q)
|
||||
if err != nil || ret == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1079,7 +1079,7 @@ func (s mappedScraper) scrapeGallery(ctx context.Context, q mappedQuery) (*Scrap
|
|||
return &ret, nil
|
||||
}
|
||||
|
||||
func (s mappedScraper) scrapeMovie(ctx context.Context, q mappedQuery) (*models.ScrapedMovie, error) {
|
||||
func (s mappedScraper) scrapeGroup(ctx context.Context, q mappedQuery) (*models.ScrapedMovie, error) {
|
||||
var ret models.ScrapedMovie
|
||||
|
||||
movieScraperConfig := s.Movie
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ func (c Cache) postScrape(ctx context.Context, content ScrapedContent) (ScrapedC
|
|||
}
|
||||
case models.ScrapedMovie:
|
||||
return c.postScrapeMovie(ctx, v)
|
||||
case *models.ScrapedGroup:
|
||||
if v != nil {
|
||||
return c.postScrapeGroup(ctx, *v)
|
||||
}
|
||||
case models.ScrapedGroup:
|
||||
return c.postScrapeGroup(ctx, v)
|
||||
}
|
||||
|
||||
// If nothing matches, pass the content through
|
||||
|
|
@ -128,6 +134,38 @@ func (c Cache) postScrapeMovie(ctx context.Context, m models.ScrapedMovie) (Scra
|
|||
return m, nil
|
||||
}
|
||||
|
||||
func (c Cache) postScrapeGroup(ctx context.Context, m models.ScrapedGroup) (ScrapedContent, error) {
|
||||
r := c.repository
|
||||
if err := r.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||
tqb := r.TagFinder
|
||||
tags, err := postProcessTags(ctx, tqb, m.Tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Tags = tags
|
||||
|
||||
if m.Studio != nil {
|
||||
if err := match.ScrapedStudio(ctx, r.StudioFinder, m.Studio, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// post-process - set the image if applicable
|
||||
if err := setGroupFrontImage(ctx, c.client, &m, c.globalConfig); err != nil {
|
||||
logger.Warnf("could not set front image using URL %s: %v", *m.FrontImage, err)
|
||||
}
|
||||
if err := setGroupBackImage(ctx, c.client, &m, c.globalConfig); err != nil {
|
||||
logger.Warnf("could not set back image using URL %s: %v", *m.BackImage, err)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c Cache) postScrapeScenePerformer(ctx context.Context, p models.ScrapedPerformer) error {
|
||||
tqb := c.repository.TagFinder
|
||||
|
||||
|
|
@ -154,7 +192,7 @@ func (c Cache) postScrapeScene(ctx context.Context, scene ScrapedScene) (Scraped
|
|||
r := c.repository
|
||||
if err := r.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||
pqb := r.PerformerFinder
|
||||
mqb := r.MovieFinder
|
||||
gqb := r.GroupFinder
|
||||
tqb := r.TagFinder
|
||||
sqb := r.StudioFinder
|
||||
|
||||
|
|
@ -173,10 +211,39 @@ func (c Cache) postScrapeScene(ctx context.Context, scene ScrapedScene) (Scraped
|
|||
}
|
||||
|
||||
for _, p := range scene.Movies {
|
||||
err := match.ScrapedMovie(ctx, mqb, p)
|
||||
matchedID, err := match.ScrapedGroup(ctx, gqb, p.StoredID, p.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if matchedID != nil {
|
||||
p.StoredID = matchedID
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range scene.Groups {
|
||||
matchedID, err := match.ScrapedGroup(ctx, gqb, p.StoredID, p.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if matchedID != nil {
|
||||
p.StoredID = matchedID
|
||||
}
|
||||
}
|
||||
|
||||
// HACK - if movies was returned but not groups, add the groups from the movies
|
||||
// if groups was returned but not movies, add the movies from the groups for backward compatibility
|
||||
if len(scene.Movies) > 0 && len(scene.Groups) == 0 {
|
||||
for _, m := range scene.Movies {
|
||||
g := m.ScrapedGroup()
|
||||
scene.Groups = append(scene.Groups, &g)
|
||||
}
|
||||
} else if len(scene.Groups) > 0 && len(scene.Movies) == 0 {
|
||||
for _, g := range scene.Groups {
|
||||
m := g.ScrapedMovie()
|
||||
scene.Movies = append(scene.Movies, &m)
|
||||
}
|
||||
}
|
||||
|
||||
tags, err := postProcessTags(ctx, tqb, scene.Tags)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func (s *xpathScraper) scrapeByURL(ctx context.Context, url string, ty ScrapeCon
|
|||
}
|
||||
return ret, nil
|
||||
case ScrapeContentTypeMovie, ScrapeContentTypeGroup:
|
||||
ret, err := scraper.scrapeMovie(ctx, q)
|
||||
ret, err := scraper.scrapeGroup(ctx, q)
|
||||
if err != nil || ret == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func (db *Anonymiser) Anonymise(ctx context.Context) error {
|
|||
func() error { return db.anonymisePerformers(ctx) },
|
||||
func() error { return db.anonymiseStudios(ctx) },
|
||||
func() error { return db.anonymiseTags(ctx) },
|
||||
func() error { return db.anonymiseMovies(ctx) },
|
||||
func() error { return db.anonymiseGroups(ctx) },
|
||||
func() error { return db.Optimise(ctx) },
|
||||
})
|
||||
}(); err != nil {
|
||||
|
|
@ -825,9 +825,9 @@ func (db *Anonymiser) anonymiseTags(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (db *Anonymiser) anonymiseMovies(ctx context.Context) error {
|
||||
logger.Infof("Anonymising movies")
|
||||
table := movieTableMgr.table
|
||||
func (db *Anonymiser) anonymiseGroups(ctx context.Context) error {
|
||||
logger.Infof("Anonymising groups")
|
||||
table := groupTableMgr.table
|
||||
lastID := 0
|
||||
total := 0
|
||||
const logEvery = 10000
|
||||
|
|
@ -883,7 +883,7 @@ func (db *Anonymiser) anonymiseMovies(ctx context.Context) error {
|
|||
total++
|
||||
|
||||
if total%logEvery == 0 {
|
||||
logger.Infof("Anonymised %d movies", total)
|
||||
logger.Infof("Anonymised %d groups", total)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -893,7 +893,7 @@ func (db *Anonymiser) anonymiseMovies(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := db.anonymiseURLs(ctx, goqu.T(movieURLsTable), "movie_id"); err != nil {
|
||||
if err := db.anonymiseURLs(ctx, goqu.T(groupURLsTable), "movie_id"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
type updateImageFunc func(ctx context.Context, id int, image []byte) error
|
||||
type getImageFunc func(ctx context.Context, movieID int) ([]byte, error)
|
||||
type getImageFunc func(ctx context.Context, id int) ([]byte, error)
|
||||
|
||||
func testUpdateImage(t *testing.T, ctx context.Context, id int, updateFn updateImageFunc, getFn getImageFunc) error {
|
||||
image := []byte("image")
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ type storeRepository struct {
|
|||
SavedFilter *SavedFilterStore
|
||||
Studio *StudioStore
|
||||
Tag *TagStore
|
||||
Movie *MovieStore
|
||||
Group *GroupStore
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
|
|
@ -110,7 +110,7 @@ func NewDatabase() *Database {
|
|||
Performer: performerStore,
|
||||
Studio: studioStore,
|
||||
Tag: tagStore,
|
||||
Movie: NewMovieStore(blobStore),
|
||||
Group: NewGroupStore(blobStore),
|
||||
SavedFilter: NewSavedFilterStore(),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,19 +17,19 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
movieTable = "movies"
|
||||
movieIDColumn = "movie_id"
|
||||
groupTable = "movies"
|
||||
groupIDColumn = "movie_id"
|
||||
|
||||
movieFrontImageBlobColumn = "front_image_blob"
|
||||
movieBackImageBlobColumn = "back_image_blob"
|
||||
groupFrontImageBlobColumn = "front_image_blob"
|
||||
groupBackImageBlobColumn = "back_image_blob"
|
||||
|
||||
moviesTagsTable = "movies_tags"
|
||||
groupsTagsTable = "movies_tags"
|
||||
|
||||
movieURLsTable = "movie_urls"
|
||||
movieURLColumn = "url"
|
||||
groupURLsTable = "movie_urls"
|
||||
groupURLColumn = "url"
|
||||
)
|
||||
|
||||
type movieRow struct {
|
||||
type groupRow struct {
|
||||
ID int `db:"id" goqu:"skipinsert"`
|
||||
Name zero.String `db:"name"`
|
||||
Aliases zero.String `db:"aliases"`
|
||||
|
|
@ -48,7 +48,7 @@ type movieRow struct {
|
|||
BackImageBlob zero.String `db:"back_image_blob"`
|
||||
}
|
||||
|
||||
func (r *movieRow) fromMovie(o models.Movie) {
|
||||
func (r *groupRow) fromGroup(o models.Group) {
|
||||
r.ID = o.ID
|
||||
r.Name = zero.StringFrom(o.Name)
|
||||
r.Aliases = zero.StringFrom(o.Aliases)
|
||||
|
|
@ -62,8 +62,8 @@ func (r *movieRow) fromMovie(o models.Movie) {
|
|||
r.UpdatedAt = Timestamp{Timestamp: o.UpdatedAt}
|
||||
}
|
||||
|
||||
func (r *movieRow) resolve() *models.Movie {
|
||||
ret := &models.Movie{
|
||||
func (r *groupRow) resolve() *models.Group {
|
||||
ret := &models.Group{
|
||||
ID: r.ID,
|
||||
Name: r.Name.String,
|
||||
Aliases: r.Aliases.String,
|
||||
|
|
@ -80,11 +80,11 @@ func (r *movieRow) resolve() *models.Movie {
|
|||
return ret
|
||||
}
|
||||
|
||||
type movieRowRecord struct {
|
||||
type groupRowRecord struct {
|
||||
updateRecord
|
||||
}
|
||||
|
||||
func (r *movieRowRecord) fromPartial(o models.MoviePartial) {
|
||||
func (r *groupRowRecord) fromPartial(o models.GroupPartial) {
|
||||
r.setNullString("name", o.Name)
|
||||
r.setNullString("aliases", o.Aliases)
|
||||
r.setNullInt("duration", o.Duration)
|
||||
|
|
@ -97,26 +97,26 @@ func (r *movieRowRecord) fromPartial(o models.MoviePartial) {
|
|||
r.setTimestamp("updated_at", o.UpdatedAt)
|
||||
}
|
||||
|
||||
type movieRepositoryType struct {
|
||||
type groupRepositoryType struct {
|
||||
repository
|
||||
scenes repository
|
||||
tags joinRepository
|
||||
}
|
||||
|
||||
var (
|
||||
movieRepository = movieRepositoryType{
|
||||
groupRepository = groupRepositoryType{
|
||||
repository: repository{
|
||||
tableName: movieTable,
|
||||
tableName: groupTable,
|
||||
idColumn: idColumn,
|
||||
},
|
||||
scenes: repository{
|
||||
tableName: moviesScenesTable,
|
||||
idColumn: movieIDColumn,
|
||||
tableName: groupsScenesTable,
|
||||
idColumn: groupIDColumn,
|
||||
},
|
||||
tags: joinRepository{
|
||||
repository: repository{
|
||||
tableName: moviesTagsTable,
|
||||
idColumn: movieIDColumn,
|
||||
tableName: groupsTagsTable,
|
||||
idColumn: groupIDColumn,
|
||||
},
|
||||
fkColumn: tagIDColumn,
|
||||
foreignTable: tagTable,
|
||||
|
|
@ -125,40 +125,40 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
type MovieStore struct {
|
||||
type GroupStore struct {
|
||||
blobJoinQueryBuilder
|
||||
tagRelationshipStore
|
||||
|
||||
tableMgr *table
|
||||
}
|
||||
|
||||
func NewMovieStore(blobStore *BlobStore) *MovieStore {
|
||||
return &MovieStore{
|
||||
func NewGroupStore(blobStore *BlobStore) *GroupStore {
|
||||
return &GroupStore{
|
||||
blobJoinQueryBuilder: blobJoinQueryBuilder{
|
||||
blobStore: blobStore,
|
||||
joinTable: movieTable,
|
||||
joinTable: groupTable,
|
||||
},
|
||||
tagRelationshipStore: tagRelationshipStore{
|
||||
idRelationshipStore: idRelationshipStore{
|
||||
joinTable: moviesTagsTableMgr,
|
||||
joinTable: groupsTagsTableMgr,
|
||||
},
|
||||
},
|
||||
|
||||
tableMgr: movieTableMgr,
|
||||
tableMgr: groupTableMgr,
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *MovieStore) table() exp.IdentifierExpression {
|
||||
func (qb *GroupStore) table() exp.IdentifierExpression {
|
||||
return qb.tableMgr.table
|
||||
}
|
||||
|
||||
func (qb *MovieStore) selectDataset() *goqu.SelectDataset {
|
||||
func (qb *GroupStore) selectDataset() *goqu.SelectDataset {
|
||||
return dialect.From(qb.table()).Select(qb.table().All())
|
||||
}
|
||||
|
||||
func (qb *MovieStore) Create(ctx context.Context, newObject *models.Movie) error {
|
||||
var r movieRow
|
||||
r.fromMovie(*newObject)
|
||||
func (qb *GroupStore) Create(ctx context.Context, newObject *models.Group) error {
|
||||
var r groupRow
|
||||
r.fromGroup(*newObject)
|
||||
|
||||
id, err := qb.tableMgr.insertID(ctx, r)
|
||||
if err != nil {
|
||||
|
|
@ -167,7 +167,7 @@ func (qb *MovieStore) Create(ctx context.Context, newObject *models.Movie) error
|
|||
|
||||
if newObject.URLs.Loaded() {
|
||||
const startPos = 0
|
||||
if err := moviesURLsTableMgr.insertJoins(ctx, id, startPos, newObject.URLs.List()); err != nil {
|
||||
if err := groupsURLsTableMgr.insertJoins(ctx, id, startPos, newObject.URLs.List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -186,8 +186,8 @@ func (qb *MovieStore) Create(ctx context.Context, newObject *models.Movie) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) UpdatePartial(ctx context.Context, id int, partial models.MoviePartial) (*models.Movie, error) {
|
||||
r := movieRowRecord{
|
||||
func (qb *GroupStore) UpdatePartial(ctx context.Context, id int, partial models.GroupPartial) (*models.Group, error) {
|
||||
r := groupRowRecord{
|
||||
updateRecord{
|
||||
Record: make(exp.Record),
|
||||
},
|
||||
|
|
@ -202,7 +202,7 @@ func (qb *MovieStore) UpdatePartial(ctx context.Context, id int, partial models.
|
|||
}
|
||||
|
||||
if partial.URLs != nil {
|
||||
if err := moviesURLsTableMgr.modifyJoins(ctx, id, partial.URLs.Values, partial.URLs.Mode); err != nil {
|
||||
if err := groupsURLsTableMgr.modifyJoins(ctx, id, partial.URLs.Values, partial.URLs.Mode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
@ -214,16 +214,16 @@ func (qb *MovieStore) UpdatePartial(ctx context.Context, id int, partial models.
|
|||
return qb.find(ctx, id)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) Update(ctx context.Context, updatedObject *models.Movie) error {
|
||||
var r movieRow
|
||||
r.fromMovie(*updatedObject)
|
||||
func (qb *GroupStore) Update(ctx context.Context, updatedObject *models.Group) error {
|
||||
var r groupRow
|
||||
r.fromGroup(*updatedObject)
|
||||
|
||||
if err := qb.tableMgr.updateByID(ctx, updatedObject.ID, r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updatedObject.URLs.Loaded() {
|
||||
if err := moviesURLsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.URLs.List()); err != nil {
|
||||
if err := groupsURLsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.URLs.List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -235,17 +235,17 @@ func (qb *MovieStore) Update(ctx context.Context, updatedObject *models.Movie) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) Destroy(ctx context.Context, id int) error {
|
||||
func (qb *GroupStore) Destroy(ctx context.Context, id int) error {
|
||||
// must handle image checksums manually
|
||||
if err := qb.destroyImages(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return movieRepository.destroyExisting(ctx, []int{id})
|
||||
return groupRepository.destroyExisting(ctx, []int{id})
|
||||
}
|
||||
|
||||
// returns nil, nil if not found
|
||||
func (qb *MovieStore) Find(ctx context.Context, id int) (*models.Movie, error) {
|
||||
func (qb *GroupStore) Find(ctx context.Context, id int) (*models.Group, error) {
|
||||
ret, err := qb.find(ctx, id)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
|
|
@ -253,8 +253,8 @@ func (qb *MovieStore) Find(ctx context.Context, id int) (*models.Movie, error) {
|
|||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *MovieStore) FindMany(ctx context.Context, ids []int) ([]*models.Movie, error) {
|
||||
ret := make([]*models.Movie, len(ids))
|
||||
func (qb *GroupStore) FindMany(ctx context.Context, ids []int) ([]*models.Group, error) {
|
||||
ret := make([]*models.Group, len(ids))
|
||||
|
||||
table := qb.table()
|
||||
if err := batchExec(ids, defaultBatchSize, func(batch []int) error {
|
||||
|
|
@ -276,7 +276,7 @@ func (qb *MovieStore) FindMany(ctx context.Context, ids []int) ([]*models.Movie,
|
|||
|
||||
for i := range ret {
|
||||
if ret[i] == nil {
|
||||
return nil, fmt.Errorf("movie with id %d not found", ids[i])
|
||||
return nil, fmt.Errorf("group with id %d not found", ids[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +284,7 @@ func (qb *MovieStore) FindMany(ctx context.Context, ids []int) ([]*models.Movie,
|
|||
}
|
||||
|
||||
// returns nil, sql.ErrNoRows if not found
|
||||
func (qb *MovieStore) find(ctx context.Context, id int) (*models.Movie, error) {
|
||||
func (qb *GroupStore) find(ctx context.Context, id int) (*models.Group, error) {
|
||||
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
|
||||
|
||||
ret, err := qb.get(ctx, q)
|
||||
|
|
@ -296,7 +296,7 @@ func (qb *MovieStore) find(ctx context.Context, id int) (*models.Movie, error) {
|
|||
}
|
||||
|
||||
// returns nil, sql.ErrNoRows if not found
|
||||
func (qb *MovieStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Movie, error) {
|
||||
func (qb *GroupStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Group, error) {
|
||||
ret, err := qb.getMany(ctx, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -309,11 +309,11 @@ func (qb *MovieStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.M
|
|||
return ret[0], nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Movie, error) {
|
||||
func (qb *GroupStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Group, error) {
|
||||
const single = false
|
||||
var ret []*models.Movie
|
||||
var ret []*models.Group
|
||||
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
||||
var f movieRow
|
||||
var f groupRow
|
||||
if err := r.StructScan(&f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -329,7 +329,7 @@ func (qb *MovieStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) FindByName(ctx context.Context, name string, nocase bool) (*models.Movie, error) {
|
||||
func (qb *GroupStore) FindByName(ctx context.Context, name string, nocase bool) (*models.Group, error) {
|
||||
// query := "SELECT * FROM movies WHERE name = ?"
|
||||
// if nocase {
|
||||
// query += " COLLATE NOCASE"
|
||||
|
|
@ -349,7 +349,7 @@ func (qb *MovieStore) FindByName(ctx context.Context, name string, nocase bool)
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Movie, error) {
|
||||
func (qb *GroupStore) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Group, error) {
|
||||
// query := "SELECT * FROM movies WHERE name"
|
||||
// if nocase {
|
||||
// query += " COLLATE NOCASE"
|
||||
|
|
@ -374,12 +374,12 @@ func (qb *MovieStore) FindByNames(ctx context.Context, names []string, nocase bo
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) Count(ctx context.Context) (int, error) {
|
||||
func (qb *GroupStore) Count(ctx context.Context) (int, error) {
|
||||
q := dialect.Select(goqu.COUNT("*")).From(qb.table())
|
||||
return count(ctx, q)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) All(ctx context.Context) ([]*models.Movie, error) {
|
||||
func (qb *GroupStore) All(ctx context.Context) ([]*models.Group, error) {
|
||||
table := qb.table()
|
||||
|
||||
return qb.getMany(ctx, qb.selectDataset().Order(
|
||||
|
|
@ -388,24 +388,24 @@ func (qb *MovieStore) All(ctx context.Context) ([]*models.Movie, error) {
|
|||
))
|
||||
}
|
||||
|
||||
func (qb *MovieStore) makeQuery(ctx context.Context, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) (*queryBuilder, error) {
|
||||
func (qb *GroupStore) makeQuery(ctx context.Context, groupFilter *models.GroupFilterType, findFilter *models.FindFilterType) (*queryBuilder, error) {
|
||||
if findFilter == nil {
|
||||
findFilter = &models.FindFilterType{}
|
||||
}
|
||||
if movieFilter == nil {
|
||||
movieFilter = &models.MovieFilterType{}
|
||||
if groupFilter == nil {
|
||||
groupFilter = &models.GroupFilterType{}
|
||||
}
|
||||
|
||||
query := movieRepository.newQuery()
|
||||
distinctIDs(&query, movieTable)
|
||||
query := groupRepository.newQuery()
|
||||
distinctIDs(&query, groupTable)
|
||||
|
||||
if q := findFilter.Q; q != nil && *q != "" {
|
||||
searchColumns := []string{"movies.name", "movies.aliases"}
|
||||
query.parseQueryString(searchColumns, *q)
|
||||
}
|
||||
|
||||
filter := filterBuilderFromHandler(ctx, &movieFilterHandler{
|
||||
movieFilter: movieFilter,
|
||||
filter := filterBuilderFromHandler(ctx, &groupFilterHandler{
|
||||
groupFilter: groupFilter,
|
||||
})
|
||||
|
||||
if err := query.addFilter(filter); err != nil {
|
||||
|
|
@ -413,7 +413,7 @@ func (qb *MovieStore) makeQuery(ctx context.Context, movieFilter *models.MovieFi
|
|||
}
|
||||
|
||||
var err error
|
||||
query.sortAndPagination, err = qb.getMovieSort(findFilter)
|
||||
query.sortAndPagination, err = qb.getGroupSort(findFilter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -423,8 +423,8 @@ func (qb *MovieStore) makeQuery(ctx context.Context, movieFilter *models.MovieFi
|
|||
return &query, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) Query(ctx context.Context, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) ([]*models.Movie, int, error) {
|
||||
query, err := qb.makeQuery(ctx, movieFilter, findFilter)
|
||||
func (qb *GroupStore) Query(ctx context.Context, groupFilter *models.GroupFilterType, findFilter *models.FindFilterType) ([]*models.Group, int, error) {
|
||||
query, err := qb.makeQuery(ctx, groupFilter, findFilter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
|
@ -434,16 +434,16 @@ func (qb *MovieStore) Query(ctx context.Context, movieFilter *models.MovieFilter
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
movies, err := qb.FindMany(ctx, idsResult)
|
||||
groups, err := qb.FindMany(ctx, idsResult)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return movies, countResult, nil
|
||||
return groups, countResult, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) QueryCount(ctx context.Context, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) (int, error) {
|
||||
query, err := qb.makeQuery(ctx, movieFilter, findFilter)
|
||||
func (qb *GroupStore) QueryCount(ctx context.Context, groupFilter *models.GroupFilterType, findFilter *models.FindFilterType) (int, error) {
|
||||
query, err := qb.makeQuery(ctx, groupFilter, findFilter)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -451,7 +451,7 @@ func (qb *MovieStore) QueryCount(ctx context.Context, movieFilter *models.MovieF
|
|||
return query.executeCount(ctx)
|
||||
}
|
||||
|
||||
var movieSortOptions = sortOptions{
|
||||
var groupSortOptions = sortOptions{
|
||||
"created_at",
|
||||
"date",
|
||||
"duration",
|
||||
|
|
@ -464,7 +464,7 @@ var movieSortOptions = sortOptions{
|
|||
"updated_at",
|
||||
}
|
||||
|
||||
func (qb *MovieStore) getMovieSort(findFilter *models.FindFilterType) (string, error) {
|
||||
func (qb *GroupStore) getGroupSort(findFilter *models.FindFilterType) (string, error) {
|
||||
var sort string
|
||||
var direction string
|
||||
if findFilter == nil {
|
||||
|
|
@ -476,16 +476,16 @@ func (qb *MovieStore) getMovieSort(findFilter *models.FindFilterType) (string, e
|
|||
}
|
||||
|
||||
// CVE-2024-32231 - ensure sort is in the list of allowed sorts
|
||||
if err := movieSortOptions.validateSort(sort); err != nil {
|
||||
if err := groupSortOptions.validateSort(sort); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sortQuery := ""
|
||||
switch sort {
|
||||
case "tag_count":
|
||||
sortQuery += getCountSort(movieTable, moviesTagsTable, movieIDColumn, direction)
|
||||
sortQuery += getCountSort(groupTable, groupsTagsTable, groupIDColumn, direction)
|
||||
case "scenes_count": // generic getSort won't work for this
|
||||
sortQuery += getCountSort(movieTable, moviesScenesTable, movieIDColumn, direction)
|
||||
sortQuery += getCountSort(groupTable, groupsScenesTable, groupIDColumn, direction)
|
||||
default:
|
||||
sortQuery += getSort(sort, direction, "movies")
|
||||
}
|
||||
|
|
@ -495,11 +495,11 @@ func (qb *MovieStore) getMovieSort(findFilter *models.FindFilterType) (string, e
|
|||
return sortQuery, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) queryMovies(ctx context.Context, query string, args []interface{}) ([]*models.Movie, error) {
|
||||
func (qb *GroupStore) queryGroups(ctx context.Context, query string, args []interface{}) ([]*models.Group, error) {
|
||||
const single = false
|
||||
var ret []*models.Movie
|
||||
if err := movieRepository.queryFunc(ctx, query, args, single, func(r *sqlx.Rows) error {
|
||||
var f movieRow
|
||||
var ret []*models.Group
|
||||
if err := groupRepository.queryFunc(ctx, query, args, single, func(r *sqlx.Rows) error {
|
||||
var f groupRow
|
||||
if err := r.StructScan(&f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -515,42 +515,42 @@ func (qb *MovieStore) queryMovies(ctx context.Context, query string, args []inte
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) UpdateFrontImage(ctx context.Context, movieID int, frontImage []byte) error {
|
||||
return qb.UpdateImage(ctx, movieID, movieFrontImageBlobColumn, frontImage)
|
||||
func (qb *GroupStore) UpdateFrontImage(ctx context.Context, groupID int, frontImage []byte) error {
|
||||
return qb.UpdateImage(ctx, groupID, groupFrontImageBlobColumn, frontImage)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) UpdateBackImage(ctx context.Context, movieID int, backImage []byte) error {
|
||||
return qb.UpdateImage(ctx, movieID, movieBackImageBlobColumn, backImage)
|
||||
func (qb *GroupStore) UpdateBackImage(ctx context.Context, groupID int, backImage []byte) error {
|
||||
return qb.UpdateImage(ctx, groupID, groupBackImageBlobColumn, backImage)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) destroyImages(ctx context.Context, movieID int) error {
|
||||
if err := qb.DestroyImage(ctx, movieID, movieFrontImageBlobColumn); err != nil {
|
||||
func (qb *GroupStore) destroyImages(ctx context.Context, groupID int) error {
|
||||
if err := qb.DestroyImage(ctx, groupID, groupFrontImageBlobColumn); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := qb.DestroyImage(ctx, movieID, movieBackImageBlobColumn); err != nil {
|
||||
if err := qb.DestroyImage(ctx, groupID, groupBackImageBlobColumn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qb *MovieStore) GetFrontImage(ctx context.Context, movieID int) ([]byte, error) {
|
||||
return qb.GetImage(ctx, movieID, movieFrontImageBlobColumn)
|
||||
func (qb *GroupStore) GetFrontImage(ctx context.Context, groupID int) ([]byte, error) {
|
||||
return qb.GetImage(ctx, groupID, groupFrontImageBlobColumn)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) HasFrontImage(ctx context.Context, movieID int) (bool, error) {
|
||||
return qb.HasImage(ctx, movieID, movieFrontImageBlobColumn)
|
||||
func (qb *GroupStore) HasFrontImage(ctx context.Context, groupID int) (bool, error) {
|
||||
return qb.HasImage(ctx, groupID, groupFrontImageBlobColumn)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) GetBackImage(ctx context.Context, movieID int) ([]byte, error) {
|
||||
return qb.GetImage(ctx, movieID, movieBackImageBlobColumn)
|
||||
func (qb *GroupStore) GetBackImage(ctx context.Context, groupID int) ([]byte, error) {
|
||||
return qb.GetImage(ctx, groupID, groupBackImageBlobColumn)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) HasBackImage(ctx context.Context, movieID int) (bool, error) {
|
||||
return qb.HasImage(ctx, movieID, movieBackImageBlobColumn)
|
||||
func (qb *GroupStore) HasBackImage(ctx context.Context, groupID int) (bool, error) {
|
||||
return qb.HasImage(ctx, groupID, groupBackImageBlobColumn)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) FindByPerformerID(ctx context.Context, performerID int) ([]*models.Movie, error) {
|
||||
func (qb *GroupStore) FindByPerformerID(ctx context.Context, performerID int) ([]*models.Group, error) {
|
||||
query := `SELECT DISTINCT movies.*
|
||||
FROM movies
|
||||
INNER JOIN movies_scenes ON movies.id = movies_scenes.movie_id
|
||||
|
|
@ -558,37 +558,37 @@ INNER JOIN performers_scenes ON performers_scenes.scene_id = movies_scenes.scene
|
|||
WHERE performers_scenes.performer_id = ?
|
||||
`
|
||||
args := []interface{}{performerID}
|
||||
return qb.queryMovies(ctx, query, args)
|
||||
return qb.queryGroups(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) CountByPerformerID(ctx context.Context, performerID int) (int, error) {
|
||||
func (qb *GroupStore) CountByPerformerID(ctx context.Context, performerID int) (int, error) {
|
||||
query := `SELECT COUNT(DISTINCT movies_scenes.movie_id) AS count
|
||||
FROM movies_scenes
|
||||
INNER JOIN performers_scenes ON performers_scenes.scene_id = movies_scenes.scene_id
|
||||
WHERE performers_scenes.performer_id = ?
|
||||
`
|
||||
args := []interface{}{performerID}
|
||||
return movieRepository.runCountQuery(ctx, query, args)
|
||||
return groupRepository.runCountQuery(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) FindByStudioID(ctx context.Context, studioID int) ([]*models.Movie, error) {
|
||||
func (qb *GroupStore) FindByStudioID(ctx context.Context, studioID int) ([]*models.Group, error) {
|
||||
query := `SELECT movies.*
|
||||
FROM movies
|
||||
WHERE movies.studio_id = ?
|
||||
`
|
||||
args := []interface{}{studioID}
|
||||
return qb.queryMovies(ctx, query, args)
|
||||
return qb.queryGroups(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) CountByStudioID(ctx context.Context, studioID int) (int, error) {
|
||||
func (qb *GroupStore) CountByStudioID(ctx context.Context, studioID int) (int, error) {
|
||||
query := `SELECT COUNT(1) AS count
|
||||
FROM movies
|
||||
WHERE movies.studio_id = ?
|
||||
`
|
||||
args := []interface{}{studioID}
|
||||
return movieRepository.runCountQuery(ctx, query, args)
|
||||
return groupRepository.runCountQuery(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *MovieStore) GetURLs(ctx context.Context, movieID int) ([]string, error) {
|
||||
return moviesURLsTableMgr.get(ctx, movieID)
|
||||
func (qb *GroupStore) GetURLs(ctx context.Context, groupID int) ([]string, error) {
|
||||
return groupsURLsTableMgr.get(ctx, groupID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,22 +7,22 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
type movieFilterHandler struct {
|
||||
movieFilter *models.MovieFilterType
|
||||
type groupFilterHandler struct {
|
||||
groupFilter *models.GroupFilterType
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) validate() error {
|
||||
movieFilter := qb.movieFilter
|
||||
if movieFilter == nil {
|
||||
func (qb *groupFilterHandler) validate() error {
|
||||
groupFilter := qb.groupFilter
|
||||
if groupFilter == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := validateFilterCombination(movieFilter.OperatorFilter); err != nil {
|
||||
if err := validateFilterCombination(groupFilter.OperatorFilter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if subFilter := movieFilter.SubFilter(); subFilter != nil {
|
||||
sqb := &movieFilterHandler{movieFilter: subFilter}
|
||||
if subFilter := groupFilter.SubFilter(); subFilter != nil {
|
||||
sqb := &groupFilterHandler{groupFilter: subFilter}
|
||||
if err := sqb.validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -31,9 +31,9 @@ func (qb *movieFilterHandler) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) handle(ctx context.Context, f *filterBuilder) {
|
||||
movieFilter := qb.movieFilter
|
||||
if movieFilter == nil {
|
||||
func (qb *groupFilterHandler) handle(ctx context.Context, f *filterBuilder) {
|
||||
groupFilter := qb.groupFilter
|
||||
if groupFilter == nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -42,51 +42,51 @@ func (qb *movieFilterHandler) handle(ctx context.Context, f *filterBuilder) {
|
|||
return
|
||||
}
|
||||
|
||||
sf := movieFilter.SubFilter()
|
||||
sf := groupFilter.SubFilter()
|
||||
if sf != nil {
|
||||
sub := &movieFilterHandler{sf}
|
||||
handleSubFilter(ctx, sub, f, movieFilter.OperatorFilter)
|
||||
sub := &groupFilterHandler{sf}
|
||||
handleSubFilter(ctx, sub, f, groupFilter.OperatorFilter)
|
||||
}
|
||||
|
||||
f.handleCriterion(ctx, qb.criterionHandler())
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) criterionHandler() criterionHandler {
|
||||
movieFilter := qb.movieFilter
|
||||
func (qb *groupFilterHandler) criterionHandler() criterionHandler {
|
||||
groupFilter := qb.groupFilter
|
||||
return compoundHandler{
|
||||
stringCriterionHandler(movieFilter.Name, "movies.name"),
|
||||
stringCriterionHandler(movieFilter.Director, "movies.director"),
|
||||
stringCriterionHandler(movieFilter.Synopsis, "movies.synopsis"),
|
||||
intCriterionHandler(movieFilter.Rating100, "movies.rating", nil),
|
||||
floatIntCriterionHandler(movieFilter.Duration, "movies.duration", nil),
|
||||
qb.missingCriterionHandler(movieFilter.IsMissing),
|
||||
qb.urlsCriterionHandler(movieFilter.URL),
|
||||
studioCriterionHandler(movieTable, movieFilter.Studios),
|
||||
qb.performersCriterionHandler(movieFilter.Performers),
|
||||
qb.tagsCriterionHandler(movieFilter.Tags),
|
||||
qb.tagCountCriterionHandler(movieFilter.TagCount),
|
||||
&dateCriterionHandler{movieFilter.Date, "movies.date", nil},
|
||||
×tampCriterionHandler{movieFilter.CreatedAt, "movies.created_at", nil},
|
||||
×tampCriterionHandler{movieFilter.UpdatedAt, "movies.updated_at", nil},
|
||||
stringCriterionHandler(groupFilter.Name, "movies.name"),
|
||||
stringCriterionHandler(groupFilter.Director, "movies.director"),
|
||||
stringCriterionHandler(groupFilter.Synopsis, "movies.synopsis"),
|
||||
intCriterionHandler(groupFilter.Rating100, "movies.rating", nil),
|
||||
floatIntCriterionHandler(groupFilter.Duration, "movies.duration", nil),
|
||||
qb.missingCriterionHandler(groupFilter.IsMissing),
|
||||
qb.urlsCriterionHandler(groupFilter.URL),
|
||||
studioCriterionHandler(groupTable, groupFilter.Studios),
|
||||
qb.performersCriterionHandler(groupFilter.Performers),
|
||||
qb.tagsCriterionHandler(groupFilter.Tags),
|
||||
qb.tagCountCriterionHandler(groupFilter.TagCount),
|
||||
&dateCriterionHandler{groupFilter.Date, "movies.date", nil},
|
||||
×tampCriterionHandler{groupFilter.CreatedAt, "movies.created_at", nil},
|
||||
×tampCriterionHandler{groupFilter.UpdatedAt, "movies.updated_at", nil},
|
||||
|
||||
&relatedFilterHandler{
|
||||
relatedIDCol: "movies_scenes.scene_id",
|
||||
relatedRepo: sceneRepository.repository,
|
||||
relatedHandler: &sceneFilterHandler{movieFilter.ScenesFilter},
|
||||
relatedHandler: &sceneFilterHandler{groupFilter.ScenesFilter},
|
||||
joinFn: func(f *filterBuilder) {
|
||||
movieRepository.scenes.innerJoin(f, "", "movies.id")
|
||||
groupRepository.scenes.innerJoin(f, "", "movies.id")
|
||||
},
|
||||
},
|
||||
|
||||
&relatedFilterHandler{
|
||||
relatedIDCol: "movies.studio_id",
|
||||
relatedRepo: studioRepository.repository,
|
||||
relatedHandler: &studioFilterHandler{movieFilter.StudiosFilter},
|
||||
relatedHandler: &studioFilterHandler{groupFilter.StudiosFilter},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) missingCriterionHandler(isMissing *string) criterionHandlerFunc {
|
||||
func (qb *groupFilterHandler) missingCriterionHandler(isMissing *string) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if isMissing != nil && *isMissing != "" {
|
||||
switch *isMissing {
|
||||
|
|
@ -104,21 +104,21 @@ func (qb *movieFilterHandler) missingCriterionHandler(isMissing *string) criteri
|
|||
}
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) urlsCriterionHandler(url *models.StringCriterionInput) criterionHandlerFunc {
|
||||
func (qb *groupFilterHandler) urlsCriterionHandler(url *models.StringCriterionInput) criterionHandlerFunc {
|
||||
h := stringListCriterionHandlerBuilder{
|
||||
primaryTable: movieTable,
|
||||
primaryFK: movieIDColumn,
|
||||
joinTable: movieURLsTable,
|
||||
stringColumn: movieURLColumn,
|
||||
primaryTable: groupTable,
|
||||
primaryFK: groupIDColumn,
|
||||
joinTable: groupURLsTable,
|
||||
stringColumn: groupURLColumn,
|
||||
addJoinTable: func(f *filterBuilder) {
|
||||
moviesURLsTableMgr.join(f, "", "movies.id")
|
||||
groupsURLsTableMgr.join(f, "", "movies.id")
|
||||
},
|
||||
}
|
||||
|
||||
return h.handler(url)
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) performersCriterionHandler(performers *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
func (qb *groupFilterHandler) performersCriterionHandler(performers *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if performers != nil {
|
||||
if performers.Modifier == models.CriterionModifierIsNull || performers.Modifier == models.CriterionModifierNotNull {
|
||||
|
|
@ -165,26 +165,26 @@ func (qb *movieFilterHandler) performersCriterionHandler(performers *models.Mult
|
|||
}
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) tagsCriterionHandler(tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||
func (qb *groupFilterHandler) tagsCriterionHandler(tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||
h := joinedHierarchicalMultiCriterionHandlerBuilder{
|
||||
primaryTable: movieTable,
|
||||
primaryTable: groupTable,
|
||||
foreignTable: tagTable,
|
||||
foreignFK: "tag_id",
|
||||
|
||||
relationsTable: "tags_relations",
|
||||
joinAs: "movie_tag",
|
||||
joinTable: moviesTagsTable,
|
||||
primaryFK: movieIDColumn,
|
||||
joinTable: groupsTagsTable,
|
||||
primaryFK: groupIDColumn,
|
||||
}
|
||||
|
||||
return h.handler(tags)
|
||||
}
|
||||
|
||||
func (qb *movieFilterHandler) tagCountCriterionHandler(count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
func (qb *groupFilterHandler) tagCountCriterionHandler(count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
h := countCriterionHandlerBuilder{
|
||||
primaryTable: movieTable,
|
||||
joinTable: moviesTagsTable,
|
||||
primaryFK: movieIDColumn,
|
||||
primaryTable: groupTable,
|
||||
joinTable: groupsTagsTable,
|
||||
primaryFK: groupIDColumn,
|
||||
}
|
||||
|
||||
return h.handler(count)
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
func loadMovieRelationships(ctx context.Context, expected models.Movie, actual *models.Movie) error {
|
||||
func loadGroupRelationships(ctx context.Context, expected models.Group, actual *models.Group) error {
|
||||
if expected.URLs.Loaded() {
|
||||
if err := actual.LoadURLs(ctx, db.Movie); err != nil {
|
||||
if err := actual.LoadURLs(ctx, db.Group); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if expected.TagIDs.Loaded() {
|
||||
if err := actual.LoadTagIDs(ctx, db.Movie); err != nil {
|
||||
if err := actual.LoadTagIDs(ctx, db.Group); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ func loadMovieRelationships(ctx context.Context, expected models.Movie, actual *
|
|||
return nil
|
||||
}
|
||||
|
||||
func Test_MovieStore_Create(t *testing.T) {
|
||||
func Test_GroupStore_Create(t *testing.T) {
|
||||
var (
|
||||
name = "name"
|
||||
url = "url"
|
||||
|
|
@ -47,21 +47,21 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
newObject models.Movie
|
||||
newObject models.Group
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"full",
|
||||
models.Movie{
|
||||
models.Group{
|
||||
Name: name,
|
||||
Duration: &duration,
|
||||
Date: &date,
|
||||
Rating: &rating,
|
||||
StudioID: &studioIDs[studioIdxWithMovie],
|
||||
StudioID: &studioIDs[studioIdxWithGroup],
|
||||
Director: director,
|
||||
Synopsis: synopsis,
|
||||
URLs: models.NewRelatedStrings([]string{url}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithMovie]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithGroup]}),
|
||||
Aliases: aliases,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
|
|
@ -70,7 +70,7 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"invalid tag id",
|
||||
models.Movie{
|
||||
models.Group{
|
||||
Name: name,
|
||||
TagIDs: models.NewRelatedIDs([]int{invalidID}),
|
||||
},
|
||||
|
|
@ -78,7 +78,7 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
qb := db.Movie
|
||||
qb := db.Group
|
||||
|
||||
for _, tt := range tests {
|
||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||
|
|
@ -86,7 +86,7 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
|
||||
p := tt.newObject
|
||||
if err := qb.Create(ctx, &p); (err != nil) != tt.wantErr {
|
||||
t.Errorf("MovieStore.Create() error = %v, wantErr = %v", err, tt.wantErr)
|
||||
t.Errorf("GroupStore.Create() error = %v, wantErr = %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if tt.wantErr {
|
||||
|
|
@ -100,17 +100,17 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
copy.ID = p.ID
|
||||
|
||||
// load relationships
|
||||
if err := loadMovieRelationships(ctx, copy, &p); err != nil {
|
||||
t.Errorf("loadMovieRelationships() error = %v", err)
|
||||
if err := loadGroupRelationships(ctx, copy, &p); err != nil {
|
||||
t.Errorf("loadGroupRelationships() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(copy, p)
|
||||
|
||||
// ensure can find the movie
|
||||
// ensure can find the group
|
||||
found, err := qb.Find(ctx, p.ID)
|
||||
if err != nil {
|
||||
t.Errorf("MovieStore.Find() error = %v", err)
|
||||
t.Errorf("GroupStore.Find() error = %v", err)
|
||||
}
|
||||
|
||||
if !assert.NotNil(found) {
|
||||
|
|
@ -118,8 +118,8 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
}
|
||||
|
||||
// load relationships
|
||||
if err := loadMovieRelationships(ctx, copy, found); err != nil {
|
||||
t.Errorf("loadMovieRelationships() error = %v", err)
|
||||
if err := loadGroupRelationships(ctx, copy, found); err != nil {
|
||||
t.Errorf("loadGroupRelationships() error = %v", err)
|
||||
return
|
||||
}
|
||||
assert.Equal(copy, *found)
|
||||
|
|
@ -129,7 +129,7 @@ func Test_MovieStore_Create(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_movieQueryBuilder_Update(t *testing.T) {
|
||||
func Test_groupQueryBuilder_Update(t *testing.T) {
|
||||
var (
|
||||
name = "name"
|
||||
url = "url"
|
||||
|
|
@ -145,22 +145,22 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
updatedObject *models.Movie
|
||||
updatedObject *models.Group
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"full",
|
||||
&models.Movie{
|
||||
ID: movieIDs[movieIdxWithTag],
|
||||
&models.Group{
|
||||
ID: groupIDs[groupIdxWithTag],
|
||||
Name: name,
|
||||
Duration: &duration,
|
||||
Date: &date,
|
||||
Rating: &rating,
|
||||
StudioID: &studioIDs[studioIdxWithMovie],
|
||||
StudioID: &studioIDs[studioIdxWithGroup],
|
||||
Director: director,
|
||||
Synopsis: synopsis,
|
||||
URLs: models.NewRelatedStrings([]string{url}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithMovie]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithGroup]}),
|
||||
Aliases: aliases,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
|
|
@ -169,8 +169,8 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"clear tag ids",
|
||||
&models.Movie{
|
||||
ID: movieIDs[movieIdxWithTag],
|
||||
&models.Group{
|
||||
ID: groupIDs[groupIdxWithTag],
|
||||
Name: name,
|
||||
TagIDs: models.NewRelatedIDs([]int{}),
|
||||
},
|
||||
|
|
@ -178,8 +178,8 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"invalid studio id",
|
||||
&models.Movie{
|
||||
ID: movieIDs[movieIdxWithScene],
|
||||
&models.Group{
|
||||
ID: groupIDs[groupIdxWithScene],
|
||||
Name: name,
|
||||
StudioID: &invalidID,
|
||||
},
|
||||
|
|
@ -187,8 +187,8 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"invalid tag id",
|
||||
&models.Movie{
|
||||
ID: movieIDs[movieIdxWithScene],
|
||||
&models.Group{
|
||||
ID: groupIDs[groupIdxWithScene],
|
||||
Name: name,
|
||||
TagIDs: models.NewRelatedIDs([]int{invalidID}),
|
||||
},
|
||||
|
|
@ -196,7 +196,7 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
qb := db.Movie
|
||||
qb := db.Group
|
||||
for _, tt := range tests {
|
||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||
assert := assert.New(t)
|
||||
|
|
@ -204,7 +204,7 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
copy := *tt.updatedObject
|
||||
|
||||
if err := qb.Update(ctx, tt.updatedObject); (err != nil) != tt.wantErr {
|
||||
t.Errorf("movieQueryBuilder.Update() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Errorf("groupQueryBuilder.Update() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if tt.wantErr {
|
||||
|
|
@ -213,12 +213,12 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
|
||||
s, err := qb.Find(ctx, tt.updatedObject.ID)
|
||||
if err != nil {
|
||||
t.Errorf("movieQueryBuilder.Find() error = %v", err)
|
||||
t.Errorf("groupQueryBuilder.Find() error = %v", err)
|
||||
}
|
||||
|
||||
// load relationships
|
||||
if err := loadMovieRelationships(ctx, copy, s); err != nil {
|
||||
t.Errorf("loadMovieRelationships() error = %v", err)
|
||||
if err := loadGroupRelationships(ctx, copy, s); err != nil {
|
||||
t.Errorf("loadGroupRelationships() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -227,9 +227,9 @@ func Test_movieQueryBuilder_Update(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func clearMoviePartial() models.MoviePartial {
|
||||
func clearGroupPartial() models.GroupPartial {
|
||||
// leave mandatory fields
|
||||
return models.MoviePartial{
|
||||
return models.GroupPartial{
|
||||
Aliases: models.OptionalString{Set: true, Null: true},
|
||||
Synopsis: models.OptionalString{Set: true, Null: true},
|
||||
Director: models.OptionalString{Set: true, Null: true},
|
||||
|
|
@ -242,7 +242,7 @@ func clearMoviePartial() models.MoviePartial {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
||||
func Test_groupQueryBuilder_UpdatePartial(t *testing.T) {
|
||||
var (
|
||||
name = "name"
|
||||
url = "url"
|
||||
|
|
@ -259,14 +259,14 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
id int
|
||||
partial models.MoviePartial
|
||||
want models.Movie
|
||||
partial models.GroupPartial
|
||||
want models.Group
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"full",
|
||||
movieIDs[movieIdxWithScene],
|
||||
models.MoviePartial{
|
||||
groupIDs[groupIdxWithScene],
|
||||
models.GroupPartial{
|
||||
Name: models.NewOptionalString(name),
|
||||
Director: models.NewOptionalString(director),
|
||||
Synopsis: models.NewOptionalString(synopsis),
|
||||
|
|
@ -278,16 +278,16 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
Date: models.NewOptionalDate(date),
|
||||
Duration: models.NewOptionalInt(duration),
|
||||
Rating: models.NewOptionalInt(rating),
|
||||
StudioID: models.NewOptionalInt(studioIDs[studioIdxWithMovie]),
|
||||
StudioID: models.NewOptionalInt(studioIDs[studioIdxWithGroup]),
|
||||
CreatedAt: models.NewOptionalTime(createdAt),
|
||||
UpdatedAt: models.NewOptionalTime(updatedAt),
|
||||
TagIDs: &models.UpdateIDs{
|
||||
IDs: []int{tagIDs[tagIdx1WithMovie], tagIDs[tagIdx1WithDupName]},
|
||||
IDs: []int{tagIDs[tagIdx1WithGroup], tagIDs[tagIdx1WithDupName]},
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
},
|
||||
},
|
||||
models.Movie{
|
||||
ID: movieIDs[movieIdxWithScene],
|
||||
models.Group{
|
||||
ID: groupIDs[groupIdxWithScene],
|
||||
Name: name,
|
||||
Director: director,
|
||||
Synopsis: synopsis,
|
||||
|
|
@ -296,20 +296,20 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
Date: &date,
|
||||
Duration: &duration,
|
||||
Rating: &rating,
|
||||
StudioID: &studioIDs[studioIdxWithMovie],
|
||||
StudioID: &studioIDs[studioIdxWithGroup],
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithMovie]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithGroup]}),
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"clear all",
|
||||
movieIDs[movieIdxWithScene],
|
||||
clearMoviePartial(),
|
||||
models.Movie{
|
||||
ID: movieIDs[movieIdxWithScene],
|
||||
Name: movieNames[movieIdxWithScene],
|
||||
groupIDs[groupIdxWithScene],
|
||||
clearGroupPartial(),
|
||||
models.Group{
|
||||
ID: groupIDs[groupIdxWithScene],
|
||||
Name: groupNames[groupIdxWithScene],
|
||||
TagIDs: models.NewRelatedIDs([]int{}),
|
||||
},
|
||||
false,
|
||||
|
|
@ -317,20 +317,20 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
{
|
||||
"invalid id",
|
||||
invalidID,
|
||||
models.MoviePartial{},
|
||||
models.Movie{},
|
||||
models.GroupPartial{},
|
||||
models.Group{},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
qb := db.Movie
|
||||
qb := db.Group
|
||||
|
||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||
assert := assert.New(t)
|
||||
|
||||
got, err := qb.UpdatePartial(ctx, tt.id, tt.partial)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("movieQueryBuilder.UpdatePartial() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Errorf("groupQueryBuilder.UpdatePartial() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -339,8 +339,8 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
}
|
||||
|
||||
// load relationships
|
||||
if err := loadMovieRelationships(ctx, tt.want, got); err != nil {
|
||||
t.Errorf("loadMovieRelationships() error = %v", err)
|
||||
if err := loadGroupRelationships(ctx, tt.want, got); err != nil {
|
||||
t.Errorf("loadGroupRelationships() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -348,12 +348,12 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
|
||||
s, err := qb.Find(ctx, tt.id)
|
||||
if err != nil {
|
||||
t.Errorf("movieQueryBuilder.Find() error = %v", err)
|
||||
t.Errorf("groupQueryBuilder.Find() error = %v", err)
|
||||
}
|
||||
|
||||
// load relationships
|
||||
if err := loadMovieRelationships(ctx, tt.want, s); err != nil {
|
||||
t.Errorf("loadMovieRelationships() error = %v", err)
|
||||
if err := loadGroupRelationships(ctx, tt.want, s); err != nil {
|
||||
t.Errorf("loadGroupRelationships() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -362,65 +362,65 @@ func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMovieFindByName(t *testing.T) {
|
||||
func TestGroupFindByName(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
mqb := db.Movie
|
||||
mqb := db.Group
|
||||
|
||||
name := movieNames[movieIdxWithScene] // find a movie by name
|
||||
name := groupNames[groupIdxWithScene] // find a group by name
|
||||
|
||||
movie, err := mqb.FindByName(ctx, name, false)
|
||||
group, err := mqb.FindByName(ctx, name, false)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding movies: %s", err.Error())
|
||||
t.Errorf("Error finding groups: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Equal(t, movieNames[movieIdxWithScene], movie.Name)
|
||||
assert.Equal(t, groupNames[groupIdxWithScene], group.Name)
|
||||
|
||||
name = movieNames[movieIdxWithDupName] // find a movie by name nocase
|
||||
name = groupNames[groupIdxWithDupName] // find a group by name nocase
|
||||
|
||||
movie, err = mqb.FindByName(ctx, name, true)
|
||||
group, err = mqb.FindByName(ctx, name, true)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding movies: %s", err.Error())
|
||||
t.Errorf("Error finding groups: %s", err.Error())
|
||||
}
|
||||
// movieIdxWithDupName and movieIdxWithScene should have similar names ( only diff should be Name vs NaMe)
|
||||
//movie.Name should match with movieIdxWithScene since its ID is before moveIdxWithDupName
|
||||
assert.Equal(t, movieNames[movieIdxWithScene], movie.Name)
|
||||
//movie.Name should match with movieIdxWithDupName if the check is not case sensitive
|
||||
assert.Equal(t, strings.ToLower(movieNames[movieIdxWithDupName]), strings.ToLower(movie.Name))
|
||||
// groupIdxWithDupName and groupIdxWithScene should have similar names ( only diff should be Name vs NaMe)
|
||||
//group.Name should match with groupIdxWithScene since its ID is before moveIdxWithDupName
|
||||
assert.Equal(t, groupNames[groupIdxWithScene], group.Name)
|
||||
//group.Name should match with groupIdxWithDupName if the check is not case sensitive
|
||||
assert.Equal(t, strings.ToLower(groupNames[groupIdxWithDupName]), strings.ToLower(group.Name))
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestMovieFindByNames(t *testing.T) {
|
||||
func TestGroupFindByNames(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
var names []string
|
||||
|
||||
mqb := db.Movie
|
||||
mqb := db.Group
|
||||
|
||||
names = append(names, movieNames[movieIdxWithScene]) // find movies by names
|
||||
names = append(names, groupNames[groupIdxWithScene]) // find groups by names
|
||||
|
||||
movies, err := mqb.FindByNames(ctx, names, false)
|
||||
groups, err := mqb.FindByNames(ctx, names, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error finding movies: %s", err.Error())
|
||||
t.Errorf("Error finding groups: %s", err.Error())
|
||||
}
|
||||
assert.Len(t, movies, 1)
|
||||
assert.Equal(t, movieNames[movieIdxWithScene], movies[0].Name)
|
||||
assert.Len(t, groups, 1)
|
||||
assert.Equal(t, groupNames[groupIdxWithScene], groups[0].Name)
|
||||
|
||||
movies, err = mqb.FindByNames(ctx, names, true) // find movies by names nocase
|
||||
groups, err = mqb.FindByNames(ctx, names, true) // find groups by names nocase
|
||||
if err != nil {
|
||||
t.Errorf("Error finding movies: %s", err.Error())
|
||||
t.Errorf("Error finding groups: %s", err.Error())
|
||||
}
|
||||
assert.Len(t, movies, 2) // movieIdxWithScene and movieIdxWithDupName
|
||||
assert.Equal(t, strings.ToLower(movieNames[movieIdxWithScene]), strings.ToLower(movies[0].Name))
|
||||
assert.Equal(t, strings.ToLower(movieNames[movieIdxWithScene]), strings.ToLower(movies[1].Name))
|
||||
assert.Len(t, groups, 2) // groupIdxWithScene and groupIdxWithDupName
|
||||
assert.Equal(t, strings.ToLower(groupNames[groupIdxWithScene]), strings.ToLower(groups[0].Name))
|
||||
assert.Equal(t, strings.ToLower(groupNames[groupIdxWithScene]), strings.ToLower(groups[1].Name))
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func moviesToIDs(i []*models.Movie) []int {
|
||||
func groupsToIDs(i []*models.Group) []int {
|
||||
ret := make([]int, len(i))
|
||||
for i, v := range i {
|
||||
ret[i] = v.ID
|
||||
|
|
@ -429,7 +429,7 @@ func moviesToIDs(i []*models.Movie) []int {
|
|||
return ret
|
||||
}
|
||||
|
||||
func TestMovieQuery(t *testing.T) {
|
||||
func TestGroupQuery(t *testing.T) {
|
||||
var (
|
||||
frontImage = "front_image"
|
||||
backImage = "back_image"
|
||||
|
|
@ -438,7 +438,7 @@ func TestMovieQuery(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
findFilter *models.FindFilterType
|
||||
filter *models.MovieFilterType
|
||||
filter *models.GroupFilterType
|
||||
includeIdxs []int
|
||||
excludeIdxs []int
|
||||
wantErr bool
|
||||
|
|
@ -446,7 +446,7 @@ func TestMovieQuery(t *testing.T) {
|
|||
{
|
||||
"is missing front image",
|
||||
nil,
|
||||
&models.MovieFilterType{
|
||||
&models.GroupFilterType{
|
||||
IsMissing: &frontImage,
|
||||
},
|
||||
// just ensure that it doesn't error
|
||||
|
|
@ -457,7 +457,7 @@ func TestMovieQuery(t *testing.T) {
|
|||
{
|
||||
"is missing back image",
|
||||
nil,
|
||||
&models.MovieFilterType{
|
||||
&models.GroupFilterType{
|
||||
IsMissing: &backImage,
|
||||
},
|
||||
// just ensure that it doesn't error
|
||||
|
|
@ -471,13 +471,13 @@ func TestMovieQuery(t *testing.T) {
|
|||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||
assert := assert.New(t)
|
||||
|
||||
results, _, err := db.Movie.Query(ctx, tt.filter, tt.findFilter)
|
||||
results, _, err := db.Group.Query(ctx, tt.filter, tt.findFilter)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("MovieQueryBuilder.Query() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Errorf("GroupQueryBuilder.Query() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
ids := moviesToIDs(results)
|
||||
ids := groupsToIDs(results)
|
||||
include := indexesToIDs(performerIDs, tt.includeIdxs)
|
||||
exclude := indexesToIDs(performerIDs, tt.excludeIdxs)
|
||||
|
||||
|
|
@ -491,66 +491,66 @@ func TestMovieQuery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMovieQueryStudio(t *testing.T) {
|
||||
func TestGroupQueryStudio(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
mqb := db.Movie
|
||||
mqb := db.Group
|
||||
studioCriterion := models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(studioIDs[studioIdxWithMovie]),
|
||||
strconv.Itoa(studioIDs[studioIdxWithGroup]),
|
||||
},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
}
|
||||
|
||||
movieFilter := models.MovieFilterType{
|
||||
groupFilter := models.GroupFilterType{
|
||||
Studios: &studioCriterion,
|
||||
}
|
||||
|
||||
movies, _, err := mqb.Query(ctx, &movieFilter, nil)
|
||||
groups, _, err := mqb.Query(ctx, &groupFilter, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Error querying movie: %s", err.Error())
|
||||
t.Errorf("Error querying group: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Len(t, movies, 1)
|
||||
assert.Len(t, groups, 1)
|
||||
|
||||
// ensure id is correct
|
||||
assert.Equal(t, movieIDs[movieIdxWithStudio], movies[0].ID)
|
||||
assert.Equal(t, groupIDs[groupIdxWithStudio], groups[0].ID)
|
||||
|
||||
studioCriterion = models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(studioIDs[studioIdxWithMovie]),
|
||||
strconv.Itoa(studioIDs[studioIdxWithGroup]),
|
||||
},
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
}
|
||||
|
||||
q := getMovieStringValue(movieIdxWithStudio, titleField)
|
||||
q := getGroupStringValue(groupIdxWithStudio, titleField)
|
||||
findFilter := models.FindFilterType{
|
||||
Q: &q,
|
||||
}
|
||||
|
||||
movies, _, err = mqb.Query(ctx, &movieFilter, &findFilter)
|
||||
groups, _, err = mqb.Query(ctx, &groupFilter, &findFilter)
|
||||
if err != nil {
|
||||
t.Errorf("Error querying movie: %s", err.Error())
|
||||
t.Errorf("Error querying group: %s", err.Error())
|
||||
}
|
||||
assert.Len(t, movies, 0)
|
||||
assert.Len(t, groups, 0)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestMovieQueryURL(t *testing.T) {
|
||||
func TestGroupQueryURL(t *testing.T) {
|
||||
const sceneIdx = 1
|
||||
movieURL := getMovieStringValue(sceneIdx, urlField)
|
||||
groupURL := getGroupStringValue(sceneIdx, urlField)
|
||||
|
||||
urlCriterion := models.StringCriterionInput{
|
||||
Value: movieURL,
|
||||
Value: groupURL,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
}
|
||||
|
||||
filter := models.MovieFilterType{
|
||||
filter := models.GroupFilterType{
|
||||
URL: &urlCriterion,
|
||||
}
|
||||
|
||||
verifyFn := func(n *models.Movie) {
|
||||
verifyFn := func(n *models.Group) {
|
||||
t.Helper()
|
||||
|
||||
urls := n.URLs.List()
|
||||
|
|
@ -562,93 +562,93 @@ func TestMovieQueryURL(t *testing.T) {
|
|||
verifyString(t, url, urlCriterion)
|
||||
}
|
||||
|
||||
verifyMovieQuery(t, filter, verifyFn)
|
||||
verifyGroupQuery(t, filter, verifyFn)
|
||||
|
||||
urlCriterion.Modifier = models.CriterionModifierNotEquals
|
||||
verifyMovieQuery(t, filter, verifyFn)
|
||||
verifyGroupQuery(t, filter, verifyFn)
|
||||
|
||||
urlCriterion.Modifier = models.CriterionModifierMatchesRegex
|
||||
urlCriterion.Value = "movie_.*1_URL"
|
||||
verifyMovieQuery(t, filter, verifyFn)
|
||||
urlCriterion.Value = "group_.*1_URL"
|
||||
verifyGroupQuery(t, filter, verifyFn)
|
||||
|
||||
urlCriterion.Modifier = models.CriterionModifierNotMatchesRegex
|
||||
verifyMovieQuery(t, filter, verifyFn)
|
||||
verifyGroupQuery(t, filter, verifyFn)
|
||||
|
||||
urlCriterion.Modifier = models.CriterionModifierIsNull
|
||||
urlCriterion.Value = ""
|
||||
verifyMovieQuery(t, filter, verifyFn)
|
||||
verifyGroupQuery(t, filter, verifyFn)
|
||||
|
||||
urlCriterion.Modifier = models.CriterionModifierNotNull
|
||||
verifyMovieQuery(t, filter, verifyFn)
|
||||
verifyGroupQuery(t, filter, verifyFn)
|
||||
}
|
||||
|
||||
func TestMovieQueryURLExcludes(t *testing.T) {
|
||||
func TestGroupQueryURLExcludes(t *testing.T) {
|
||||
withRollbackTxn(func(ctx context.Context) error {
|
||||
mqb := db.Movie
|
||||
mqb := db.Group
|
||||
|
||||
// create movie with two URLs
|
||||
movie := models.Movie{
|
||||
Name: "TestMovieQueryURLExcludes",
|
||||
// create group with two URLs
|
||||
group := models.Group{
|
||||
Name: "TestGroupQueryURLExcludes",
|
||||
URLs: models.NewRelatedStrings([]string{
|
||||
"aaa",
|
||||
"bbb",
|
||||
}),
|
||||
}
|
||||
|
||||
err := mqb.Create(ctx, &movie)
|
||||
err := mqb.Create(ctx, &group)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating movie: %w", err)
|
||||
return fmt.Errorf("Error creating group: %w", err)
|
||||
}
|
||||
|
||||
// query for movies that exclude the URL "aaa"
|
||||
// query for groups that exclude the URL "aaa"
|
||||
urlCriterion := models.StringCriterionInput{
|
||||
Value: "aaa",
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
}
|
||||
|
||||
nameCriterion := models.StringCriterionInput{
|
||||
Value: movie.Name,
|
||||
Value: group.Name,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
}
|
||||
|
||||
filter := models.MovieFilterType{
|
||||
filter := models.GroupFilterType{
|
||||
URL: &urlCriterion,
|
||||
Name: &nameCriterion,
|
||||
}
|
||||
|
||||
movies := queryMovies(ctx, t, &filter, nil)
|
||||
assert.Len(t, movies, 0, "Expected no movies to be found")
|
||||
groups := queryGroups(ctx, t, &filter, nil)
|
||||
assert.Len(t, groups, 0, "Expected no groups to be found")
|
||||
|
||||
// query for movies that exclude the URL "ccc"
|
||||
// query for groups that exclude the URL "ccc"
|
||||
urlCriterion.Value = "ccc"
|
||||
movies = queryMovies(ctx, t, &filter, nil)
|
||||
groups = queryGroups(ctx, t, &filter, nil)
|
||||
|
||||
if assert.Len(t, movies, 1, "Expected one movie to be found") {
|
||||
assert.Equal(t, movie.Name, movies[0].Name)
|
||||
if assert.Len(t, groups, 1, "Expected one group to be found") {
|
||||
assert.Equal(t, group.Name, groups[0].Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func verifyMovieQuery(t *testing.T, filter models.MovieFilterType, verifyFn func(s *models.Movie)) {
|
||||
func verifyGroupQuery(t *testing.T, filter models.GroupFilterType, verifyFn func(s *models.Group)) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
t.Helper()
|
||||
sqb := db.Movie
|
||||
sqb := db.Group
|
||||
|
||||
movies := queryMovies(ctx, t, &filter, nil)
|
||||
groups := queryGroups(ctx, t, &filter, nil)
|
||||
|
||||
for _, movie := range movies {
|
||||
if err := movie.LoadURLs(ctx, sqb); err != nil {
|
||||
t.Errorf("Error loading movie relationships: %v", err)
|
||||
for _, group := range groups {
|
||||
if err := group.LoadURLs(ctx, sqb); err != nil {
|
||||
t.Errorf("Error loading group relationships: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// assume it should find at least one
|
||||
assert.Greater(t, len(movies), 0)
|
||||
assert.Greater(t, len(groups), 0)
|
||||
|
||||
for _, m := range movies {
|
||||
for _, m := range groups {
|
||||
verifyFn(m)
|
||||
}
|
||||
|
||||
|
|
@ -656,102 +656,102 @@ func verifyMovieQuery(t *testing.T, filter models.MovieFilterType, verifyFn func
|
|||
})
|
||||
}
|
||||
|
||||
func queryMovies(ctx context.Context, t *testing.T, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) []*models.Movie {
|
||||
sqb := db.Movie
|
||||
movies, _, err := sqb.Query(ctx, movieFilter, findFilter)
|
||||
func queryGroups(ctx context.Context, t *testing.T, groupFilter *models.GroupFilterType, findFilter *models.FindFilterType) []*models.Group {
|
||||
sqb := db.Group
|
||||
groups, _, err := sqb.Query(ctx, groupFilter, findFilter)
|
||||
if err != nil {
|
||||
t.Errorf("Error querying movie: %s", err.Error())
|
||||
t.Errorf("Error querying group: %s", err.Error())
|
||||
}
|
||||
|
||||
return movies
|
||||
return groups
|
||||
}
|
||||
|
||||
func TestMovieQueryTags(t *testing.T) {
|
||||
func TestGroupQueryTags(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
tagCriterion := models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(tagIDs[tagIdxWithMovie]),
|
||||
strconv.Itoa(tagIDs[tagIdx1WithMovie]),
|
||||
strconv.Itoa(tagIDs[tagIdxWithGroup]),
|
||||
strconv.Itoa(tagIDs[tagIdx1WithGroup]),
|
||||
},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
}
|
||||
|
||||
movieFilter := models.MovieFilterType{
|
||||
groupFilter := models.GroupFilterType{
|
||||
Tags: &tagCriterion,
|
||||
}
|
||||
|
||||
// ensure ids are correct
|
||||
movies := queryMovies(ctx, t, &movieFilter, nil)
|
||||
assert.Len(t, movies, 3)
|
||||
for _, movie := range movies {
|
||||
assert.True(t, movie.ID == movieIDs[movieIdxWithTag] || movie.ID == movieIDs[movieIdxWithTwoTags] || movie.ID == movieIDs[movieIdxWithThreeTags])
|
||||
groups := queryGroups(ctx, t, &groupFilter, nil)
|
||||
assert.Len(t, groups, 3)
|
||||
for _, group := range groups {
|
||||
assert.True(t, group.ID == groupIDs[groupIdxWithTag] || group.ID == groupIDs[groupIdxWithTwoTags] || group.ID == groupIDs[groupIdxWithThreeTags])
|
||||
}
|
||||
|
||||
tagCriterion = models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(tagIDs[tagIdx1WithMovie]),
|
||||
strconv.Itoa(tagIDs[tagIdx2WithMovie]),
|
||||
strconv.Itoa(tagIDs[tagIdx1WithGroup]),
|
||||
strconv.Itoa(tagIDs[tagIdx2WithGroup]),
|
||||
},
|
||||
Modifier: models.CriterionModifierIncludesAll,
|
||||
}
|
||||
|
||||
movies = queryMovies(ctx, t, &movieFilter, nil)
|
||||
groups = queryGroups(ctx, t, &groupFilter, nil)
|
||||
|
||||
if assert.Len(t, movies, 2) {
|
||||
assert.Equal(t, sceneIDs[movieIdxWithTwoTags], movies[0].ID)
|
||||
assert.Equal(t, sceneIDs[movieIdxWithThreeTags], movies[1].ID)
|
||||
if assert.Len(t, groups, 2) {
|
||||
assert.Equal(t, sceneIDs[groupIdxWithTwoTags], groups[0].ID)
|
||||
assert.Equal(t, sceneIDs[groupIdxWithThreeTags], groups[1].ID)
|
||||
}
|
||||
|
||||
tagCriterion = models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(tagIDs[tagIdx1WithMovie]),
|
||||
strconv.Itoa(tagIDs[tagIdx1WithGroup]),
|
||||
},
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
}
|
||||
|
||||
q := getSceneStringValue(movieIdxWithTwoTags, titleField)
|
||||
q := getSceneStringValue(groupIdxWithTwoTags, titleField)
|
||||
findFilter := models.FindFilterType{
|
||||
Q: &q,
|
||||
}
|
||||
|
||||
movies = queryMovies(ctx, t, &movieFilter, &findFilter)
|
||||
assert.Len(t, movies, 0)
|
||||
groups = queryGroups(ctx, t, &groupFilter, &findFilter)
|
||||
assert.Len(t, groups, 0)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestMovieQueryTagCount(t *testing.T) {
|
||||
func TestGroupQueryTagCount(t *testing.T) {
|
||||
const tagCount = 1
|
||||
tagCountCriterion := models.IntCriterionInput{
|
||||
Value: tagCount,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
}
|
||||
|
||||
verifyMoviesTagCount(t, tagCountCriterion)
|
||||
verifyGroupsTagCount(t, tagCountCriterion)
|
||||
|
||||
tagCountCriterion.Modifier = models.CriterionModifierNotEquals
|
||||
verifyMoviesTagCount(t, tagCountCriterion)
|
||||
verifyGroupsTagCount(t, tagCountCriterion)
|
||||
|
||||
tagCountCriterion.Modifier = models.CriterionModifierGreaterThan
|
||||
verifyMoviesTagCount(t, tagCountCriterion)
|
||||
verifyGroupsTagCount(t, tagCountCriterion)
|
||||
|
||||
tagCountCriterion.Modifier = models.CriterionModifierLessThan
|
||||
verifyMoviesTagCount(t, tagCountCriterion)
|
||||
verifyGroupsTagCount(t, tagCountCriterion)
|
||||
}
|
||||
|
||||
func verifyMoviesTagCount(t *testing.T, tagCountCriterion models.IntCriterionInput) {
|
||||
func verifyGroupsTagCount(t *testing.T, tagCountCriterion models.IntCriterionInput) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
sqb := db.Movie
|
||||
movieFilter := models.MovieFilterType{
|
||||
sqb := db.Group
|
||||
groupFilter := models.GroupFilterType{
|
||||
TagCount: &tagCountCriterion,
|
||||
}
|
||||
|
||||
movies := queryMovies(ctx, t, &movieFilter, nil)
|
||||
assert.Greater(t, len(movies), 0)
|
||||
groups := queryGroups(ctx, t, &groupFilter, nil)
|
||||
assert.Greater(t, len(groups), 0)
|
||||
|
||||
for _, movie := range movies {
|
||||
ids, err := sqb.GetTagIDs(ctx, movie.ID)
|
||||
for _, group := range groups {
|
||||
ids, err := sqb.GetTagIDs(ctx, group.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -762,7 +762,7 @@ func verifyMoviesTagCount(t *testing.T, tagCountCriterion models.IntCriterionInp
|
|||
})
|
||||
}
|
||||
|
||||
func TestMovieQuerySorting(t *testing.T) {
|
||||
func TestGroupQuerySorting(t *testing.T) {
|
||||
sort := "scenes_count"
|
||||
direction := models.SortDirectionEnumDesc
|
||||
findFilter := models.FindFilterType{
|
||||
|
|
@ -771,60 +771,60 @@ func TestMovieQuerySorting(t *testing.T) {
|
|||
}
|
||||
|
||||
withTxn(func(ctx context.Context) error {
|
||||
movies := queryMovies(ctx, t, nil, &findFilter)
|
||||
groups := queryGroups(ctx, t, nil, &findFilter)
|
||||
|
||||
// scenes should be in same order as indexes
|
||||
firstMovie := movies[0]
|
||||
firstGroup := groups[0]
|
||||
|
||||
assert.Equal(t, movieIDs[movieIdxWithScene], firstMovie.ID)
|
||||
assert.Equal(t, groupIDs[groupIdxWithScene], firstGroup.ID)
|
||||
|
||||
// sort in descending order
|
||||
direction = models.SortDirectionEnumAsc
|
||||
|
||||
movies = queryMovies(ctx, t, nil, &findFilter)
|
||||
lastMovie := movies[len(movies)-1]
|
||||
groups = queryGroups(ctx, t, nil, &findFilter)
|
||||
lastGroup := groups[len(groups)-1]
|
||||
|
||||
assert.Equal(t, movieIDs[movieIdxWithScene], lastMovie.ID)
|
||||
assert.Equal(t, groupIDs[groupIdxWithScene], lastGroup.ID)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestMovieUpdateFrontImage(t *testing.T) {
|
||||
func TestGroupUpdateFrontImage(t *testing.T) {
|
||||
if err := withRollbackTxn(func(ctx context.Context) error {
|
||||
qb := db.Movie
|
||||
qb := db.Group
|
||||
|
||||
// create movie to test against
|
||||
const name = "TestMovieUpdateMovieImages"
|
||||
movie := models.Movie{
|
||||
// create group to test against
|
||||
const name = "TestGroupUpdateGroupImages"
|
||||
group := models.Group{
|
||||
Name: name,
|
||||
}
|
||||
err := qb.Create(ctx, &movie)
|
||||
err := qb.Create(ctx, &group)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating movie: %s", err.Error())
|
||||
return fmt.Errorf("Error creating group: %s", err.Error())
|
||||
}
|
||||
|
||||
return testUpdateImage(t, ctx, movie.ID, qb.UpdateFrontImage, qb.GetFrontImage)
|
||||
return testUpdateImage(t, ctx, group.ID, qb.UpdateFrontImage, qb.GetFrontImage)
|
||||
}); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMovieUpdateBackImage(t *testing.T) {
|
||||
func TestGroupUpdateBackImage(t *testing.T) {
|
||||
if err := withRollbackTxn(func(ctx context.Context) error {
|
||||
qb := db.Movie
|
||||
qb := db.Group
|
||||
|
||||
// create movie to test against
|
||||
const name = "TestMovieUpdateMovieImages"
|
||||
movie := models.Movie{
|
||||
// create group to test against
|
||||
const name = "TestGroupUpdateGroupImages"
|
||||
group := models.Group{
|
||||
Name: name,
|
||||
}
|
||||
err := qb.Create(ctx, &movie)
|
||||
err := qb.Create(ctx, &group)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating movie: %s", err.Error())
|
||||
return fmt.Errorf("Error creating group: %s", err.Error())
|
||||
}
|
||||
|
||||
return testUpdateImage(t, ctx, movie.ID, qb.UpdateBackImage, qb.GetBackImage)
|
||||
return testUpdateImage(t, ctx, group.ID, qb.UpdateBackImage, qb.GetBackImage)
|
||||
}); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const (
|
|||
performersScenesTable = "performers_scenes"
|
||||
scenesTagsTable = "scenes_tags"
|
||||
scenesGalleriesTable = "scenes_galleries"
|
||||
moviesScenesTable = "movies_scenes"
|
||||
groupsScenesTable = "movies_scenes"
|
||||
scenesURLsTable = "scene_urls"
|
||||
sceneURLColumn = "url"
|
||||
scenesViewDatesTable = "scenes_view_dates"
|
||||
|
|
@ -173,7 +173,7 @@ type sceneRepositoryType struct {
|
|||
galleries joinRepository
|
||||
tags joinRepository
|
||||
performers joinRepository
|
||||
movies repository
|
||||
groups repository
|
||||
|
||||
files filesRepository
|
||||
|
||||
|
|
@ -209,8 +209,8 @@ var (
|
|||
},
|
||||
fkColumn: performerIDColumn,
|
||||
},
|
||||
movies: repository{
|
||||
tableName: moviesScenesTable,
|
||||
groups: repository{
|
||||
tableName: groupsScenesTable,
|
||||
idColumn: sceneIDColumn,
|
||||
},
|
||||
files: filesRepository{
|
||||
|
|
@ -343,8 +343,8 @@ func (qb *SceneStore) Create(ctx context.Context, newObject *models.Scene, fileI
|
|||
}
|
||||
}
|
||||
|
||||
if newObject.Movies.Loaded() {
|
||||
if err := scenesMoviesTableMgr.insertJoins(ctx, id, newObject.Movies.List()); err != nil {
|
||||
if newObject.Groups.Loaded() {
|
||||
if err := scenesGroupsTableMgr.insertJoins(ctx, id, newObject.Groups.List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -399,8 +399,8 @@ func (qb *SceneStore) UpdatePartial(ctx context.Context, id int, partial models.
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
if partial.MovieIDs != nil {
|
||||
if err := scenesMoviesTableMgr.modifyJoins(ctx, id, partial.MovieIDs.Movies, partial.MovieIDs.Mode); err != nil {
|
||||
if partial.GroupIDs != nil {
|
||||
if err := scenesGroupsTableMgr.modifyJoins(ctx, id, partial.GroupIDs.Groups, partial.GroupIDs.Mode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
@ -451,8 +451,8 @@ func (qb *SceneStore) Update(ctx context.Context, updatedObject *models.Scene) e
|
|||
}
|
||||
}
|
||||
|
||||
if updatedObject.Movies.Loaded() {
|
||||
if err := scenesMoviesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.Movies.List()); err != nil {
|
||||
if updatedObject.Groups.Loaded() {
|
||||
if err := scenesGroupsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.Groups.List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -778,23 +778,23 @@ func (qb *SceneStore) OCountByPerformerID(ctx context.Context, performerID int)
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *SceneStore) FindByMovieID(ctx context.Context, movieID int) ([]*models.Scene, error) {
|
||||
sq := dialect.From(scenesMoviesJoinTable).Select(scenesMoviesJoinTable.Col(sceneIDColumn)).Where(
|
||||
scenesMoviesJoinTable.Col(movieIDColumn).Eq(movieID),
|
||||
func (qb *SceneStore) FindByGroupID(ctx context.Context, groupID int) ([]*models.Scene, error) {
|
||||
sq := dialect.From(scenesGroupsJoinTable).Select(scenesGroupsJoinTable.Col(sceneIDColumn)).Where(
|
||||
scenesGroupsJoinTable.Col(groupIDColumn).Eq(groupID),
|
||||
)
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting scenes for movie %d: %w", movieID, err)
|
||||
return nil, fmt.Errorf("getting scenes for group %d: %w", groupID, err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *SceneStore) CountByMovieID(ctx context.Context, movieID int) (int, error) {
|
||||
joinTable := scenesMoviesJoinTable
|
||||
func (qb *SceneStore) CountByGroupID(ctx context.Context, groupID int) (int, error) {
|
||||
joinTable := scenesGroupsJoinTable
|
||||
|
||||
q := dialect.Select(goqu.COUNT("*")).From(joinTable).Where(joinTable.Col(movieIDColumn).Eq(movieID))
|
||||
q := dialect.Select(goqu.COUNT("*")).From(joinTable).Where(joinTable.Col(groupIDColumn).Eq(groupID))
|
||||
return count(ctx, q)
|
||||
}
|
||||
|
||||
|
|
@ -1142,8 +1142,8 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
|
|||
direction := findFilter.GetDirection()
|
||||
switch sort {
|
||||
case "movie_scene_number", "group_scene_number":
|
||||
query.join(moviesScenesTable, "", "scenes.id = movies_scenes.scene_id")
|
||||
query.sortAndPagination += getSort("scene_index", direction, moviesScenesTable)
|
||||
query.join(groupsScenesTable, "", "scenes.id = movies_scenes.scene_id")
|
||||
query.sortAndPagination += getSort("scene_index", direction, groupsScenesTable)
|
||||
case "tag_count":
|
||||
query.sortAndPagination += getCountSort(sceneTable, scenesTagsTable, sceneIDColumn, direction)
|
||||
case "performer_count":
|
||||
|
|
@ -1270,11 +1270,11 @@ func (qb *SceneStore) AssignFiles(ctx context.Context, sceneID int, fileIDs []mo
|
|||
return scenesFilesTableMgr.insertJoins(ctx, sceneID, firstPrimary, fileIDs)
|
||||
}
|
||||
|
||||
func (qb *SceneStore) GetMovies(ctx context.Context, id int) (ret []models.MoviesScenes, err error) {
|
||||
ret = []models.MoviesScenes{}
|
||||
func (qb *SceneStore) GetGroups(ctx context.Context, id int) (ret []models.GroupsScenes, err error) {
|
||||
ret = []models.GroupsScenes{}
|
||||
|
||||
if err := sceneRepository.movies.getAll(ctx, id, func(rows *sqlx.Rows) error {
|
||||
var ms moviesScenesRow
|
||||
if err := sceneRepository.groups.getAll(ctx, id, func(rows *sqlx.Rows) error {
|
||||
var ms groupsScenesRow
|
||||
if err := rows.StructScan(&ms); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,10 +195,10 @@ func (qb *sceneFilterHandler) criterionHandler() criterionHandler {
|
|||
|
||||
&relatedFilterHandler{
|
||||
relatedIDCol: "movies_scenes.movie_id",
|
||||
relatedRepo: movieRepository.repository,
|
||||
relatedHandler: &movieFilterHandler{sceneFilter.MoviesFilter},
|
||||
relatedRepo: groupRepository.repository,
|
||||
relatedHandler: &groupFilterHandler{sceneFilter.MoviesFilter},
|
||||
joinFn: func(f *filterBuilder) {
|
||||
sceneRepository.movies.innerJoin(f, "", "scenes.id")
|
||||
sceneRepository.groups.innerJoin(f, "", "scenes.id")
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ func (qb *sceneFilterHandler) isMissingCriterionHandler(isMissing *string) crite
|
|||
case "studio":
|
||||
f.addWhere("scenes.studio_id IS NULL")
|
||||
case "movie":
|
||||
sceneRepository.movies.join(f, "movies_join", "scenes.id")
|
||||
sceneRepository.groups.join(f, "movies_join", "scenes.id")
|
||||
f.addWhere("movies_join.scene_id IS NULL")
|
||||
case "performers":
|
||||
sceneRepository.performers.join(f, "performers_join", "scenes.id")
|
||||
|
|
@ -485,10 +485,10 @@ func (qb *sceneFilterHandler) performerAgeCriterionHandler(performerAge *models.
|
|||
|
||||
func (qb *sceneFilterHandler) groupsCriterionHandler(movies *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
addJoinsFunc := func(f *filterBuilder) {
|
||||
sceneRepository.movies.join(f, "", "scenes.id")
|
||||
sceneRepository.groups.join(f, "", "scenes.id")
|
||||
f.addLeftJoin("movies", "", "movies_scenes.movie_id = movies.id")
|
||||
}
|
||||
h := qb.getMultiCriterionHandlerBuilder(movieTable, moviesScenesTable, "movie_id", addJoinsFunc)
|
||||
h := qb.getMultiCriterionHandlerBuilder(groupTable, groupsScenesTable, "movie_id", addJoinsFunc)
|
||||
return h.handler(movies)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ func loadSceneRelationships(ctx context.Context, expected models.Scene, actual *
|
|||
return err
|
||||
}
|
||||
}
|
||||
if expected.Movies.Loaded() {
|
||||
if err := actual.LoadMovies(ctx, db.Scene); err != nil {
|
||||
if expected.Groups.Loaded() {
|
||||
if err := actual.LoadGroups(ctx, db.Scene); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -120,13 +120,13 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
|
|||
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
||||
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
}),
|
||||
|
|
@ -165,13 +165,13 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
|
|||
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
||||
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
}),
|
||||
|
|
@ -219,11 +219,11 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
|
|||
true,
|
||||
},
|
||||
{
|
||||
"invalid movie id",
|
||||
"invalid group id",
|
||||
models.Scene{
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: invalidID,
|
||||
GroupID: invalidID,
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
}),
|
||||
|
|
@ -349,13 +349,13 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
|
|||
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
||||
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
}),
|
||||
|
|
@ -381,7 +381,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
|
|||
GalleryIDs: models.NewRelatedIDs([]int{}),
|
||||
TagIDs: models.NewRelatedIDs([]int{}),
|
||||
PerformerIDs: models.NewRelatedIDs([]int{}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{}),
|
||||
StashIDs: models.NewRelatedStashIDs([]models.StashID{}),
|
||||
},
|
||||
false,
|
||||
|
|
@ -411,10 +411,10 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"clear movies",
|
||||
"clear groups",
|
||||
&models.Scene{
|
||||
ID: sceneIDs[sceneIdxWithMovie],
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
|
||||
ID: sceneIDs[sceneIdxWithGroup],
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{}),
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
|
@ -451,12 +451,12 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
|
|||
true,
|
||||
},
|
||||
{
|
||||
"invalid movie id",
|
||||
"invalid group id",
|
||||
&models.Scene{
|
||||
ID: sceneIDs[sceneIdxWithSpacedName],
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: invalidID,
|
||||
GroupID: invalidID,
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
}),
|
||||
|
|
@ -573,14 +573,14 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
IDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
},
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: []models.MoviesScenes{
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: []models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
},
|
||||
|
|
@ -621,13 +621,13 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
|
||||
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
||||
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
}),
|
||||
|
|
@ -658,7 +658,7 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
|
|||
GalleryIDs: models.NewRelatedIDs([]int{}),
|
||||
TagIDs: models.NewRelatedIDs([]int{}),
|
||||
PerformerIDs: models.NewRelatedIDs([]int{}),
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{}),
|
||||
StashIDs: models.NewRelatedStashIDs([]models.StashID{}),
|
||||
PlayDuration: getScenePlayDuration(sceneIdxWithSpacedName),
|
||||
ResumeTime: getSceneResumeTime(sceneIdxWithSpacedName),
|
||||
|
|
@ -727,13 +727,13 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
stashID1 = "stashid1"
|
||||
stashID2 = "stashid2"
|
||||
|
||||
movieScenes = []models.MoviesScenes{
|
||||
groupScenes = []models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithDupName],
|
||||
GroupID: groupIDs[groupIdxWithDupName],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
}
|
||||
|
|
@ -863,40 +863,40 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"add movies",
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
"add groups",
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
models.ScenePartial{
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: movieScenes,
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: groupScenes,
|
||||
Mode: models.RelationshipUpdateModeAdd,
|
||||
},
|
||||
},
|
||||
models.Scene{
|
||||
Movies: models.NewRelatedMovies(append([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups(append([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: indexesToIDs(movieIDs, sceneMovies[sceneIdxWithMovie])[0],
|
||||
GroupID: indexesToIDs(groupIDs, sceneGroups[sceneIdxWithGroup])[0],
|
||||
},
|
||||
}, movieScenes...)),
|
||||
}, groupScenes...)),
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"add movies to empty",
|
||||
"add groups to empty",
|
||||
sceneIDs[sceneIdx1WithPerformer],
|
||||
models.ScenePartial{
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: movieScenes,
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: groupScenes,
|
||||
Mode: models.RelationshipUpdateModeAdd,
|
||||
},
|
||||
},
|
||||
models.Scene{
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithDupName],
|
||||
GroupID: groupIDs[groupIdxWithDupName],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithStudio],
|
||||
GroupID: groupIDs[groupIdxWithStudio],
|
||||
SceneIndex: &sceneIndex2,
|
||||
},
|
||||
}),
|
||||
|
|
@ -967,27 +967,27 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"add duplicate movies",
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
"add duplicate groups",
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
models.ScenePartial{
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: append([]models.MoviesScenes{
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: append([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
SceneIndex: &sceneIndex,
|
||||
},
|
||||
},
|
||||
movieScenes...,
|
||||
groupScenes...,
|
||||
),
|
||||
Mode: models.RelationshipUpdateModeAdd,
|
||||
},
|
||||
},
|
||||
models.Scene{
|
||||
Movies: models.NewRelatedMovies(append([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups(append([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: indexesToIDs(movieIDs, sceneMovies[sceneIdxWithMovie])[0],
|
||||
GroupID: indexesToIDs(groupIDs, sceneGroups[sceneIdxWithGroup])[0],
|
||||
},
|
||||
}, movieScenes...)),
|
||||
}, groupScenes...)),
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
|
@ -1044,13 +1044,13 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
true,
|
||||
},
|
||||
{
|
||||
"add invalid movies",
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
"add invalid groups",
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
models.ScenePartial{
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: []models.MoviesScenes{
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: []models.GroupsScenes{
|
||||
{
|
||||
MovieID: invalidID,
|
||||
GroupID: invalidID,
|
||||
},
|
||||
},
|
||||
Mode: models.RelationshipUpdateModeAdd,
|
||||
|
|
@ -1102,20 +1102,20 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"remove movies",
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
"remove groups",
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
models.ScenePartial{
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: []models.MoviesScenes{
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: []models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithScene],
|
||||
GroupID: groupIDs[groupIdxWithScene],
|
||||
},
|
||||
},
|
||||
Mode: models.RelationshipUpdateModeRemove,
|
||||
},
|
||||
},
|
||||
models.Scene{
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{}),
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
|
@ -1176,22 +1176,22 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"remove unrelated movies",
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
"remove unrelated groups",
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
models.ScenePartial{
|
||||
MovieIDs: &models.UpdateMovieIDs{
|
||||
Movies: []models.MoviesScenes{
|
||||
GroupIDs: &models.UpdateGroupIDs{
|
||||
Groups: []models.GroupsScenes{
|
||||
{
|
||||
MovieID: movieIDs[movieIdxWithDupName],
|
||||
GroupID: groupIDs[groupIdxWithDupName],
|
||||
},
|
||||
},
|
||||
Mode: models.RelationshipUpdateModeRemove,
|
||||
},
|
||||
},
|
||||
models.Scene{
|
||||
Movies: models.NewRelatedMovies([]models.MoviesScenes{
|
||||
Groups: models.NewRelatedGroups([]models.GroupsScenes{
|
||||
{
|
||||
MovieID: indexesToIDs(movieIDs, sceneMovies[sceneIdxWithMovie])[0],
|
||||
GroupID: indexesToIDs(groupIDs, sceneGroups[sceneIdxWithGroup])[0],
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
|
@ -1257,9 +1257,9 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|||
assert.ElementsMatch(tt.want.GalleryIDs.List(), got.GalleryIDs.List())
|
||||
assert.ElementsMatch(tt.want.GalleryIDs.List(), s.GalleryIDs.List())
|
||||
}
|
||||
if tt.partial.MovieIDs != nil {
|
||||
assert.ElementsMatch(tt.want.Movies.List(), got.Movies.List())
|
||||
assert.ElementsMatch(tt.want.Movies.List(), s.Movies.List())
|
||||
if tt.partial.GroupIDs != nil {
|
||||
assert.ElementsMatch(tt.want.Groups.List(), got.Groups.List())
|
||||
assert.ElementsMatch(tt.want.Groups.List(), s.Groups.List())
|
||||
}
|
||||
if tt.partial.StashIDs != nil {
|
||||
assert.ElementsMatch(tt.want.StashIDs.List(), got.StashIDs.List())
|
||||
|
|
@ -1467,9 +1467,9 @@ func Test_sceneQueryBuilder_Find(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"with movies",
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
makeSceneWithID(sceneIdxWithMovie),
|
||||
"with groups",
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
makeSceneWithID(sceneIdxWithGroup),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
|
@ -1527,13 +1527,13 @@ func Test_sceneQueryBuilder_FindMany(t *testing.T) {
|
|||
sceneIDs[sceneIdxWithGallery],
|
||||
sceneIDs[sceneIdxWithTwoPerformers],
|
||||
sceneIDs[sceneIdxWithTwoTags],
|
||||
sceneIDs[sceneIdxWithMovie],
|
||||
sceneIDs[sceneIdxWithGroup],
|
||||
},
|
||||
[]*models.Scene{
|
||||
makeSceneWithID(sceneIdxWithGallery),
|
||||
makeSceneWithID(sceneIdxWithTwoPerformers),
|
||||
makeSceneWithID(sceneIdxWithTwoTags),
|
||||
makeSceneWithID(sceneIdxWithMovie),
|
||||
makeSceneWithID(sceneIdxWithGroup),
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
|
@ -1608,9 +1608,9 @@ func Test_sceneQueryBuilder_FindByChecksum(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"with movies",
|
||||
getChecksum(sceneIdxWithMovie),
|
||||
[]*models.Scene{makeSceneWithID(sceneIdxWithMovie)},
|
||||
"with groups",
|
||||
getChecksum(sceneIdxWithGroup),
|
||||
[]*models.Scene{makeSceneWithID(sceneIdxWithGroup)},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
|
@ -1678,9 +1678,9 @@ func Test_sceneQueryBuilder_FindByOSHash(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"with movies",
|
||||
getOSHash(sceneIdxWithMovie),
|
||||
[]*models.Scene{makeSceneWithID(sceneIdxWithMovie)},
|
||||
"with groups",
|
||||
getOSHash(sceneIdxWithGroup),
|
||||
[]*models.Scene{makeSceneWithID(sceneIdxWithGroup)},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
|
@ -1749,9 +1749,9 @@ func Test_sceneQueryBuilder_FindByPath(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
"with movies",
|
||||
getPath(sceneIdxWithMovie),
|
||||
[]*models.Scene{makeSceneWithID(sceneIdxWithMovie)},
|
||||
"with groups",
|
||||
getPath(sceneIdxWithGroup),
|
||||
[]*models.Scene{makeSceneWithID(sceneIdxWithGroup)},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
|
@ -2107,7 +2107,7 @@ func TestSceneQuery(t *testing.T) {
|
|||
},
|
||||
},
|
||||
[]int{sceneIdxWithGallery},
|
||||
[]int{sceneIdxWithMovie},
|
||||
[]int{sceneIdxWithGroup},
|
||||
false,
|
||||
},
|
||||
{
|
||||
|
|
@ -2120,7 +2120,7 @@ func TestSceneQuery(t *testing.T) {
|
|||
},
|
||||
},
|
||||
[]int{sceneIdxWithGallery},
|
||||
[]int{sceneIdxWithMovie},
|
||||
[]int{sceneIdxWithGroup},
|
||||
false,
|
||||
},
|
||||
// {
|
||||
|
|
@ -2133,7 +2133,7 @@ func TestSceneQuery(t *testing.T) {
|
|||
// },
|
||||
// },
|
||||
// []int{sceneIdxWithGallery},
|
||||
// []int{sceneIdxWithMovie},
|
||||
// []int{sceneIdxWithGroup},
|
||||
// false,
|
||||
// },
|
||||
{
|
||||
|
|
@ -3108,7 +3108,7 @@ func TestSceneQueryIsMissingMovies(t *testing.T) {
|
|||
IsMissing: &isMissing,
|
||||
}
|
||||
|
||||
q := getSceneStringValue(sceneIdxWithMovie, titleField)
|
||||
q := getSceneStringValue(sceneIdxWithGroup, titleField)
|
||||
findFilter := models.FindFilterType{
|
||||
Q: &q,
|
||||
}
|
||||
|
|
@ -3122,7 +3122,7 @@ func TestSceneQueryIsMissingMovies(t *testing.T) {
|
|||
|
||||
// ensure non of the ids equal the one with movies
|
||||
for _, scene := range scenes {
|
||||
assert.NotEqual(t, sceneIDs[sceneIdxWithMovie], scene.ID)
|
||||
assert.NotEqual(t, sceneIDs[sceneIdxWithGroup], scene.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -3878,7 +3878,7 @@ func TestSceneQueryMovies(t *testing.T) {
|
|||
sqb := db.Scene
|
||||
movieCriterion := models.MultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(movieIDs[movieIdxWithScene]),
|
||||
strconv.Itoa(groupIDs[groupIdxWithScene]),
|
||||
},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
}
|
||||
|
|
@ -3892,16 +3892,16 @@ func TestSceneQueryMovies(t *testing.T) {
|
|||
assert.Len(t, scenes, 1)
|
||||
|
||||
// ensure id is correct
|
||||
assert.Equal(t, sceneIDs[sceneIdxWithMovie], scenes[0].ID)
|
||||
assert.Equal(t, sceneIDs[sceneIdxWithGroup], scenes[0].ID)
|
||||
|
||||
movieCriterion = models.MultiCriterionInput{
|
||||
Value: []string{
|
||||
strconv.Itoa(movieIDs[movieIdxWithScene]),
|
||||
strconv.Itoa(groupIDs[groupIdxWithScene]),
|
||||
},
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
}
|
||||
|
||||
q := getSceneStringValue(sceneIdxWithMovie, titleField)
|
||||
q := getSceneStringValue(sceneIdxWithGroup, titleField)
|
||||
findFilter := models.FindFilterType{
|
||||
Q: &q,
|
||||
}
|
||||
|
|
@ -4212,22 +4212,22 @@ func TestSceneCountByTagID(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestSceneCountByMovieID(t *testing.T) {
|
||||
func TestSceneCountByGroupID(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
sqb := db.Scene
|
||||
|
||||
sceneCount, err := sqb.CountByMovieID(ctx, movieIDs[movieIdxWithScene])
|
||||
sceneCount, err := sqb.CountByGroupID(ctx, groupIDs[groupIdxWithScene])
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error calling CountByMovieID: %s", err.Error())
|
||||
t.Errorf("error calling CountByGroupID: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Equal(t, 1, sceneCount)
|
||||
|
||||
sceneCount, err = sqb.CountByMovieID(ctx, 0)
|
||||
sceneCount, err = sqb.CountByGroupID(ctx, 0)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error calling CountByMovieID: %s", err.Error())
|
||||
t.Errorf("error calling CountByGroupID: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Equal(t, 0, sceneCount)
|
||||
|
|
@ -4264,16 +4264,16 @@ func TestFindByMovieID(t *testing.T) {
|
|||
withTxn(func(ctx context.Context) error {
|
||||
sqb := db.Scene
|
||||
|
||||
scenes, err := sqb.FindByMovieID(ctx, movieIDs[movieIdxWithScene])
|
||||
scenes, err := sqb.FindByGroupID(ctx, groupIDs[groupIdxWithScene])
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error calling FindByMovieID: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Len(t, scenes, 1)
|
||||
assert.Equal(t, sceneIDs[sceneIdxWithMovie], scenes[0].ID)
|
||||
assert.Equal(t, sceneIDs[sceneIdxWithGroup], scenes[0].ID)
|
||||
|
||||
scenes, err = sqb.FindByMovieID(ctx, 0)
|
||||
scenes, err = sqb.FindByGroupID(ctx, 0)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error calling FindByMovieID: %s", err.Error())
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
sceneIdxWithMovie = iota
|
||||
sceneIdxWithGroup = iota
|
||||
sceneIdxWithGallery
|
||||
sceneIdxWithPerformer
|
||||
sceneIdx1WithPerformer
|
||||
|
|
@ -148,17 +148,17 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
movieIdxWithScene = iota
|
||||
movieIdxWithStudio
|
||||
movieIdxWithTag
|
||||
movieIdxWithTwoTags
|
||||
movieIdxWithThreeTags
|
||||
// movies with dup names start from the end
|
||||
// create 7 more basic movies (can remove this if we add more indexes)
|
||||
movieIdxWithDupName = movieIdxWithStudio + 7
|
||||
groupIdxWithScene = iota
|
||||
groupIdxWithStudio
|
||||
groupIdxWithTag
|
||||
groupIdxWithTwoTags
|
||||
groupIdxWithThreeTags
|
||||
// groups with dup names start from the end
|
||||
// create 7 more basic groups (can remove this if we add more indexes)
|
||||
groupIdxWithDupName = groupIdxWithStudio + 7
|
||||
|
||||
moviesNameCase = movieIdxWithDupName
|
||||
moviesNameNoCase = 1
|
||||
groupsNameCase = groupIdxWithDupName
|
||||
groupsNameNoCase = 1
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -220,10 +220,10 @@ const (
|
|||
tagIdxWithParentAndChild
|
||||
tagIdxWithGrandParent
|
||||
tagIdx2WithMarkers
|
||||
tagIdxWithMovie
|
||||
tagIdx1WithMovie
|
||||
tagIdx2WithMovie
|
||||
tagIdx3WithMovie
|
||||
tagIdxWithGroup
|
||||
tagIdx1WithGroup
|
||||
tagIdx2WithGroup
|
||||
tagIdx3WithGroup
|
||||
// new indexes above
|
||||
// tags with dup names start from the end
|
||||
tagIdx1WithDupName
|
||||
|
|
@ -238,7 +238,7 @@ const (
|
|||
const (
|
||||
studioIdxWithScene = iota
|
||||
studioIdxWithTwoScenes
|
||||
studioIdxWithMovie
|
||||
studioIdxWithGroup
|
||||
studioIdxWithChildStudio
|
||||
studioIdxWithParentStudio
|
||||
studioIdxWithImage
|
||||
|
|
@ -305,7 +305,7 @@ var (
|
|||
sceneIDs []int
|
||||
imageIDs []int
|
||||
performerIDs []int
|
||||
movieIDs []int
|
||||
groupIDs []int
|
||||
galleryIDs []int
|
||||
tagIDs []int
|
||||
studioIDs []int
|
||||
|
|
@ -316,7 +316,7 @@ var (
|
|||
|
||||
tagNames []string
|
||||
studioNames []string
|
||||
movieNames []string
|
||||
groupNames []string
|
||||
performerNames []string
|
||||
)
|
||||
|
||||
|
|
@ -389,8 +389,8 @@ var (
|
|||
sceneIdxWithGallery: {galleryIdxWithScene},
|
||||
}
|
||||
|
||||
sceneMovies = linkMap{
|
||||
sceneIdxWithMovie: {movieIdxWithScene},
|
||||
sceneGroups = linkMap{
|
||||
sceneIdxWithGroup: {groupIdxWithScene},
|
||||
}
|
||||
|
||||
sceneStudios = map[int]int{
|
||||
|
|
@ -496,14 +496,14 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
movieStudioLinks = [][2]int{
|
||||
{movieIdxWithStudio, studioIdxWithMovie},
|
||||
groupStudioLinks = [][2]int{
|
||||
{groupIdxWithStudio, studioIdxWithGroup},
|
||||
}
|
||||
|
||||
movieTags = linkMap{
|
||||
movieIdxWithTag: {tagIdxWithMovie},
|
||||
movieIdxWithTwoTags: {tagIdx1WithMovie, tagIdx2WithMovie},
|
||||
movieIdxWithThreeTags: {tagIdx1WithMovie, tagIdx2WithMovie, tagIdx3WithMovie},
|
||||
groupTags = linkMap{
|
||||
groupIdxWithTag: {tagIdxWithGroup},
|
||||
groupIdxWithTwoTags: {tagIdx1WithGroup, tagIdx2WithGroup},
|
||||
groupIdxWithThreeTags: {tagIdx1WithGroup, tagIdx2WithGroup, tagIdx3WithGroup},
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -653,8 +653,8 @@ func populateDB() error {
|
|||
return fmt.Errorf("error creating tags: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := createMovies(ctx, db.Movie, moviesNameCase, moviesNameNoCase); err != nil {
|
||||
return fmt.Errorf("error creating movies: %s", err.Error())
|
||||
if err := createGroups(ctx, db.Group, groupsNameCase, groupsNameNoCase); err != nil {
|
||||
return fmt.Errorf("error creating groups: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := createPerformers(ctx, performersNameCase, performersNameNoCase); err != nil {
|
||||
|
|
@ -685,8 +685,8 @@ func populateDB() error {
|
|||
return fmt.Errorf("error creating saved filters: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := linkMovieStudios(ctx, db.Movie); err != nil {
|
||||
return fmt.Errorf("error linking movie studios: %s", err.Error())
|
||||
if err := linkGroupStudios(ctx, db.Group); err != nil {
|
||||
return fmt.Errorf("error linking group studios: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := linkStudiosParent(ctx); err != nil {
|
||||
|
|
@ -1069,12 +1069,12 @@ func makeScene(i int) *models.Scene {
|
|||
pids := indexesToIDs(performerIDs, scenePerformers[i])
|
||||
tids := indexesToIDs(tagIDs, sceneTags[i])
|
||||
|
||||
mids := indexesToIDs(movieIDs, sceneMovies[i])
|
||||
mids := indexesToIDs(groupIDs, sceneGroups[i])
|
||||
|
||||
movies := make([]models.MoviesScenes, len(mids))
|
||||
groups := make([]models.GroupsScenes, len(mids))
|
||||
for i, m := range mids {
|
||||
movies[i] = models.MoviesScenes{
|
||||
MovieID: m,
|
||||
groups[i] = models.GroupsScenes{
|
||||
GroupID: m,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1092,7 +1092,7 @@ func makeScene(i int) *models.Scene {
|
|||
GalleryIDs: models.NewRelatedIDs(gids),
|
||||
PerformerIDs: models.NewRelatedIDs(pids),
|
||||
TagIDs: models.NewRelatedIDs(tids),
|
||||
Movies: models.NewRelatedMovies(movies),
|
||||
Groups: models.NewRelatedGroups(groups),
|
||||
StashIDs: models.NewRelatedStashIDs([]models.StashID{
|
||||
sceneStashID(i),
|
||||
}),
|
||||
|
|
@ -1320,18 +1320,18 @@ func createGalleries(ctx context.Context, n int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getMovieStringValue(index int, field string) string {
|
||||
return getPrefixedStringValue("movie", index, field)
|
||||
func getGroupStringValue(index int, field string) string {
|
||||
return getPrefixedStringValue("group", index, field)
|
||||
}
|
||||
|
||||
func getMovieNullStringValue(index int, field string) string {
|
||||
ret := getPrefixedNullStringValue("movie", index, field)
|
||||
func getGroupNullStringValue(index int, field string) string {
|
||||
ret := getPrefixedNullStringValue("group", index, field)
|
||||
|
||||
return ret.String
|
||||
}
|
||||
|
||||
func getMovieEmptyString(index int, field string) string {
|
||||
v := getPrefixedNullStringValue("movie", index, field)
|
||||
func getGroupEmptyString(index int, field string) string {
|
||||
v := getPrefixedNullStringValue("group", index, field)
|
||||
if !v.Valid {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -1339,8 +1339,8 @@ func getMovieEmptyString(index int, field string) string {
|
|||
return v.String
|
||||
}
|
||||
|
||||
// createMoviees creates n movies with plain Name and o movies with camel cased NaMe included
|
||||
func createMovies(ctx context.Context, mqb models.MovieReaderWriter, n int, o int) error {
|
||||
// createGroups creates n groups with plain Name and o groups with camel cased NaMe included
|
||||
func createGroups(ctx context.Context, mqb models.GroupReaderWriter, n int, o int) error {
|
||||
const namePlain = "Name"
|
||||
const nameNoCase = "NaMe"
|
||||
|
||||
|
|
@ -1348,31 +1348,31 @@ func createMovies(ctx context.Context, mqb models.MovieReaderWriter, n int, o in
|
|||
index := i
|
||||
name := namePlain
|
||||
|
||||
tids := indexesToIDs(tagIDs, movieTags[i])
|
||||
tids := indexesToIDs(tagIDs, groupTags[i])
|
||||
|
||||
if i >= n { // i<n tags get normal names
|
||||
name = nameNoCase // i>=n movies get dup names if case is not checked
|
||||
name = nameNoCase // i>=n groups get dup names if case is not checked
|
||||
index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also
|
||||
} // so count backwards to 0 as needed
|
||||
// movies [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
||||
// groups [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
||||
|
||||
name = getMovieStringValue(index, name)
|
||||
movie := models.Movie{
|
||||
name = getGroupStringValue(index, name)
|
||||
group := models.Group{
|
||||
Name: name,
|
||||
URLs: models.NewRelatedStrings([]string{
|
||||
getMovieEmptyString(i, urlField),
|
||||
getGroupEmptyString(i, urlField),
|
||||
}),
|
||||
TagIDs: models.NewRelatedIDs(tids),
|
||||
}
|
||||
|
||||
err := mqb.Create(ctx, &movie)
|
||||
err := mqb.Create(ctx, &group)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating movie [%d] %v+: %s", i, movie, err.Error())
|
||||
return fmt.Errorf("Error creating group [%d] %v+: %s", i, group, err.Error())
|
||||
}
|
||||
|
||||
movieIDs = append(movieIDs, movie.ID)
|
||||
movieNames = append(movieNames, movie.Name)
|
||||
groupIDs = append(groupIDs, group.ID)
|
||||
groupNames = append(groupNames, group.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -1709,7 +1709,7 @@ func createStudios(ctx context.Context, n int, o int) error {
|
|||
TagIDs: models.NewRelatedIDs(tids),
|
||||
}
|
||||
// only add aliases for some scenes
|
||||
if i == studioIdxWithMovie || i%5 == 0 {
|
||||
if i == studioIdxWithGroup || i%5 == 0 {
|
||||
alias := getStudioStringValue(i, "Alias")
|
||||
studio.Aliases = models.NewRelatedStrings([]string{alias})
|
||||
}
|
||||
|
|
@ -1842,12 +1842,12 @@ func doLinks(links [][2]int, fn func(idx1, idx2 int) error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func linkMovieStudios(ctx context.Context, mqb models.MovieWriter) error {
|
||||
return doLinks(movieStudioLinks, func(movieIndex, studioIndex int) error {
|
||||
movie := models.MoviePartial{
|
||||
func linkGroupStudios(ctx context.Context, mqb models.GroupWriter) error {
|
||||
return doLinks(groupStudioLinks, func(groupIndex, studioIndex int) error {
|
||||
group := models.GroupPartial{
|
||||
StudioID: models.NewOptionalInt(studioIDs[studioIndex]),
|
||||
}
|
||||
_, err := mqb.UpdatePartial(ctx, movieIDs[movieIndex], movie)
|
||||
_, err := mqb.UpdatePartial(ctx, groupIDs[groupIndex], group)
|
||||
|
||||
return err
|
||||
})
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ func TestStudioQueryForAutoTag(t *testing.T) {
|
|||
withTxn(func(ctx context.Context) error {
|
||||
tqb := db.Studio
|
||||
|
||||
name := studioNames[studioIdxWithMovie] // find a studio by name
|
||||
name := studioNames[studioIdxWithGroup] // find a studio by name
|
||||
|
||||
studios, err := tqb.QueryForAutoTag(ctx, []string{name})
|
||||
|
||||
|
|
@ -225,16 +225,16 @@ func TestStudioQueryForAutoTag(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Len(t, studios, 1)
|
||||
assert.Equal(t, strings.ToLower(studioNames[studioIdxWithMovie]), strings.ToLower(studios[0].Name))
|
||||
assert.Equal(t, strings.ToLower(studioNames[studioIdxWithGroup]), strings.ToLower(studios[0].Name))
|
||||
|
||||
name = getStudioStringValue(studioIdxWithMovie, "Alias")
|
||||
name = getStudioStringValue(studioIdxWithGroup, "Alias")
|
||||
studios, err = tqb.QueryForAutoTag(ctx, []string{name})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding studios: %s", err.Error())
|
||||
}
|
||||
if assert.Len(t, studios, 1) {
|
||||
assert.Equal(t, studioIDs[studioIdxWithMovie], studios[0].ID)
|
||||
assert.Equal(t, studioIDs[studioIdxWithGroup], studios[0].ID)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
|
@ -911,7 +911,7 @@ func TestStudioQueryName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStudioQueryAlias(t *testing.T) {
|
||||
const studioIdx = studioIdxWithMovie
|
||||
const studioIdx = studioIdxWithGroup
|
||||
studioName := getStudioStringValue(studioIdx, "Alias")
|
||||
|
||||
aliasCriterion := &models.StringCriterionInput{
|
||||
|
|
|
|||
|
|
@ -588,30 +588,30 @@ func (t *orderedValueTable[T]) modifyJoins(ctx context.Context, id int, v []T, m
|
|||
return nil
|
||||
}
|
||||
|
||||
type scenesMoviesTable struct {
|
||||
type scenesGroupsTable struct {
|
||||
table
|
||||
}
|
||||
|
||||
type moviesScenesRow struct {
|
||||
type groupsScenesRow struct {
|
||||
SceneID null.Int `db:"scene_id"`
|
||||
MovieID null.Int `db:"movie_id"`
|
||||
GroupID null.Int `db:"movie_id"`
|
||||
SceneIndex null.Int `db:"scene_index"`
|
||||
}
|
||||
|
||||
func (r moviesScenesRow) resolve(sceneID int) models.MoviesScenes {
|
||||
return models.MoviesScenes{
|
||||
MovieID: int(r.MovieID.Int64),
|
||||
func (r groupsScenesRow) resolve(sceneID int) models.GroupsScenes {
|
||||
return models.GroupsScenes{
|
||||
GroupID: int(r.GroupID.Int64),
|
||||
SceneIndex: nullIntPtr(r.SceneIndex),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) get(ctx context.Context, id int) ([]models.MoviesScenes, error) {
|
||||
func (t *scenesGroupsTable) get(ctx context.Context, id int) ([]models.GroupsScenes, error) {
|
||||
q := dialect.Select("movie_id", "scene_index").From(t.table.table).Where(t.idColumn.Eq(id))
|
||||
|
||||
const single = false
|
||||
var ret []models.MoviesScenes
|
||||
var ret []models.GroupsScenes
|
||||
if err := queryFunc(ctx, q, single, func(rows *sqlx.Rows) error {
|
||||
var v moviesScenesRow
|
||||
var v groupsScenesRow
|
||||
if err := rows.StructScan(&v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -620,15 +620,15 @@ func (t *scenesMoviesTable) get(ctx context.Context, id int) ([]models.MoviesSce
|
|||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("getting scene movies from %s: %w", t.table.table.GetTable(), err)
|
||||
return nil, fmt.Errorf("getting scene groups from %s: %w", t.table.table.GetTable(), err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) insertJoin(ctx context.Context, id int, v models.MoviesScenes) (sql.Result, error) {
|
||||
func (t *scenesGroupsTable) insertJoin(ctx context.Context, id int, v models.GroupsScenes) (sql.Result, error) {
|
||||
q := dialect.Insert(t.table.table).Cols(t.idColumn.GetCol(), "movie_id", "scene_index").Vals(
|
||||
goqu.Vals{id, v.MovieID, intFromPtr(v.SceneIndex)},
|
||||
goqu.Vals{id, v.GroupID, intFromPtr(v.SceneIndex)},
|
||||
)
|
||||
ret, err := exec(ctx, q)
|
||||
if err != nil {
|
||||
|
|
@ -638,7 +638,7 @@ func (t *scenesMoviesTable) insertJoin(ctx context.Context, id int, v models.Mov
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) insertJoins(ctx context.Context, id int, v []models.MoviesScenes) error {
|
||||
func (t *scenesGroupsTable) insertJoins(ctx context.Context, id int, v []models.GroupsScenes) error {
|
||||
for _, fk := range v {
|
||||
if _, err := t.insertJoin(ctx, id, fk); err != nil {
|
||||
return err
|
||||
|
|
@ -648,7 +648,7 @@ func (t *scenesMoviesTable) insertJoins(ctx context.Context, id int, v []models.
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) replaceJoins(ctx context.Context, id int, v []models.MoviesScenes) error {
|
||||
func (t *scenesGroupsTable) replaceJoins(ctx context.Context, id int, v []models.GroupsScenes) error {
|
||||
if err := t.destroy(ctx, []int{id}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -656,7 +656,7 @@ func (t *scenesMoviesTable) replaceJoins(ctx context.Context, id int, v []models
|
|||
return t.insertJoins(ctx, id, v)
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) addJoins(ctx context.Context, id int, v []models.MoviesScenes) error {
|
||||
func (t *scenesGroupsTable) addJoins(ctx context.Context, id int, v []models.GroupsScenes) error {
|
||||
// get existing foreign keys
|
||||
fks, err := t.get(ctx, id)
|
||||
if err != nil {
|
||||
|
|
@ -664,12 +664,12 @@ func (t *scenesMoviesTable) addJoins(ctx context.Context, id int, v []models.Mov
|
|||
}
|
||||
|
||||
// only add values that are not already present
|
||||
var filtered []models.MoviesScenes
|
||||
var filtered []models.GroupsScenes
|
||||
for _, vv := range v {
|
||||
found := false
|
||||
|
||||
for _, e := range fks {
|
||||
if vv.MovieID == e.MovieID {
|
||||
if vv.GroupID == e.GroupID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
|
@ -682,11 +682,11 @@ func (t *scenesMoviesTable) addJoins(ctx context.Context, id int, v []models.Mov
|
|||
return t.insertJoins(ctx, id, filtered)
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) destroyJoins(ctx context.Context, id int, v []models.MoviesScenes) error {
|
||||
func (t *scenesGroupsTable) destroyJoins(ctx context.Context, id int, v []models.GroupsScenes) error {
|
||||
for _, vv := range v {
|
||||
q := dialect.Delete(t.table.table).Where(
|
||||
t.idColumn.Eq(id),
|
||||
t.table.table.Col("movie_id").Eq(vv.MovieID),
|
||||
t.table.table.Col("movie_id").Eq(vv.GroupID),
|
||||
)
|
||||
|
||||
if _, err := exec(ctx, q); err != nil {
|
||||
|
|
@ -697,7 +697,7 @@ func (t *scenesMoviesTable) destroyJoins(ctx context.Context, id int, v []models
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *scenesMoviesTable) modifyJoins(ctx context.Context, id int, v []models.MoviesScenes, mode models.RelationshipUpdateMode) error {
|
||||
func (t *scenesGroupsTable) modifyJoins(ctx context.Context, id int, v []models.GroupsScenes, mode models.RelationshipUpdateMode) error {
|
||||
switch mode {
|
||||
case models.RelationshipUpdateModeSet:
|
||||
return t.replaceJoins(ctx, id, v)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ var (
|
|||
scenesTagsJoinTable = goqu.T(scenesTagsTable)
|
||||
scenesPerformersJoinTable = goqu.T(performersScenesTable)
|
||||
scenesStashIDsJoinTable = goqu.T("scene_stash_ids")
|
||||
scenesMoviesJoinTable = goqu.T(moviesScenesTable)
|
||||
scenesGroupsJoinTable = goqu.T(groupsScenesTable)
|
||||
scenesURLsJoinTable = goqu.T(scenesURLsTable)
|
||||
|
||||
performersAliasesJoinTable = goqu.T(performersAliasesTable)
|
||||
|
|
@ -37,8 +37,8 @@ var (
|
|||
studiosTagsJoinTable = goqu.T(studiosTagsTable)
|
||||
studiosStashIDsJoinTable = goqu.T("studio_stash_ids")
|
||||
|
||||
moviesURLsJoinTable = goqu.T(movieURLsTable)
|
||||
moviesTagsJoinTable = goqu.T(moviesTagsTable)
|
||||
groupsURLsJoinTable = goqu.T(groupURLsTable)
|
||||
groupsTagsJoinTable = goqu.T(groupsTagsTable)
|
||||
|
||||
tagsAliasesJoinTable = goqu.T(tagAliasesTable)
|
||||
tagRelationsJoinTable = goqu.T(tagRelationsTable)
|
||||
|
|
@ -184,10 +184,10 @@ var (
|
|||
},
|
||||
}
|
||||
|
||||
scenesMoviesTableMgr = &scenesMoviesTable{
|
||||
scenesGroupsTableMgr = &scenesGroupsTable{
|
||||
table: table{
|
||||
table: scenesMoviesJoinTable,
|
||||
idColumn: scenesMoviesJoinTable.Col(sceneIDColumn),
|
||||
table: scenesGroupsJoinTable,
|
||||
idColumn: scenesGroupsJoinTable.Col(sceneIDColumn),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -337,25 +337,25 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
movieTableMgr = &table{
|
||||
table: goqu.T(movieTable),
|
||||
idColumn: goqu.T(movieTable).Col(idColumn),
|
||||
groupTableMgr = &table{
|
||||
table: goqu.T(groupTable),
|
||||
idColumn: goqu.T(groupTable).Col(idColumn),
|
||||
}
|
||||
|
||||
moviesURLsTableMgr = &orderedValueTable[string]{
|
||||
groupsURLsTableMgr = &orderedValueTable[string]{
|
||||
table: table{
|
||||
table: moviesURLsJoinTable,
|
||||
idColumn: moviesURLsJoinTable.Col(movieIDColumn),
|
||||
table: groupsURLsJoinTable,
|
||||
idColumn: groupsURLsJoinTable.Col(groupIDColumn),
|
||||
},
|
||||
valueColumn: moviesURLsJoinTable.Col(movieURLColumn),
|
||||
valueColumn: groupsURLsJoinTable.Col(groupURLColumn),
|
||||
}
|
||||
|
||||
moviesTagsTableMgr = &joinTable{
|
||||
groupsTagsTableMgr = &joinTable{
|
||||
table: table{
|
||||
table: moviesTagsJoinTable,
|
||||
idColumn: moviesTagsJoinTable.Col(movieIDColumn),
|
||||
table: groupsTagsJoinTable,
|
||||
idColumn: groupsTagsJoinTable.Col(groupIDColumn),
|
||||
},
|
||||
fkColumn: moviesTagsJoinTable.Col(tagIDColumn),
|
||||
fkColumn: groupsTagsJoinTable.Col(tagIDColumn),
|
||||
foreignTable: tagTableMgr,
|
||||
orderBy: tagTableMgr.table.Col("name").Asc(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ func (qb *TagStore) FindByGalleryID(ctx context.Context, galleryID int) ([]*mode
|
|||
return qb.queryTags(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *TagStore) FindByMovieID(ctx context.Context, movieID int) ([]*models.Tag, error) {
|
||||
func (qb *TagStore) FindByGroupID(ctx context.Context, movieID int) ([]*models.Tag, error) {
|
||||
query := `
|
||||
SELECT tags.* FROM tags
|
||||
LEFT JOIN movies_tags as movies_join on movies_join.tag_id = tags.id
|
||||
|
|
@ -637,6 +637,7 @@ func (qb *TagStore) Query(ctx context.Context, tagFilter *models.TagFilterType,
|
|||
var tagSortOptions = sortOptions{
|
||||
"created_at",
|
||||
"galleries_count",
|
||||
"groups_count",
|
||||
"id",
|
||||
"images_count",
|
||||
"movies_count",
|
||||
|
|
@ -684,7 +685,7 @@ func (qb *TagStore) getTagSort(query *queryBuilder, findFilter *models.FindFilte
|
|||
case "studios_count":
|
||||
sortQuery += getCountSort(tagTable, studiosTagsTable, tagIDColumn, direction)
|
||||
case "movies_count", "groups_count":
|
||||
sortQuery += getCountSort(tagTable, moviesTagsTable, tagIDColumn, direction)
|
||||
sortQuery += getCountSort(tagTable, groupsTagsTable, tagIDColumn, direction)
|
||||
default:
|
||||
sortQuery += getSort(sort, direction, "tags")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,11 +190,11 @@ func (qb *tagFilterHandler) studioCountCriterionHandler(studioCount *models.IntC
|
|||
}
|
||||
}
|
||||
|
||||
func (qb *tagFilterHandler) groupCountCriterionHandler(movieCount *models.IntCriterionInput) criterionHandlerFunc {
|
||||
func (qb *tagFilterHandler) groupCountCriterionHandler(groupCount *models.IntCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if movieCount != nil {
|
||||
if groupCount != nil {
|
||||
f.addLeftJoin("movies_tags", "", "movies_tags.tag_id = tags.id")
|
||||
clause, args := getIntCriterionWhereClause("count(distinct movies_tags.movie_id)", *movieCount)
|
||||
clause, args := getIntCriterionWhereClause("count(distinct movies_tags.movie_id)", *groupCount)
|
||||
|
||||
f.addHaving(clause, args...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,22 +42,22 @@ func TestMarkerFindBySceneMarkerID(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestTagFindByMovieID(t *testing.T) {
|
||||
func TestTagFindByGroupID(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
tqb := db.Tag
|
||||
|
||||
movieID := movieIDs[movieIdxWithTag]
|
||||
groupID := groupIDs[groupIdxWithTag]
|
||||
|
||||
tags, err := tqb.FindByMovieID(ctx, movieID)
|
||||
tags, err := tqb.FindByGroupID(ctx, groupID)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding tags: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Len(t, tags, 1)
|
||||
assert.Equal(t, tagIDs[tagIdxWithMovie], tags[0].ID)
|
||||
assert.Equal(t, tagIDs[tagIdxWithGroup], tags[0].ID)
|
||||
|
||||
tags, err = tqb.FindByMovieID(ctx, 0)
|
||||
tags, err = tqb.FindByGroupID(ctx, 0)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding tags: %s", err.Error())
|
||||
|
|
@ -236,7 +236,7 @@ func TestTagQuerySort(t *testing.T) {
|
|||
|
||||
sortBy = "movies_count"
|
||||
tags = queryTags(ctx, t, sqb, nil, findFilter)
|
||||
assert.Equal(tagIDs[tagIdx1WithMovie], tags[0].ID)
|
||||
assert.Equal(tagIDs[tagIdx1WithGroup], tags[0].ID)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ func (db *Database) Repository() models.Repository {
|
|||
Gallery: db.Gallery,
|
||||
GalleryChapter: db.GalleryChapter,
|
||||
Image: db.Image,
|
||||
Movie: db.Movie,
|
||||
Group: db.Group,
|
||||
Performer: db.Performer,
|
||||
Scene: db.Scene,
|
||||
SceneMarker: db.SceneMarker,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ sceneByFragment:
|
|||
<single scraper config>
|
||||
sceneByURL:
|
||||
<multiple scraper URL configs>
|
||||
movieByURL:
|
||||
groupByURL:
|
||||
<multiple scraper URL configs>
|
||||
galleryByFragment:
|
||||
<single scraper config>
|
||||
|
|
@ -42,7 +42,7 @@ The scraping types and their required fields are outlined in the following table
|
|||
| Scraper in query dropdown button in Scene Edit page | Valid `sceneByName` and `sceneByQueryFragment` configurations. |
|
||||
| Scraper in `Scrape...` dropdown button in Scene Edit page | Valid `sceneByFragment` configuration. |
|
||||
| Scrape scene from URL | Valid `sceneByURL` configuration with matching URL. |
|
||||
| Scrape movie from URL | Valid `movieByURL` configuration with matching URL. |
|
||||
| Scrape group from URL | Valid `groupByURL` configuration with matching URL. **Note:** `movieByURL` is also supported but is deprecated. |
|
||||
| Scraper in `Scrape...` dropdown button in Gallery Edit page | Valid `galleryByFragment` configuration. |
|
||||
| Scrape gallery from URL | Valid `galleryByURL` configuration with matching URL. |
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ The script is sent input and expects output based on the scraping type, as detai
|
|||
| `sceneByName` | `{"name": "<scene query string>"}` | Array of JSON-encoded scene fragments |
|
||||
| `sceneByQueryFragment`, `sceneByFragment` | JSON-encoded scene fragment | JSON-encoded scene fragment |
|
||||
| `sceneByURL` | `{"url": "<url>"}` | JSON-encoded scene fragment |
|
||||
| `movieByURL` | `{"url": "<url>"}` | JSON-encoded movie fragment |
|
||||
| `groupByURL` | `{"url": "<url>"}` | JSON-encoded group fragment |
|
||||
| `galleryByFragment` | JSON-encoded gallery fragment | JSON-encoded gallery fragment |
|
||||
| `galleryByURL` | `{"url": "<url>"}` | JSON-encoded gallery fragment |
|
||||
|
||||
|
|
@ -225,7 +225,7 @@ sceneByFragment:
|
|||
|
||||
The above configuration would scrape from the value of `queryURL`, replacing `{filename}` with the base filename of the scene, after it has been manipulated by the regex replacements.
|
||||
|
||||
### scrapeXPath and scrapeJson use with `<scene|performer|gallery|movie>ByURL`
|
||||
### scrapeXPath and scrapeJson use with `<scene|performer|gallery|group>ByURL`
|
||||
|
||||
For `sceneByURL`, `performerByURL`, `galleryByURL` the `queryURL` can also be present if we want to use `queryURLReplace`. The functionality is the same as `sceneByFragment`, the only placeholder field available though is the `url`:
|
||||
* `{url}` - the url of the scene/performer/gallery
|
||||
|
|
@ -271,9 +271,9 @@ Likewise, the top-level `jsonScrapers` field contains json scraping configuratio
|
|||
|
||||
Collectively, these configurations are known as mapped scraping configurations.
|
||||
|
||||
A mapped scraping configuration may contain a `common` field, and must contain `performer`, `scene`, `movie` or `gallery` depending on the scraping type it is configured for.
|
||||
A mapped scraping configuration may contain a `common` field, and must contain `performer`, `scene`, `group` or `gallery` depending on the scraping type it is configured for.
|
||||
|
||||
Within the `performer`/`scene`/`movie`/`gallery` field are key/value pairs corresponding to the [golang fields](/help/ScraperDevelopment.md#object-fields) on the performer/scene object. These fields are case-sensitive.
|
||||
Within the `performer`/`scene`/`group`/`gallery` field are key/value pairs corresponding to the [golang fields](/help/ScraperDevelopment.md#object-fields) on the performer/scene object. These fields are case-sensitive.
|
||||
|
||||
The values of these may be either a simple selector value, which tells the system where to get the value of the field from, or a more advanced configuration (see below). For example, for an xpath configuration:
|
||||
|
||||
|
|
@ -820,7 +820,7 @@ URL
|
|||
Date
|
||||
Image
|
||||
Studio (see Studio Fields)
|
||||
Movies (see Movie Fields)
|
||||
Groups (see Group Fields)
|
||||
Tags (see Tag fields)
|
||||
Performers (list of Performer fields)
|
||||
```
|
||||
|
|
@ -835,7 +835,7 @@ URL
|
|||
Name
|
||||
```
|
||||
|
||||
### Movie
|
||||
### Group
|
||||
```
|
||||
Name
|
||||
Aliases
|
||||
|
|
|
|||
Loading…
Reference in a new issue