Skip to content

Commit

Permalink
Gallery URLs (stashapp#4114)
Browse files Browse the repository at this point in the history
* Initial backend changes
* Fix unit tests
* UI changes
* Fix missing URL filters
  • Loading branch information
WithoutPants authored and halkeye committed Sep 1, 2024
1 parent 7006b14 commit 1eeff96
Show file tree
Hide file tree
Showing 29 changed files with 358 additions and 114 deletions.
2 changes: 1 addition & 1 deletion graphql/documents/data/gallery-slim.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ fragment SlimGalleryData on Gallery {
id
title
date
url
urls
details
rating100
organized
Expand Down
2 changes: 1 addition & 1 deletion graphql/documents/data/gallery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fragment GalleryData on Gallery {
updated_at
title
date
url
urls
details
rating100
organized
Expand Down
2 changes: 1 addition & 1 deletion graphql/documents/data/scrapers.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ fragment ScrapedSceneData on ScrapedScene {
fragment ScrapedGalleryData on ScrapedGallery {
title
details
url
urls
date

studio {
Expand Down
12 changes: 8 additions & 4 deletions graphql/schema/types/gallery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ type Gallery {
checksum: String! @deprecated(reason: "Use files.fingerprints")
path: String @deprecated(reason: "Use files.path")
title: String
url: String
url: String @deprecated(reason: "Use urls")
urls: [String!]!
date: String
details: String
# rating expressed as 1-5
Expand Down Expand Up @@ -33,7 +34,8 @@ type Gallery {

input GalleryCreateInput {
title: String!
url: String
url: String @deprecated(reason: "Use urls")
urls: [String!]
date: String
details: String
# rating expressed as 1-5
Expand All @@ -51,7 +53,8 @@ input GalleryUpdateInput {
clientMutationId: String
id: ID!
title: String
url: String
url: String @deprecated(reason: "Use urls")
urls: [String!]
date: String
details: String
# rating expressed as 1-5
Expand All @@ -70,7 +73,8 @@ input GalleryUpdateInput {
input BulkGalleryUpdateInput {
clientMutationId: String
ids: [ID!]
url: String
url: String @deprecated(reason: "Use urls")
urls: BulkUpdateStrings
date: String
details: String
# rating expressed as 1-5
Expand Down
6 changes: 4 additions & 2 deletions graphql/schema/types/scraper.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ input ScrapedSceneInput {
type ScrapedGallery {
title: String
details: String
url: String
url: String @deprecated(reason: "use urls")
urls: [String!]
date: String

studio: ScrapedStudio
Expand All @@ -111,7 +112,8 @@ type ScrapedGallery {
input ScrapedGalleryInput {
title: String
details: String
url: String
url: String @deprecated(reason: "use urls")
urls: [String!]
date: String

# no studio, tags or performers
Expand Down
29 changes: 29 additions & 0 deletions internal/api/resolver_model_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,32 @@ func (r *galleryResolver) Chapters(ctx context.Context, obj *models.Gallery) (re

return ret, nil
}

func (r *galleryResolver) URL(ctx context.Context, obj *models.Gallery) (*string, error) {
if !obj.URLs.Loaded() {
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
return obj.LoadURLs(ctx, r.repository.Gallery)
}); err != nil {
return nil, err
}
}

urls := obj.URLs.List()
if len(urls) == 0 {
return nil, nil
}

return &urls[0], nil
}

func (r *galleryResolver) Urls(ctx context.Context, obj *models.Gallery) ([]string, error) {
if !obj.URLs.Loaded() {
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
return obj.LoadURLs(ctx, r.repository.Gallery)
}); err != nil {
return nil, err
}
}

return obj.URLs.List(), nil
}
12 changes: 9 additions & 3 deletions internal/api/resolver_mutation_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func (r *mutationResolver) GalleryCreate(ctx context.Context, input GalleryCreat
newGallery := models.NewGallery()

newGallery.Title = input.Title
newGallery.URL = translator.string(input.URL)
newGallery.Details = translator.string(input.Details)
newGallery.Rating = translator.ratingConversion(input.Rating, input.Rating100)

Expand Down Expand Up @@ -71,6 +70,12 @@ func (r *mutationResolver) GalleryCreate(ctx context.Context, input GalleryCreat
return nil, fmt.Errorf("converting scene ids: %w", err)
}

if input.Urls != nil {
newGallery.URLs = models.NewRelatedStrings(input.Urls)
} else if input.URL != nil {
newGallery.URLs = models.NewRelatedStrings([]string{*input.URL})
}

// Start the transaction and save the gallery
if err := r.withTxn(ctx, func(ctx context.Context) error {
qb := r.repository.Gallery
Expand Down Expand Up @@ -178,7 +183,6 @@ func (r *mutationResolver) galleryUpdate(ctx context.Context, input models.Galle
}

updatedGallery.Details = translator.optionalString(input.Details, "details")
updatedGallery.URL = translator.optionalString(input.URL, "url")
updatedGallery.Rating = translator.optionalRatingConversion(input.Rating, input.Rating100)
updatedGallery.Organized = translator.optionalBool(input.Organized, "organized")

Expand All @@ -191,6 +195,8 @@ func (r *mutationResolver) galleryUpdate(ctx context.Context, input models.Galle
return nil, fmt.Errorf("converting studio id: %w", err)
}

updatedGallery.URLs = translator.optionalURLs(input.Urls, input.URL)

updatedGallery.PrimaryFileID, err = translator.fileIDPtrFromString(input.PrimaryFileID)
if err != nil {
return nil, fmt.Errorf("converting primary file id: %w", err)
Expand Down Expand Up @@ -252,9 +258,9 @@ func (r *mutationResolver) BulkGalleryUpdate(ctx context.Context, input BulkGall
updatedGallery := models.NewGalleryPartial()

updatedGallery.Details = translator.optionalString(input.Details, "details")
updatedGallery.URL = translator.optionalString(input.URL, "url")
updatedGallery.Rating = translator.optionalRatingConversion(input.Rating, input.Rating100)
updatedGallery.Organized = translator.optionalBool(input.Organized, "organized")
updatedGallery.URLs = translator.optionalURLsBulk(input.Urls, input.URL)

updatedGallery.Date, err = translator.optionalDate(input.Date, "date")
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/gallery/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func ToBasicJSON(gallery *models.Gallery) (*jsonschema.Gallery, error) {
newGalleryJSON := jsonschema.Gallery{
Title: gallery.Title,
URL: gallery.URL,
URLs: gallery.URLs.List(),
Details: gallery.Details,
CreatedAt: json.JSONTime{Time: gallery.CreatedAt},
UpdatedAt: json.JSONTime{Time: gallery.UpdatedAt},
Expand Down
4 changes: 2 additions & 2 deletions pkg/gallery/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func createFullGallery(id int) models.Gallery {
Details: details,
Rating: &rating,
Organized: organized,
URL: url,
URLs: models.NewRelatedStrings([]string{url}),
CreatedAt: createTime,
UpdatedAt: updateTime,
}
Expand All @@ -85,7 +85,7 @@ func createFullJSONGallery() *jsonschema.Gallery {
Details: details,
Rating: rating,
Organized: organized,
URL: url,
URLs: []string{url},
ZipFiles: []string{path},
CreatedAt: json.JSONTime{
Time: createTime,
Expand Down
6 changes: 4 additions & 2 deletions pkg/gallery/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ func (i *Importer) galleryJSONToGallery(galleryJSON jsonschema.Gallery) models.G
if galleryJSON.Details != "" {
newGallery.Details = galleryJSON.Details
}
if galleryJSON.URL != "" {
newGallery.URL = galleryJSON.URL
if len(galleryJSON.URLs) > 0 {
newGallery.URLs = models.NewRelatedStrings(galleryJSON.URLs)
} else if galleryJSON.URL != "" {
newGallery.URLs = models.NewRelatedStrings([]string{galleryJSON.URL})
}
if galleryJSON.Date != "" {
d, err := models.ParseDate(galleryJSON.Date)
Expand Down
2 changes: 1 addition & 1 deletion pkg/gallery/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestImporterPreImport(t *testing.T) {
Details: details,
Rating: &rating,
Organized: organized,
URL: url,
URLs: models.NewRelatedStrings([]string{url}),
Files: models.NewRelatedFiles([]models.File{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Expand Down
5 changes: 4 additions & 1 deletion pkg/models/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type GalleryUpdateInput struct {
ClientMutationID *string `json:"clientMutationId"`
ID string `json:"id"`
Title *string `json:"title"`
URL *string `json:"url"`
Urls []string `json:"urls"`
Date *string `json:"date"`
Details *string `json:"details"`
Rating *int `json:"rating"`
Expand All @@ -70,6 +70,9 @@ type GalleryUpdateInput struct {
TagIds []string `json:"tag_ids"`
PerformerIds []string `json:"performer_ids"`
PrimaryFileID *string `json:"primary_file_id"`

// deprecated
URL *string `json:"url"`
}

type GalleryDestroyInput struct {
Expand Down
5 changes: 4 additions & 1 deletion pkg/models/jsonschema/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Gallery struct {
ZipFiles []string `json:"zip_files,omitempty"`
FolderPath string `json:"folder_path,omitempty"`
Title string `json:"title,omitempty"`
URL string `json:"url,omitempty"`
URLs []string `json:"urls,omitempty"`
Date string `json:"date,omitempty"`
Details string `json:"details,omitempty"`
Rating int `json:"rating,omitempty"`
Expand All @@ -32,6 +32,9 @@ type Gallery struct {
Tags []string `json:"tags,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`

// deprecated - for import only
URL string `json:"url,omitempty"`
}

func (s Gallery) Filename(basename string, hash string) string {
Expand Down
23 changes: 23 additions & 0 deletions pkg/models/mocks/GalleryReaderWriter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions pkg/models/model_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ type Gallery struct {
ID int `json:"id"`

Title string `json:"title"`
URL string `json:"url"`
Date *Date `json:"date"`
Details string `json:"details"`
// Rating expressed in 1-100 scale
Expand All @@ -31,9 +30,10 @@ type Gallery struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`

SceneIDs RelatedIDs `json:"scene_ids"`
TagIDs RelatedIDs `json:"tag_ids"`
PerformerIDs RelatedIDs `json:"performer_ids"`
URLs RelatedStrings `json:"urls"`
SceneIDs RelatedIDs `json:"scene_ids"`
TagIDs RelatedIDs `json:"tag_ids"`
PerformerIDs RelatedIDs `json:"performer_ids"`
}

func NewGallery() Gallery {
Expand All @@ -51,7 +51,7 @@ type GalleryPartial struct {
// Checksum OptionalString
// Zip OptionalBool
Title OptionalString
URL OptionalString
URLs *UpdateStrings
Date OptionalDate
Details OptionalString
// Rating expressed in 1-100 scale
Expand Down Expand Up @@ -81,6 +81,12 @@ func (g *Gallery) IsUserCreated() bool {
return g.PrimaryFileID == nil && g.FolderID == nil
}

func (g *Gallery) LoadURLs(ctx context.Context, l URLLoader) error {
return g.URLs.load(func() ([]string, error) {
return l.GetURLs(ctx, g.ID)
})
}

func (g *Gallery) LoadFiles(ctx context.Context, l FileLoader) error {
return g.Files.load(func() ([]File, error) {
return l.GetFiles(ctx, g.ID)
Expand Down
1 change: 1 addition & 0 deletions pkg/models/repository_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type GalleryReader interface {
GalleryQueryer
GalleryCounter

URLLoader
FileIDLoader
ImageIDLoader
SceneIDLoader
Expand Down
16 changes: 11 additions & 5 deletions pkg/scraper/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ import "github.com/stashapp/stash/pkg/models"
type ScrapedGallery struct {
Title *string `json:"title"`
Details *string `json:"details"`
URL *string `json:"url"`
URLs []string `json:"urls"`
Date *string `json:"date"`
Studio *models.ScrapedStudio `json:"studio"`
Tags []*models.ScrapedTag `json:"tags"`
Performers []*models.ScrapedPerformer `json:"performers"`

// deprecated
URL *string `json:"url"`
}

func (ScrapedGallery) IsScrapedContent() {}

type ScrapedGalleryInput struct {
Title *string `json:"title"`
Details *string `json:"details"`
URL *string `json:"url"`
Date *string `json:"date"`
Title *string `json:"title"`
Details *string `json:"details"`
URLs []string `json:"urls"`
Date *string `json:"date"`

// deprecated
URL *string `json:"url"`
}
4 changes: 2 additions & 2 deletions pkg/scraper/query_url.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ func queryURLParametersFromGallery(gallery *models.Gallery) queryURLParameters {
ret["title"] = gallery.Title
}

if gallery.URL != "" {
ret["url"] = gallery.URL
if len(gallery.URLs.List()) > 0 {
ret["url"] = gallery.URLs.List()[0]
}

return ret
Expand Down
9 changes: 8 additions & 1 deletion pkg/scraper/stash.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,18 @@ func galleryToUpdateInput(gallery *models.Gallery) models.GalleryUpdateInput {
// fallback to file basename if title is empty
title := gallery.GetTitle()

var url *string
urls := gallery.URLs.List()
if len(urls) > 0 {
url = &urls[0]
}

return models.GalleryUpdateInput{
ID: strconv.Itoa(gallery.ID),
Title: &title,
Details: &gallery.Details,
URL: &gallery.URL,
URL: url,
Urls: urls,
Date: dateToStringPtr(gallery.Date),
}
}
Loading

0 comments on commit 1eeff96

Please sign in to comment.