Feature: Add Various Scraper Fields (#6249)

* Support aliases in stashbox studio query
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
Gykes 2025-11-12 15:14:04 -08:00 committed by GitHub
parent b2c8f09585
commit a08d2e258a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 105 additions and 8 deletions

View file

@ -59,6 +59,10 @@ type ScrapedStudio {
urls: [String!] urls: [String!]
parent: ScrapedStudio parent: ScrapedStudio
image: String image: String
details: String
"Aliases must be comma-delimited to be parsed correctly"
aliases: String
tags: [ScrapedTag!]
remote_site_id: String remote_site_id: String
} }

View file

@ -13,6 +13,7 @@ fragment ImageFragment on Image {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
...URLFragment ...URLFragment
} }

View file

@ -19,6 +19,9 @@ type ScrapedStudio struct {
Parent *ScrapedStudio `json:"parent"` Parent *ScrapedStudio `json:"parent"`
Image *string `json:"image"` Image *string `json:"image"`
Images []string `json:"images"` Images []string `json:"images"`
Details *string `json:"details"`
Aliases *string `json:"aliases"`
Tags []*ScrapedTag `json:"tags"`
RemoteSiteID *string `json:"remote_site_id"` RemoteSiteID *string `json:"remote_site_id"`
} }
@ -55,6 +58,14 @@ func (s *ScrapedStudio) ToStudio(endpoint string, excluded map[string]bool) *Stu
} }
} }
if s.Details != nil && !excluded["details"] {
ret.Details = *s.Details
}
if s.Aliases != nil && !excluded["aliases"] {
ret.Aliases = NewRelatedStrings(stringslice.FromString(*s.Aliases, ","))
}
if s.Parent != nil && s.Parent.StoredID != nil && !excluded["parent"] && !excluded["parent_studio"] { if s.Parent != nil && s.Parent.StoredID != nil && !excluded["parent"] && !excluded["parent_studio"] {
parentId, _ := strconv.Atoi(*s.Parent.StoredID) parentId, _ := strconv.Atoi(*s.Parent.StoredID)
ret.ParentID = &parentId ret.ParentID = &parentId
@ -108,6 +119,17 @@ func (s *ScrapedStudio) ToPartial(id string, endpoint string, excluded map[strin
} }
} }
if s.Details != nil && !excluded["details"] {
ret.Details = NewOptionalString(*s.Details)
}
if s.Aliases != nil && !excluded["aliases"] {
ret.Aliases = &UpdateStrings{
Values: stringslice.FromString(*s.Aliases, ","),
Mode: RelationshipUpdateModeSet,
}
}
if s.Parent != nil && !excluded["parent"] { if s.Parent != nil && !excluded["parent"] {
if s.Parent.StoredID != nil { if s.Parent.StoredID != nil {
parentID, _ := strconv.Atoi(*s.Parent.StoredID) parentID, _ := strconv.Atoi(*s.Parent.StoredID)

View file

@ -82,11 +82,12 @@ func (t *ImageFragment) GetHeight() int {
} }
type StudioFragment struct { type StudioFragment struct {
Name string "json:\"name\" graphql:\"name\"" Name string "json:\"name\" graphql:\"name\""
ID string "json:\"id\" graphql:\"id\"" ID string "json:\"id\" graphql:\"id\""
Urls []*URLFragment "json:\"urls\" graphql:\"urls\"" Aliases []string "json:\"aliases\" graphql:\"aliases\""
Parent *StudioFragment_Parent "json:\"parent,omitempty\" graphql:\"parent\"" Urls []*URLFragment "json:\"urls\" graphql:\"urls\""
Images []*ImageFragment "json:\"images\" graphql:\"images\"" Parent *StudioFragment_Parent "json:\"parent,omitempty\" graphql:\"parent\""
Images []*ImageFragment "json:\"images\" graphql:\"images\""
} }
func (t *StudioFragment) GetName() string { func (t *StudioFragment) GetName() string {
@ -101,6 +102,12 @@ func (t *StudioFragment) GetID() string {
} }
return t.ID return t.ID
} }
func (t *StudioFragment) GetAliases() []string {
if t == nil {
t = &StudioFragment{}
}
return t.Aliases
}
func (t *StudioFragment) GetUrls() []*URLFragment { func (t *StudioFragment) GetUrls() []*URLFragment {
if t == nil { if t == nil {
t = &StudioFragment{} t = &StudioFragment{}
@ -845,6 +852,7 @@ fragment ImageFragment on Image {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
... URLFragment ... URLFragment
} }
@ -980,6 +988,7 @@ fragment ImageFragment on Image {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
... URLFragment ... URLFragment
} }
@ -1115,6 +1124,7 @@ fragment ImageFragment on Image {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
... URLFragment ... URLFragment
} }
@ -1250,6 +1260,7 @@ fragment ImageFragment on Image {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
... URLFragment ... URLFragment
} }
@ -1543,6 +1554,7 @@ fragment ImageFragment on Image {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
... URLFragment ... URLFragment
} }
@ -1641,6 +1653,7 @@ const FindStudioDocument = `query FindStudio ($id: ID, $name: String) {
fragment StudioFragment on Studio { fragment StudioFragment on Studio {
name name
id id
aliases
urls { urls {
... URLFragment ... URLFragment
} }

View file

@ -2,6 +2,7 @@ package stashbox
import ( import (
"context" "context"
"strings"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models"
@ -63,8 +64,11 @@ func studioFragmentToScrapedStudio(s graphql.StudioFragment) *models.ScrapedStud
images = append(images, image.URL) images = append(images, image.URL)
} }
aliases := strings.Join(s.Aliases, ", ")
st := &models.ScrapedStudio{ st := &models.ScrapedStudio{
Name: s.Name, Name: s.Name,
Aliases: &aliases,
Images: images, Images: images,
RemoteSiteID: &s.ID, RemoteSiteID: &s.ID,
} }

View file

@ -7,9 +7,19 @@ fragment ScrapedStudioData on ScrapedStudio {
name name
urls urls
image image
details
aliases
tags {
...ScrapedSceneTagData
}
remote_site_id remote_site_id
} }
image image
details
aliases
tags {
...ScrapedSceneTagData
}
remote_site_id remote_site_id
} }
@ -129,9 +139,19 @@ fragment ScrapedSceneStudioData on ScrapedStudio {
name name
urls urls
image image
details
aliases
tags {
...ScrapedSceneTagData
}
remote_site_id remote_site_id
} }
image image
details
aliases
tags {
...ScrapedSceneTagData
}
remote_site_id remote_site_id
} }

View file

@ -41,7 +41,9 @@ export const ScrapedStudioRow: React.FC<IScrapedStudioRow> = ({
const value = resultValue ? [resultValue] : []; const value = resultValue ? [resultValue] : [];
const selectValue = value.map((p) => { const selectValue = value.map((p) => {
const aliases: string[] = []; const aliases: string[] = p.aliases
? p.aliases.split(",").map((a) => a.trim())
: [];
return { return {
id: p.stored_id ?? "", id: p.stored_id ?? "",
name: p.name ?? "", name: p.name ?? "",
@ -55,10 +57,11 @@ export const ScrapedStudioRow: React.FC<IScrapedStudioRow> = ({
isDisabled={!isNew} isDisabled={!isNew}
onSelect={(items) => { onSelect={(items) => {
if (onChangeFn) { if (onChangeFn) {
const { id, ...data } = items[0]; const { id, aliases, ...data } = items[0];
onChangeFn({ onChangeFn({
...data, ...data,
stored_id: id, stored_id: id,
aliases: aliases?.join(", "),
}); });
} }
}} }}

View file

@ -142,6 +142,9 @@ const StudioDetails: React.FC<IStudioDetailsProps> = ({
<div className="col-12"> <div className="col-12">
{maybeRenderField("name", studio.name, !isNew)} {maybeRenderField("name", studio.name, !isNew)}
{maybeRenderURLListField("urls", studio.urls)} {maybeRenderURLListField("urls", studio.urls)}
{maybeRenderField("details", studio.details)}
{maybeRenderField("aliases", studio.aliases)}
{maybeRenderField("tags", studio.tags?.map((t) => t.name).join(", "))}
{maybeRenderField("parent_studio", studio.parent?.name, false)} {maybeRenderField("parent_studio", studio.parent?.name, false)}
{maybeRenderStashBoxLink()} {maybeRenderStashBoxLink()}
</div> </div>
@ -232,6 +235,11 @@ const StudioModal: React.FC<IStudioModalProps> = ({
urls: studio.urls, urls: studio.urls,
image: studio.image, image: studio.image,
parent_id: studio.parent?.stored_id, parent_id: studio.parent?.stored_id,
details: studio.details,
aliases: studio.aliases?.split(",").map((a) => a.trim()),
tag_ids: studio.tags?.map((t) => t.stored_id).filter((id) => id) as
| string[]
| undefined,
}; };
// stashid handling code // stashid handling code
@ -261,6 +269,11 @@ const StudioModal: React.FC<IStudioModalProps> = ({
name: studio.parent?.name, name: studio.parent?.name,
urls: studio.parent?.urls, urls: studio.parent?.urls,
image: studio.parent?.image, image: studio.parent?.image,
details: studio.parent?.details,
aliases: studio.parent?.aliases?.split(",").map((a) => a.trim()),
tag_ids: studio.parent?.tags
?.map((t) => t.stored_id)
.filter((id) => id) as string[] | undefined,
}; };
// stashid handling code // stashid handling code

View file

@ -739,7 +739,11 @@ xPathScrapers:
URL: $performer/@href URL: $performer/@href
Studio: Studio:
Name: $studio Name: $studio
URL: $studio/@href URL: $studio/@href
Details: //div[@class="studioDescription"]
Aliases: //div[@class="studioAliases"]/span
Tags:
Name: //div[@class="studioTags"]/a
``` ```
See also [#333](https://github.com/stashapp/stash/pull/333) for more examples. See also [#333](https://github.com/stashapp/stash/pull/333) for more examples.
@ -822,6 +826,11 @@ jsonScrapers:
Name: data.performers.#.name Name: data.performers.#.name
Studio: Studio:
Name: data.site.name Name: data.site.name
URL: data.site.url
Details: data.site.description
Aliases: data.site.aliases
Tags:
Name: data.site.tags.#.name
Tags: Tags:
Name: data.tags.#.tag Name: data.tags.#.tag
@ -839,6 +848,11 @@ jsonScrapers:
Name: $data.performers.#.name Name: $data.performers.#.name
Studio: Studio:
Name: $data.site.name Name: $data.site.name
URL: $data.site.url
Details: $data.site.description
Aliases: $data.site.aliases
Tags:
Name: $data.site.tags.#.name
Tags: Tags:
Name: $data.tags.#.tag Name: $data.tags.#.tag
driver: driver:
@ -955,7 +969,10 @@ URLs
### Studio ### Studio
``` ```
Aliases
Details
Name Name
Tags (see Tag fields)
URL URL
``` ```