diff --git a/gqlgen.yml b/gqlgen.yml index 5be8c743a..b5d2674fa 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -23,10 +23,10 @@ autobind: models: # Scalars - Timestamp: - model: github.com/stashapp/stash/pkg/models.Timestamp Int64: - model: github.com/stashapp/stash/pkg/models.Int64 + model: github.com/99designs/gqlgen/graphql.Int64 + Timestamp: + model: github.com/stashapp/stash/internal/api.Timestamp # define to force resolvers Image: model: github.com/stashapp/stash/pkg/models.Image @@ -54,12 +54,6 @@ models: model: github.com/stashapp/stash/internal/manager/config.ScanMetadataOptions AutoTagMetadataOptions: model: github.com/stashapp/stash/internal/manager/config.AutoTagMetadataOptions - SceneParserInput: - model: github.com/stashapp/stash/internal/manager.SceneParserInput - SceneParserResult: - model: github.com/stashapp/stash/internal/manager.SceneParserResult - SceneMovieID: - model: github.com/stashapp/stash/internal/manager.SceneMovieID SystemStatus: model: github.com/stashapp/stash/internal/manager.SystemStatus SystemStatusEnum: diff --git a/pkg/models/timestamp.go b/internal/api/models.go similarity index 98% rename from pkg/models/timestamp.go rename to internal/api/models.go index 478948da6..92713a56e 100644 --- a/pkg/models/timestamp.go +++ b/internal/api/models.go @@ -1,4 +1,4 @@ -package models +package api import ( "errors" diff --git a/pkg/models/timestamp_test.go b/internal/api/models_test.go similarity index 99% rename from pkg/models/timestamp_test.go rename to internal/api/models_test.go index 392a1e8d8..35c9bd03c 100644 --- a/pkg/models/timestamp_test.go +++ b/internal/api/models_test.go @@ -1,4 +1,4 @@ -package models +package api import ( "bytes" diff --git a/internal/api/resolver_query_find_scene.go b/internal/api/resolver_query_find_scene.go index 608bb7a9e..2b33d2115 100644 --- a/internal/api/resolver_query_find_scene.go +++ b/internal/api/resolver_query_find_scene.go @@ -5,8 +5,9 @@ import ( "strconv" "github.com/99designs/gqlgen/graphql" - "github.com/stashapp/stash/internal/manager" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/scene" "github.com/stashapp/stash/pkg/sliceutil/stringslice" ) @@ -189,11 +190,11 @@ func (r *queryResolver) FindScenesByPathRegex(ctx context.Context, filter *model return ret, nil } -func (r *queryResolver) ParseSceneFilenames(ctx context.Context, filter *models.FindFilterType, config manager.SceneParserInput) (ret *SceneParserResultType, err error) { - parser := manager.NewSceneFilenameParser(filter, config) +func (r *queryResolver) ParseSceneFilenames(ctx context.Context, filter *models.FindFilterType, config models.SceneParserInput) (ret *SceneParserResultType, err error) { + parser := scene.NewFilenameParser(filter, config) if err := r.withReadTxn(ctx, func(ctx context.Context) error { - result, count, err := parser.Parse(ctx, manager.SceneFilenameParserRepository{ + result, count, err := parser.Parse(ctx, scene.FilenameParserRepository{ Scene: r.repository.Scene, Performer: r.repository.Performer, Studio: r.repository.Studio, diff --git a/pkg/models/filename_parser.go b/pkg/models/filename_parser.go new file mode 100644 index 000000000..584ae72cb --- /dev/null +++ b/pkg/models/filename_parser.go @@ -0,0 +1,30 @@ +package models + +type SceneParserInput struct { + IgnoreWords []string `json:"ignoreWords"` + WhitespaceCharacters *string `json:"whitespaceCharacters"` + CapitalizeTitle *bool `json:"capitalizeTitle"` + IgnoreOrganized *bool `json:"ignoreOrganized"` +} + +type SceneParserResult struct { + Scene *Scene `json:"scene"` + Title *string `json:"title"` + Code *string `json:"code"` + Details *string `json:"details"` + Director *string `json:"director"` + URL *string `json:"url"` + Date *string `json:"date"` + Rating *int `json:"rating"` + Rating100 *int `json:"rating100"` + StudioID *string `json:"studio_id"` + GalleryIds []string `json:"gallery_ids"` + PerformerIds []string `json:"performer_ids"` + Movies []*SceneMovieID `json:"movies"` + TagIds []string `json:"tag_ids"` +} + +type SceneMovieID struct { + MovieID string `json:"movie_id"` + SceneIndex *string `json:"scene_index"` +} diff --git a/pkg/models/int64.go b/pkg/models/int64.go deleted file mode 100644 index cfc557793..000000000 --- a/pkg/models/int64.go +++ /dev/null @@ -1,39 +0,0 @@ -package models - -import ( - "errors" - "fmt" - "io" - "strconv" - - "github.com/99designs/gqlgen/graphql" - "github.com/stashapp/stash/pkg/logger" -) - -var ErrInt64 = errors.New("cannot parse Int64") - -func MarshalInt64(v int64) graphql.Marshaler { - return graphql.WriterFunc(func(w io.Writer) { - _, err := io.WriteString(w, strconv.FormatInt(v, 10)) - if err != nil { - logger.Warnf("could not marshal int64: %v", err) - } - }) -} - -func UnmarshalInt64(v interface{}) (int64, error) { - if tmpStr, ok := v.(string); ok { - if len(tmpStr) == 0 { - return 0, nil - } - - ret, err := strconv.ParseInt(tmpStr, 10, 64) - if err != nil { - return 0, fmt.Errorf("cannot parse %v as Int64: %w", tmpStr, err) - } - - return ret, nil - } - - return 0, fmt.Errorf("%w: not a string", ErrInt64) -} diff --git a/internal/manager/filename_parser.go b/pkg/scene/filename_parser.go similarity index 83% rename from internal/manager/filename_parser.go rename to pkg/scene/filename_parser.go index 82fe686c0..3dfab3538 100644 --- a/internal/manager/filename_parser.go +++ b/pkg/scene/filename_parser.go @@ -1,4 +1,4 @@ -package manager +package scene import ( "context" @@ -9,42 +9,12 @@ import ( "strings" "time" - "github.com/stashapp/stash/pkg/scene" "github.com/stashapp/stash/pkg/studio" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/tag" ) -type SceneParserInput struct { - IgnoreWords []string `json:"ignoreWords"` - WhitespaceCharacters *string `json:"whitespaceCharacters"` - CapitalizeTitle *bool `json:"capitalizeTitle"` - IgnoreOrganized *bool `json:"ignoreOrganized"` -} - -type SceneParserResult struct { - Scene *models.Scene `json:"scene"` - Title *string `json:"title"` - Code *string `json:"code"` - Details *string `json:"details"` - Director *string `json:"director"` - URL *string `json:"url"` - Date *string `json:"date"` - Rating *int `json:"rating"` - Rating100 *int `json:"rating100"` - StudioID *string `json:"studio_id"` - GalleryIds []string `json:"gallery_ids"` - PerformerIds []string `json:"performer_ids"` - Movies []*SceneMovieID `json:"movies"` - TagIds []string `json:"tag_ids"` -} - -type SceneMovieID struct { - MovieID string `json:"movie_id"` - SceneIndex *string `json:"scene_index"` -} - type parserField struct { field string fieldRegex *regexp.Regexp @@ -435,9 +405,9 @@ func (m parseMapper) parse(scene *models.Scene) *sceneHolder { return sceneHolder } -type SceneFilenameParser struct { +type FilenameParser struct { Pattern string - ParserInput SceneParserInput + ParserInput models.SceneParserInput Filter *models.FindFilterType whitespaceRE *regexp.Regexp performerCache map[string]*models.Performer @@ -446,8 +416,8 @@ type SceneFilenameParser struct { tagCache map[string]*models.Tag } -func NewSceneFilenameParser(filter *models.FindFilterType, config SceneParserInput) *SceneFilenameParser { - p := &SceneFilenameParser{ +func NewFilenameParser(filter *models.FindFilterType, config models.SceneParserInput) *FilenameParser { + p := &FilenameParser{ Pattern: *filter.Q, ParserInput: config, Filter: filter, @@ -463,7 +433,7 @@ func NewSceneFilenameParser(filter *models.FindFilterType, config SceneParserInp return p } -func (p *SceneFilenameParser) initWhiteSpaceRegex() { +func (p *FilenameParser) initWhiteSpaceRegex() { compileREs() wsChars := "" @@ -479,15 +449,15 @@ func (p *SceneFilenameParser) initWhiteSpaceRegex() { } } -type SceneFilenameParserRepository struct { - Scene scene.Queryer +type FilenameParserRepository struct { + Scene Queryer Performer PerformerNamesFinder Studio studio.Queryer Movie MovieNameFinder Tag tag.Queryer } -func (p *SceneFilenameParser) Parse(ctx context.Context, repo SceneFilenameParserRepository) ([]*SceneParserResult, int, error) { +func (p *FilenameParser) Parse(ctx context.Context, repo FilenameParserRepository) ([]*models.SceneParserResult, int, error) { // perform the query to find the scenes mapper, err := newParseMapper(p.Pattern, p.ParserInput.IgnoreWords) @@ -509,7 +479,7 @@ func (p *SceneFilenameParser) Parse(ctx context.Context, repo SceneFilenameParse p.Filter.Q = nil - scenes, total, err := scene.QueryWithCount(ctx, repo.Scene, sceneFilter, p.Filter) + scenes, total, err := QueryWithCount(ctx, repo.Scene, sceneFilter, p.Filter) if err != nil { return nil, 0, err } @@ -519,13 +489,13 @@ func (p *SceneFilenameParser) Parse(ctx context.Context, repo SceneFilenameParse return ret, total, nil } -func (p *SceneFilenameParser) parseScenes(ctx context.Context, repo SceneFilenameParserRepository, scenes []*models.Scene, mapper *parseMapper) []*SceneParserResult { - var ret []*SceneParserResult +func (p *FilenameParser) parseScenes(ctx context.Context, repo FilenameParserRepository, scenes []*models.Scene, mapper *parseMapper) []*models.SceneParserResult { + var ret []*models.SceneParserResult for _, scene := range scenes { sceneHolder := mapper.parse(scene) if sceneHolder != nil { - r := &SceneParserResult{ + r := &models.SceneParserResult{ Scene: scene, } p.setParserResult(ctx, repo, *sceneHolder, r) @@ -537,7 +507,7 @@ func (p *SceneFilenameParser) parseScenes(ctx context.Context, repo SceneFilenam return ret } -func (p SceneFilenameParser) replaceWhitespaceCharacters(value string) string { +func (p FilenameParser) replaceWhitespaceCharacters(value string) string { if p.whitespaceRE != nil { value = p.whitespaceRE.ReplaceAllString(value, " ") // remove consecutive spaces @@ -551,7 +521,7 @@ type PerformerNamesFinder interface { FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error) } -func (p *SceneFilenameParser) queryPerformer(ctx context.Context, qb PerformerNamesFinder, performerName string) *models.Performer { +func (p *FilenameParser) queryPerformer(ctx context.Context, qb PerformerNamesFinder, performerName string) *models.Performer { // massage the performer name performerName = delimiterRE.ReplaceAllString(performerName, " ") @@ -574,7 +544,7 @@ func (p *SceneFilenameParser) queryPerformer(ctx context.Context, qb PerformerNa return ret } -func (p *SceneFilenameParser) queryStudio(ctx context.Context, qb studio.Queryer, studioName string) *models.Studio { +func (p *FilenameParser) queryStudio(ctx context.Context, qb studio.Queryer, studioName string) *models.Studio { // massage the performer name studioName = delimiterRE.ReplaceAllString(studioName, " ") @@ -600,7 +570,7 @@ type MovieNameFinder interface { FindByName(ctx context.Context, name string, nocase bool) (*models.Movie, error) } -func (p *SceneFilenameParser) queryMovie(ctx context.Context, qb MovieNameFinder, movieName string) *models.Movie { +func (p *FilenameParser) queryMovie(ctx context.Context, qb MovieNameFinder, movieName string) *models.Movie { // massage the movie name movieName = delimiterRE.ReplaceAllString(movieName, " ") @@ -617,7 +587,7 @@ func (p *SceneFilenameParser) queryMovie(ctx context.Context, qb MovieNameFinder return ret } -func (p *SceneFilenameParser) queryTag(ctx context.Context, qb tag.Queryer, tagName string) *models.Tag { +func (p *FilenameParser) queryTag(ctx context.Context, qb tag.Queryer, tagName string) *models.Tag { // massage the tag name tagName = delimiterRE.ReplaceAllString(tagName, " ") @@ -640,7 +610,7 @@ func (p *SceneFilenameParser) queryTag(ctx context.Context, qb tag.Queryer, tagN return ret } -func (p *SceneFilenameParser) setPerformers(ctx context.Context, qb PerformerNamesFinder, h sceneHolder, result *SceneParserResult) { +func (p *FilenameParser) setPerformers(ctx context.Context, qb PerformerNamesFinder, h sceneHolder, result *models.SceneParserResult) { // query for each performer performersSet := make(map[int]bool) for _, performerName := range h.performers { @@ -656,7 +626,7 @@ func (p *SceneFilenameParser) setPerformers(ctx context.Context, qb PerformerNam } } -func (p *SceneFilenameParser) setTags(ctx context.Context, qb tag.Queryer, h sceneHolder, result *SceneParserResult) { +func (p *FilenameParser) setTags(ctx context.Context, qb tag.Queryer, h sceneHolder, result *models.SceneParserResult) { // query for each performer tagsSet := make(map[int]bool) for _, tagName := range h.tags { @@ -672,7 +642,7 @@ func (p *SceneFilenameParser) setTags(ctx context.Context, qb tag.Queryer, h sce } } -func (p *SceneFilenameParser) setStudio(ctx context.Context, qb studio.Queryer, h sceneHolder, result *SceneParserResult) { +func (p *FilenameParser) setStudio(ctx context.Context, qb studio.Queryer, h sceneHolder, result *models.SceneParserResult) { // query for each performer if h.studio != "" { studio := p.queryStudio(ctx, qb, h.studio) @@ -683,7 +653,7 @@ func (p *SceneFilenameParser) setStudio(ctx context.Context, qb studio.Queryer, } } -func (p *SceneFilenameParser) setMovies(ctx context.Context, qb MovieNameFinder, h sceneHolder, result *SceneParserResult) { +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 { @@ -691,7 +661,7 @@ func (p *SceneFilenameParser) setMovies(ctx context.Context, qb MovieNameFinder, movie := p.queryMovie(ctx, qb, movieName) if movie != nil { if _, found := moviesSet[movie.ID]; !found { - result.Movies = append(result.Movies, &SceneMovieID{ + result.Movies = append(result.Movies, &models.SceneMovieID{ MovieID: strconv.Itoa(movie.ID), }) moviesSet[movie.ID] = true @@ -701,7 +671,7 @@ func (p *SceneFilenameParser) setMovies(ctx context.Context, qb MovieNameFinder, } } -func (p *SceneFilenameParser) setParserResult(ctx context.Context, repo SceneFilenameParserRepository, h sceneHolder, result *SceneParserResult) { +func (p *FilenameParser) setParserResult(ctx context.Context, repo FilenameParserRepository, h sceneHolder, result *models.SceneParserResult) { if h.result.Title != "" { title := h.result.Title title = p.replaceWhitespaceCharacters(title)