From 15a7b8a8594bf0557d130ceaf91e05d3d0297c0a Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Thu, 4 Jul 2024 09:10:26 +1000 Subject: [PATCH] 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 --- gqlgen.yml | 10 +- internal/api/changeset_translator.go | 50 +-- internal/api/context_keys.go | 2 +- internal/api/loaders/dataloaders.go | 14 +- internal/api/loaders/movieloader_gen.go | 80 ++-- internal/api/resolver.go | 12 +- internal/api/resolver_model_movie.go | 38 +- internal/api/resolver_model_performer.go | 8 +- internal/api/resolver_model_scene.go | 22 +- internal/api/resolver_model_studio.go | 8 +- internal/api/resolver_model_tag.go | 2 +- internal/api/resolver_mutation_group.go | 152 +++---- internal/api/resolver_mutation_movie.go | 150 +++---- internal/api/resolver_mutation_scene.go | 14 +- internal/api/resolver_query_find_group.go | 16 +- internal/api/resolver_query_find_movie.go | 20 +- internal/api/resolver_query_scraper.go | 8 +- internal/api/routes_movie.go | 50 +-- internal/api/server.go | 8 +- internal/api/urlbuilders/movie.go | 23 +- internal/dlna/cds.go | 26 +- internal/dlna/dms.go | 4 +- internal/dlna/service.go | 4 +- internal/manager/json_utils.go | 4 +- internal/manager/task_export.go | 98 ++--- internal/manager/task_import.go | 30 +- internal/static/embed.go | 4 +- pkg/match/scraped.go | 24 +- pkg/models/jsonschema/movie.go | 10 +- pkg/models/jsonschema/scene.go | 6 +- ...ieReaderWriter.go => GroupReaderWriter.go} | 202 ++++----- pkg/models/mocks/SavedFilterReaderWriter.go | 37 -- pkg/models/mocks/SceneReaderWriter.go | 66 +-- pkg/models/mocks/TagReaderWriter.go | 46 +- pkg/models/mocks/database.go | 8 +- pkg/models/model_joins.go | 38 +- pkg/models/model_movie.go | 16 +- pkg/models/model_scene.go | 14 +- pkg/models/model_scraped_item.go | 48 +++ pkg/models/movie.go | 4 +- pkg/models/paths/paths_json.go | 10 +- pkg/models/relationships.go | 38 +- pkg/models/repository.go | 2 +- pkg/models/repository_movie.go | 106 ++--- pkg/models/repository_scene.go | 6 +- pkg/models/repository_tag.go | 2 +- pkg/models/scene.go | 4 +- pkg/movie/export.go | 4 +- pkg/movie/export_test.go | 44 +- pkg/movie/import.go | 76 ++-- pkg/movie/import_test.go | 84 ++-- pkg/movie/query.go | 8 +- pkg/scene/export.go | 36 +- pkg/scene/export_test.go | 78 ++-- pkg/scene/filename_parser.go | 52 +-- pkg/scene/import.go | 48 +-- pkg/scene/import_test.go | 58 +-- pkg/scraper/cache.go | 4 +- pkg/scraper/config.go | 27 +- pkg/scraper/group.go | 2 +- pkg/scraper/image.go | 34 ++ pkg/scraper/json.go | 2 +- pkg/scraper/mapped.go | 2 +- pkg/scraper/postprocessing.go | 71 ++- pkg/scraper/xpath.go | 2 +- pkg/sqlite/anonymise.go | 12 +- pkg/sqlite/blob_test.go | 2 +- pkg/sqlite/database.go | 4 +- pkg/sqlite/movies.go | 204 ++++----- pkg/sqlite/movies_filter.go | 98 ++--- pkg/sqlite/movies_test.go | 404 +++++++++--------- pkg/sqlite/scene.go | 46 +- pkg/sqlite/scene_filter.go | 12 +- pkg/sqlite/scene_test.go | 212 ++++----- pkg/sqlite/setup_test.go | 116 ++--- pkg/sqlite/studio_test.go | 10 +- pkg/sqlite/table.go | 40 +- pkg/sqlite/tables.go | 34 +- pkg/sqlite/tag.go | 5 +- pkg/sqlite/tag_filter.go | 6 +- pkg/sqlite/tag_test.go | 12 +- pkg/sqlite/transaction.go | 2 +- .../src/docs/en/Manual/ScraperDevelopment.md | 16 +- 83 files changed, 1765 insertions(+), 1646 deletions(-) rename pkg/models/mocks/{MovieReaderWriter.go => GroupReaderWriter.go} (59%) diff --git a/gqlgen.yml b/gqlgen.yml index 36febdaae..9f22ccb49 100644 --- a/gqlgen.yml +++ b/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 diff --git a/internal/api/changeset_translator.go b/internal/api/changeset_translator.go index b5bd5835a..efac25087 100644 --- a/internal/api/changeset_translator.go +++ b/internal/api/changeset_translator.go @@ -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 } diff --git a/internal/api/context_keys.go b/internal/api/context_keys.go index a8ab0afb5..df61139f8 100644 --- a/internal/api/context_keys.go +++ b/internal/api/context_keys.go @@ -9,7 +9,7 @@ const ( performerKey key = iota + 1 sceneKey studioKey - movieKey + groupKey tagKey downloadKey imageKey diff --git a/internal/api/loaders/dataloaders.go b/internal/api/loaders/dataloaders.go index 397b57d04..d1b13db69 100644 --- a/internal/api/loaders/dataloaders.go +++ b/internal/api/loaders/dataloaders.go @@ -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) diff --git a/internal/api/loaders/movieloader_gen.go b/internal/api/loaders/movieloader_gen.go index 3783d3a41..e892f63c2 100644 --- a/internal/api/loaders/movieloader_gen.go +++ b/internal/api/loaders/movieloader_gen.go @@ -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) } diff --git a/internal/api/resolver.go b/internal/api/resolver.go index 78ec0fc58..e5c635b9a 100644 --- a/internal/api/resolver.go +++ b/internal/api/resolver.go @@ -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 diff --git a/internal/api/resolver_model_movie.go b/internal/api/resolver_model_movie.go index d1509c7a1..abbbccaf1 100644 --- a/internal/api/resolver_model_movie.go +++ b/internal/api/resolver_model_movie.go @@ -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 diff --git a/internal/api/resolver_model_performer.go b/internal/api/resolver_model_performer.go index 224e733bd..b6f6af369 100644 --- a/internal/api/resolver_model_performer.go +++ b/internal/api/resolver_model_performer.go @@ -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) } diff --git a/internal/api/resolver_model_scene.go b/internal/api/resolver_model_scene.go index 987c6e7b8..2600c9538 100644 --- a/internal/api/resolver_model_scene.go +++ b/internal/api/resolver_model_scene.go @@ -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, } diff --git a/internal/api/resolver_model_studio.go b/internal/api/resolver_model_studio.go index 1f8142e99..9dcfd5df5 100644 --- a/internal/api/resolver_model_studio.go +++ b/internal/api/resolver_model_studio.go @@ -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) } diff --git a/internal/api/resolver_model_tag.go b/internal/api/resolver_model_tag.go index 3cf0bd1d9..11b9f935b 100644 --- a/internal/api/resolver_model_tag.go +++ b/internal/api/resolver_model_tag.go @@ -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 diff --git a/internal/api/resolver_mutation_group.go b/internal/api/resolver_mutation_group.go index 1645d80b3..d455dd105 100644 --- a/internal/api/resolver_mutation_group.go +++ b/internal/api/resolver_mutation_group.go @@ -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 diff --git a/internal/api/resolver_mutation_movie.go b/internal/api/resolver_mutation_movie.go index 3e73f32dd..2e1011083 100644 --- a/internal/api/resolver_mutation_movie.go +++ b/internal/api/resolver_mutation_movie.go @@ -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 diff --git a/internal/api/resolver_mutation_scene.go b/internal/api/resolver_mutation_scene.go index d3616cc4c..3020f13fd 100644 --- a/internal/api/resolver_mutation_scene.go +++ b/internal/api/resolver_mutation_scene.go @@ -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) } diff --git a/internal/api/resolver_query_find_group.go b/internal/api/resolver_query_find_group.go index f5fdde50a..6f8a6c6ba 100644 --- a/internal/api/resolver_query_find_group.go +++ b/internal/api/resolver_query_find_group.go @@ -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 { diff --git a/internal/api/resolver_query_find_movie.go b/internal/api/resolver_query_find_movie.go index 84e01e282..2f80d6f59 100644 --- a/internal/api/resolver_query_find_movie.go +++ b/internal/api/resolver_query_find_movie.go @@ -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 diff --git a/internal/api/resolver_query_scraper.go b/internal/api/resolver_query_scraper.go index 9d69843bc..b9690cea7 100644 --- a/internal/api/resolver_query_scraper.go +++ b/internal/api/resolver_query_scraper.go @@ -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{ diff --git a/internal/api/routes_movie.go b/internal/api/routes_movie.go index cd4224681..20eaa4c23 100644 --- a/internal/api/routes_movie.go +++ b/internal/api/routes_movie.go @@ -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)) }) } diff --git a/internal/api/server.go b/internal/api/server.go index b9fd1eeed..679bd3f1c 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -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() } diff --git a/internal/api/urlbuilders/movie.go b/internal/api/urlbuilders/movie.go index a9ca68310..26abd8dbd 100644 --- a/internal/api/urlbuilders/movie.go +++ b/internal/api/urlbuilders/movie.go @@ -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 } diff --git a/internal/dlna/cds.go b/internal/dlna/cds.go index 6e1604bdc..b6a4014b1 100644 --- a/internal/dlna/cds.go +++ b/internal/dlna/cds.go @@ -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 { diff --git a/internal/dlna/dms.go b/internal/dlna/dms.go index 0df483cca..8c5074d30 100644 --- a/internal/dlna/dms.go +++ b/internal/dlna/dms.go @@ -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 ( diff --git a/internal/dlna/service.go b/internal/dlna/service.go index 07f416084..6ef825bac 100644 --- a/internal/dlna/service.go +++ b/internal/dlna/service.go @@ -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, } } diff --git a/internal/manager/json_utils.go b/internal/manager/json_utils.go index c90c95029..f1ce60404 100644 --- a/internal/manager/json_utils.go +++ b/internal/manager/json_utils.go @@ -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 { diff --git a/internal/manager/task_export.go b/internal/manager/task_export.go index cbf304fb6..150894914 100644 --- a/internal/manager/task_export.go +++ b/internal/manager/task_export.go @@ -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) } } } diff --git a/internal/manager/task_import.go b/internal/manager/task_import.go index 47fbf0cd1..b83ca0b3c 100644 --- a/internal/manager/task_import.go +++ b/internal/manager/task_import.go @@ -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, diff --git a/internal/static/embed.go b/internal/static/embed.go index d82c0b66b..7c06c611b 100644 --- a/internal/static/embed.go +++ b/internal/static/embed.go @@ -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. diff --git a/pkg/match/scraped.go b/pkg/match/scraped.go index 0b8a8d696..637d48bfc 100644 --- a/pkg/match/scraped.go +++ b/pkg/match/scraped.go @@ -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 diff --git a/pkg/models/jsonschema/movie.go b/pkg/models/jsonschema/movie.go index eeefe1ed1..fcf1ffe60 100644 --- a/pkg/models/jsonschema/movie.go +++ b/pkg/models/jsonschema/movie.go @@ -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") } diff --git a/pkg/models/jsonschema/scene.go b/pkg/models/jsonschema/scene.go index 9c59610ab..757f520b8 100644 --- a/pkg/models/jsonschema/scene.go +++ b/pkg/models/jsonschema/scene.go @@ -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"` diff --git a/pkg/models/mocks/MovieReaderWriter.go b/pkg/models/mocks/GroupReaderWriter.go similarity index 59% rename from pkg/models/mocks/MovieReaderWriter.go rename to pkg/models/mocks/GroupReaderWriter.go index 0da8c8a19..5e3a2644c 100644 --- a/pkg/models/mocks/MovieReaderWriter.go +++ b/pkg/models/mocks/GroupReaderWriter.go @@ -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) } diff --git a/pkg/models/mocks/SavedFilterReaderWriter.go b/pkg/models/mocks/SavedFilterReaderWriter.go index 655738546..53f5cb0e5 100644 --- a/pkg/models/mocks/SavedFilterReaderWriter.go +++ b/pkg/models/mocks/SavedFilterReaderWriter.go @@ -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) diff --git a/pkg/models/mocks/SceneReaderWriter.go b/pkg/models/mocks/SceneReaderWriter.go index 080e40b0d..3787d8182 100644 --- a/pkg/models/mocks/SceneReaderWriter.go +++ b/pkg/models/mocks/SceneReaderWriter.go @@ -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) diff --git a/pkg/models/mocks/TagReaderWriter.go b/pkg/models/mocks/TagReaderWriter.go index c3dfe7bd2..a285b97bf 100644 --- a/pkg/models/mocks/TagReaderWriter.go +++ b/pkg/models/mocks/TagReaderWriter.go @@ -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) diff --git a/pkg/models/mocks/database.go b/pkg/models/mocks/database.go index 83d2cbfab..189299210 100644 --- a/pkg/models/mocks/database.go +++ b/pkg/models/mocks/database.go @@ -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, diff --git a/pkg/models/model_joins.go b/pkg/models/model_joins.go index da70293c3..189c2d772 100644 --- a/pkg/models/model_joins.go +++ b/pkg/models/model_joins.go @@ -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, } } diff --git a/pkg/models/model_movie.go b/pkg/models/model_movie.go index cd8bb848c..af3ac56c6 100644 --- a/pkg/models/model_movie.go +++ b/pkg/models/model_movie.go @@ -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), } } diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index 7b7770471..3f26a8cb6 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -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, } diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index e95fc6df4..35f781109 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -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 +} diff --git a/pkg/models/movie.go b/pkg/models/movie.go index 5fb98190d..db7badccc 100644 --- a/pkg/models/movie.go +++ b/pkg/models/movie.go @@ -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"` diff --git a/pkg/models/paths/paths_json.go b/pkg/models/paths/paths_json.go index 7f05027c4..e6e302238 100644 --- a/pkg/models/paths/paths_json.go +++ b/pkg/models/paths/paths_json.go @@ -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) diff --git a/pkg/models/relationships.go b/pkg/models/relationships.go index 021fab4db..81528c26e 100644 --- a/pkg/models/relationships.go +++ b/pkg/models/relationships.go @@ -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 diff --git a/pkg/models/repository.go b/pkg/models/repository.go index 3eb9a03d3..9bd1e8cad 100644 --- a/pkg/models/repository.go +++ b/pkg/models/repository.go @@ -20,7 +20,7 @@ type Repository struct { Gallery GalleryReaderWriter GalleryChapter GalleryChapterReaderWriter Image ImageReaderWriter - Movie MovieReaderWriter + Group GroupReaderWriter Performer PerformerReaderWriter Scene SceneReaderWriter SceneMarker SceneMarkerReaderWriter diff --git a/pkg/models/repository_movie.go b/pkg/models/repository_movie.go index dec0e0421..0396049b6 100644 --- a/pkg/models/repository_movie.go +++ b/pkg/models/repository_movie.go @@ -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 } diff --git a/pkg/models/repository_scene.go b/pkg/models/repository_scene.go index bc01ca691..bbd696066 100644 --- a/pkg/models/repository_scene.go +++ b/pkg/models/repository_scene.go @@ -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 diff --git a/pkg/models/repository_tag.go b/pkg/models/repository_tag.go index 00f35abc4..2b073cae0 100644 --- a/pkg/models/repository_tag.go +++ b/pkg/models/repository_tag.go @@ -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) diff --git a/pkg/models/scene.go b/pkg/models/scene.go index 5c5df87db..814c4a41d 100644 --- a/pkg/models/scene.go +++ b/pkg/models/scene.go @@ -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 diff --git a/pkg/movie/export.go b/pkg/movie/export.go index 55e157168..06f492320 100644 --- a/pkg/movie/export.go +++ b/pkg/movie/export.go @@ -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, diff --git a/pkg/movie/export_test.go b/pkg/movie/export_test.go index dd6c9f274..ee83a360a 100644 --- a/pkg/movie/export_test.go +++ b/pkg/movie/export_test.go @@ -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: diff --git a/pkg/movie/import.go b/pkg/movie/import.go index 27c25316d..fea410d95 100644 --- a/pkg/movie/import.go +++ b/pkg/movie/import.go @@ -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 diff --git a/pkg/movie/import_test.go b/pkg/movie/import_test.go index 2cf35319c..c1d1e18f6 100644 --- a/pkg/movie/import_test.go +++ b/pkg/movie/import_test.go @@ -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) diff --git a/pkg/movie/query.go b/pkg/movie/query.go index 72764b8dd..8b2e5baef 100644 --- a/pkg/movie/query.go +++ b/pkg/movie/query.go @@ -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, diff --git a/pkg/scene/export.go b/pkg/scene/export.go index 6c2895c08..5733c3be5 100644 --- a/pkg/scene/export.go +++ b/pkg/scene/export.go @@ -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 diff --git a/pkg/scene/export_test.go b/pkg/scene/export_test.go index 89fe3dfc6..cde421bd8 100644 --- a/pkg/scene/export_test.go +++ b/pkg/scene/export_test.go @@ -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: diff --git a/pkg/scene/filename_parser.go b/pkg/scene/filename_parser.go index 0426696de..b8dff89d7 100644 --- a/pkg/scene/filename_parser.go +++ b/pkg/scene/filename_parser.go @@ -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) } } diff --git a/pkg/scene/import.go b/pkg/scene/import.go index fc2db4dea..884d6d7e0 100644 --- a/pkg/scene/import.go +++ b/pkg/scene/import.go @@ -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 { diff --git a/pkg/scene/import_test.go b/pkg/scene/import_test.go index 261807856..26844f687 100644 --- a/pkg/scene/import_test.go +++ b/pkg/scene/import_test.go @@ -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) diff --git a/pkg/scraper/cache.go b/pkg/scraper/cache.go index 167b7676b..1799892f9 100644 --- a/pkg/scraper/cache.go +++ b/pkg/scraper/cache.go @@ -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, } } diff --git a/pkg/scraper/config.go b/pkg/scraper/config.go index 19545a08d..9c51b4bba 100644 --- a/pkg/scraper/config.go +++ b/pkg/scraper/config.go @@ -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") diff --git a/pkg/scraper/group.go b/pkg/scraper/group.go index 94cc05b96..fff9beb2f 100644 --- a/pkg/scraper/group.go +++ b/pkg/scraper/group.go @@ -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 } diff --git a/pkg/scraper/image.go b/pkg/scraper/image.go index 78652f11d..193ddc517 100644 --- a/pkg/scraper/image.go +++ b/pkg/scraper/image.go @@ -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 { diff --git a/pkg/scraper/json.go b/pkg/scraper/json.go index 0da20a827..929b5152e 100644 --- a/pkg/scraper/json.go +++ b/pkg/scraper/json.go @@ -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 } diff --git a/pkg/scraper/mapped.go b/pkg/scraper/mapped.go index 7b0d6dc7e..a6b70565f 100644 --- a/pkg/scraper/mapped.go +++ b/pkg/scraper/mapped.go @@ -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 diff --git a/pkg/scraper/postprocessing.go b/pkg/scraper/postprocessing.go index e153c5616..09a4657c3 100644 --- a/pkg/scraper/postprocessing.go +++ b/pkg/scraper/postprocessing.go @@ -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) diff --git a/pkg/scraper/xpath.go b/pkg/scraper/xpath.go index 9eab9c67f..299e9b5db 100644 --- a/pkg/scraper/xpath.go +++ b/pkg/scraper/xpath.go @@ -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 } diff --git a/pkg/sqlite/anonymise.go b/pkg/sqlite/anonymise.go index 465e6cad5..1dc12df1c 100644 --- a/pkg/sqlite/anonymise.go +++ b/pkg/sqlite/anonymise.go @@ -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 } diff --git a/pkg/sqlite/blob_test.go b/pkg/sqlite/blob_test.go index 4c6e0ccc2..10c2b93fe 100644 --- a/pkg/sqlite/blob_test.go +++ b/pkg/sqlite/blob_test.go @@ -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") diff --git a/pkg/sqlite/database.go b/pkg/sqlite/database.go index 84220b398..675ee4972 100644 --- a/pkg/sqlite/database.go +++ b/pkg/sqlite/database.go @@ -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(), } diff --git a/pkg/sqlite/movies.go b/pkg/sqlite/movies.go index e5c08c31f..ca9b0b8f2 100644 --- a/pkg/sqlite/movies.go +++ b/pkg/sqlite/movies.go @@ -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) } diff --git a/pkg/sqlite/movies_filter.go b/pkg/sqlite/movies_filter.go index 0a2b3d674..54c4cd03b 100644 --- a/pkg/sqlite/movies_filter.go +++ b/pkg/sqlite/movies_filter.go @@ -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) diff --git a/pkg/sqlite/movies_test.go b/pkg/sqlite/movies_test.go index 3cfe05fe8..451713379 100644 --- a/pkg/sqlite/movies_test.go +++ b/pkg/sqlite/movies_test.go @@ -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()) } diff --git a/pkg/sqlite/scene.go b/pkg/sqlite/scene.go index fa0cb5e63..5b4caff11 100644 --- a/pkg/sqlite/scene.go +++ b/pkg/sqlite/scene.go @@ -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 } diff --git a/pkg/sqlite/scene_filter.go b/pkg/sqlite/scene_filter.go index 7c6e3f634..53eacaf34 100644 --- a/pkg/sqlite/scene_filter.go +++ b/pkg/sqlite/scene_filter.go @@ -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) } diff --git a/pkg/sqlite/scene_test.go b/pkg/sqlite/scene_test.go index f5528b124..9116158fc 100644 --- a/pkg/sqlite/scene_test.go +++ b/pkg/sqlite/scene_test.go @@ -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()) diff --git a/pkg/sqlite/setup_test.go b/pkg/sqlite/setup_test.go index b8ce23cd6..aa6af73c4 100644 --- a/pkg/sqlite/setup_test.go +++ b/pkg/sqlite/setup_test.go @@ -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 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 }) diff --git a/pkg/sqlite/studio_test.go b/pkg/sqlite/studio_test.go index 627129f0d..a61dadc24 100644 --- a/pkg/sqlite/studio_test.go +++ b/pkg/sqlite/studio_test.go @@ -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{ diff --git a/pkg/sqlite/table.go b/pkg/sqlite/table.go index 6b6ed9417..65716cff3 100644 --- a/pkg/sqlite/table.go +++ b/pkg/sqlite/table.go @@ -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) diff --git a/pkg/sqlite/tables.go b/pkg/sqlite/tables.go index 2f500639e..7f93c8148 100644 --- a/pkg/sqlite/tables.go +++ b/pkg/sqlite/tables.go @@ -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(), } diff --git a/pkg/sqlite/tag.go b/pkg/sqlite/tag.go index 69dc086ea..faab05c5e 100644 --- a/pkg/sqlite/tag.go +++ b/pkg/sqlite/tag.go @@ -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") } diff --git a/pkg/sqlite/tag_filter.go b/pkg/sqlite/tag_filter.go index c2fd1723f..8daee02a8 100644 --- a/pkg/sqlite/tag_filter.go +++ b/pkg/sqlite/tag_filter.go @@ -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...) } diff --git a/pkg/sqlite/tag_test.go b/pkg/sqlite/tag_test.go index 099f8b912..f673567f8 100644 --- a/pkg/sqlite/tag_test.go +++ b/pkg/sqlite/tag_test.go @@ -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 }) diff --git a/pkg/sqlite/transaction.go b/pkg/sqlite/transaction.go index eda5b6b8d..705c61e07 100644 --- a/pkg/sqlite/transaction.go +++ b/pkg/sqlite/transaction.go @@ -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, diff --git a/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md b/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md index c74b821cf..caa3d41dc 100644 --- a/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md +++ b/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md @@ -20,7 +20,7 @@ sceneByFragment: sceneByURL: -movieByURL: +groupByURL: galleryByFragment: @@ -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": ""}` | Array of JSON-encoded scene fragments | | `sceneByQueryFragment`, `sceneByFragment` | JSON-encoded scene fragment | JSON-encoded scene fragment | | `sceneByURL` | `{"url": ""}` | JSON-encoded scene fragment | -| `movieByURL` | `{"url": ""}` | JSON-encoded movie fragment | +| `groupByURL` | `{"url": ""}` | JSON-encoded group fragment | | `galleryByFragment` | JSON-encoded gallery fragment | JSON-encoded gallery fragment | | `galleryByURL` | `{"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 `ByURL` +### scrapeXPath and scrapeJson use with `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