From d68d022893aee62c5a3f4c81fefe9098f5309fc4 Mon Sep 17 00:00:00 2001 From: InfiniteTF Date: Wed, 1 Jun 2022 06:53:31 +0200 Subject: [PATCH] Add support for submitting stash-box scene updates by draft (#2577) --- .../stashbox/graphql/generated_client.go | 512 +++++++++--------- .../stashbox/graphql/generated_models.go | 6 +- pkg/scraper/stashbox/graphql/override.go | 1 + pkg/scraper/stashbox/stash_box.go | 26 + .../src/components/Changelog/Changelog.tsx | 10 +- .../components/Changelog/versions/v0160.md | 5 + .../src/components/Dialogs/SubmitDraft.tsx | 35 +- ui/v2.5/src/locales/en-GB.json | 4 +- 8 files changed, 332 insertions(+), 267 deletions(-) create mode 100644 ui/v2.5/src/components/Changelog/versions/v0160.md diff --git a/pkg/scraper/stashbox/graphql/generated_client.go b/pkg/scraper/stashbox/graphql/generated_client.go index 248f3e711..a41380740 100644 --- a/pkg/scraper/stashbox/graphql/generated_client.go +++ b/pkg/scraper/stashbox/graphql/generated_client.go @@ -239,6 +239,52 @@ fragment URLFragment on URL { url type } +fragment ImageFragment on Image { + id + url + width + height +} +fragment TagFragment on Tag { + name + id +} +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration +} +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ... URLFragment + } + images { + ... ImageFragment + } + studio { + ... StudioFragment + } + tags { + ... TagFragment + } + performers { + ... PerformerAppearanceFragment + } + fingerprints { + ... FingerprintFragment + } +} fragment StudioFragment on Studio { name id @@ -249,9 +295,11 @@ fragment StudioFragment on Studio { ... ImageFragment } } -fragment TagFragment on Tag { - name - id +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment + } } fragment PerformerFragment on Performer { id @@ -287,61 +335,13 @@ fragment PerformerFragment on Performer { ... BodyModificationFragment } } -fragment BodyModificationFragment on BodyModification { - location - description -} -fragment FingerprintFragment on Fingerprint { - algorithm - hash - duration -} -fragment SceneFragment on Scene { - id - title - details - duration - date - urls { - ... URLFragment - } - images { - ... ImageFragment - } - studio { - ... StudioFragment - } - tags { - ... TagFragment - } - performers { - ... PerformerAppearanceFragment - } - fingerprints { - ... FingerprintFragment - } -} -fragment ImageFragment on Image { - id - url - width - height -} -fragment PerformerAppearanceFragment on PerformerAppearance { - as - performer { - ... PerformerFragment - } -} fragment FuzzyDateFragment on FuzzyDate { date accuracy } -fragment MeasurementsFragment on Measurements { - band_size - cup_size - waist - hip +fragment BodyModificationFragment on BodyModification { + location + description } ` @@ -363,6 +363,35 @@ const FindScenesByFullFingerprintsDocument = `query FindScenesByFullFingerprints ... SceneFragment } } +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ... URLFragment + } + images { + ... ImageFragment + } + studio { + ... StudioFragment + } + tags { + ... TagFragment + } + performers { + ... PerformerAppearanceFragment + } + fingerprints { + ... FingerprintFragment + } +} +fragment URLFragment on URL { + url + type +} fragment StudioFragment on Studio { name id @@ -373,6 +402,27 @@ fragment StudioFragment on Studio { ... ImageFragment } } +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment + } +} +fragment BodyModificationFragment on BodyModification { + location + description +} +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration +} +fragment ImageFragment on Image { + id + url + width + height +} fragment TagFragment on Tag { name id @@ -415,62 +465,12 @@ fragment FuzzyDateFragment on FuzzyDate { date accuracy } -fragment BodyModificationFragment on BodyModification { - location - description -} -fragment FingerprintFragment on Fingerprint { - algorithm - hash - duration -} -fragment SceneFragment on Scene { - id - title - details - duration - date - urls { - ... URLFragment - } - images { - ... ImageFragment - } - studio { - ... StudioFragment - } - tags { - ... TagFragment - } - performers { - ... PerformerAppearanceFragment - } - fingerprints { - ... FingerprintFragment - } -} -fragment ImageFragment on Image { - id - url - width - height -} fragment MeasurementsFragment on Measurements { band_size cup_size waist hip } -fragment URLFragment on URL { - url - type -} -fragment PerformerAppearanceFragment on PerformerAppearance { - as - performer { - ... PerformerFragment - } -} ` func (c *Client) FindScenesByFullFingerprints(ctx context.Context, fingerprints []*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesByFullFingerprints, error) { @@ -491,6 +491,26 @@ const FindScenesBySceneFingerprintsDocument = `query FindScenesBySceneFingerprin ... SceneFragment } } +fragment URLFragment on URL { + url + type +} +fragment ImageFragment on Image { + id + url + width + height +} +fragment StudioFragment on Studio { + name + id + urls { + ... URLFragment + } + images { + ... ImageFragment + } +} fragment PerformerFragment on Performer { id name @@ -531,49 +551,11 @@ fragment MeasurementsFragment on Measurements { waist hip } -fragment BodyModificationFragment on BodyModification { - location - description -} fragment FingerprintFragment on Fingerprint { algorithm hash duration } -fragment ImageFragment on Image { - id - url - width - height -} -fragment URLFragment on URL { - url - type -} -fragment StudioFragment on Studio { - name - id - urls { - ... URLFragment - } - images { - ... ImageFragment - } -} -fragment TagFragment on Tag { - name - id -} -fragment PerformerAppearanceFragment on PerformerAppearance { - as - performer { - ... PerformerFragment - } -} -fragment FuzzyDateFragment on FuzzyDate { - date - accuracy -} fragment SceneFragment on Scene { id title @@ -599,6 +581,24 @@ fragment SceneFragment on Scene { ... FingerprintFragment } } +fragment TagFragment on Tag { + name + id +} +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment + } +} +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} +fragment BodyModificationFragment on BodyModification { + location + description +} ` func (c *Client) FindScenesBySceneFingerprints(ctx context.Context, fingerprints [][]*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesBySceneFingerprints, error) { @@ -619,10 +619,41 @@ const SearchSceneDocument = `query SearchScene ($term: String!) { ... SceneFragment } } +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ... URLFragment + } + images { + ... ImageFragment + } + studio { + ... StudioFragment + } + tags { + ... TagFragment + } + performers { + ... PerformerAppearanceFragment + } + fingerprints { + ... FingerprintFragment + } +} fragment URLFragment on URL { url type } +fragment ImageFragment on Image { + id + url + width + height +} fragment TagFragment on Tag { name id @@ -661,30 +692,14 @@ fragment PerformerFragment on Performer { ... BodyModificationFragment } } -fragment SceneFragment on Scene { - id - title - details - duration +fragment FuzzyDateFragment on FuzzyDate { date - urls { - ... URLFragment - } - images { - ... ImageFragment - } - studio { - ... StudioFragment - } - tags { - ... TagFragment - } - performers { - ... PerformerAppearanceFragment - } - fingerprints { - ... FingerprintFragment - } + accuracy +} +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration } fragment StudioFragment on Studio { name @@ -702,10 +717,6 @@ fragment PerformerAppearanceFragment on PerformerAppearance { ... PerformerFragment } } -fragment FuzzyDateFragment on FuzzyDate { - date - accuracy -} fragment MeasurementsFragment on Measurements { band_size cup_size @@ -716,17 +727,6 @@ fragment BodyModificationFragment on BodyModification { location description } -fragment FingerprintFragment on Fingerprint { - algorithm - hash - duration -} -fragment ImageFragment on Image { - id - url - width - height -} ` func (c *Client) SearchScene(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchScene, error) { @@ -747,20 +747,6 @@ const SearchPerformerDocument = `query SearchPerformer ($term: String!) { ... PerformerFragment } } -fragment FuzzyDateFragment on FuzzyDate { - date - accuracy -} -fragment MeasurementsFragment on Measurements { - band_size - cup_size - waist - hip -} -fragment BodyModificationFragment on BodyModification { - location - description -} fragment PerformerFragment on Performer { id name @@ -805,6 +791,20 @@ fragment ImageFragment on Image { width height } +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} +fragment BodyModificationFragment on BodyModification { + location + description +} ` func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) { @@ -825,20 +825,6 @@ const FindPerformerByIDDocument = `query FindPerformerByID ($id: ID!) { ... PerformerFragment } } -fragment FuzzyDateFragment on FuzzyDate { - date - accuracy -} -fragment MeasurementsFragment on Measurements { - band_size - cup_size - waist - hip -} -fragment BodyModificationFragment on BodyModification { - location - description -} fragment PerformerFragment on Performer { id name @@ -883,6 +869,20 @@ fragment ImageFragment on Image { width height } +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} +fragment BodyModificationFragment on BodyModification { + location + description +} ` func (c *Client) FindPerformerByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindPerformerByID, error) { @@ -903,6 +903,14 @@ const FindSceneByIDDocument = `query FindSceneByID ($id: ID!) { ... SceneFragment } } +fragment BodyModificationFragment on BodyModification { + location + description +} +fragment URLFragment on URL { + url + type +} fragment ImageFragment on Image { id url @@ -913,11 +921,43 @@ fragment TagFragment on Tag { name id } -fragment PerformerAppearanceFragment on PerformerAppearance { - as - performer { - ... PerformerFragment +fragment PerformerFragment on Performer { + id + name + disambiguation + aliases + gender + merged_ids + urls { + ... URLFragment } + images { + ... ImageFragment + } + birthdate { + ... FuzzyDateFragment + } + ethnicity + country + eye_color + hair_color + height + measurements { + ... MeasurementsFragment + } + breast_type + career_start_year + career_end_year + tattoos { + ... BodyModificationFragment + } + piercings { + ... BodyModificationFragment + } +} +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy } fragment MeasurementsFragment on Measurements { band_size @@ -925,10 +965,6 @@ fragment MeasurementsFragment on Measurements { waist hip } -fragment BodyModificationFragment on BodyModification { - location - description -} fragment SceneFragment on Scene { id title @@ -954,10 +990,6 @@ fragment SceneFragment on Scene { ... FingerprintFragment } } -fragment URLFragment on URL { - url - type -} fragment StudioFragment on Studio { name id @@ -968,43 +1000,11 @@ fragment StudioFragment on Studio { ... ImageFragment } } -fragment PerformerFragment on Performer { - id - name - disambiguation - aliases - gender - merged_ids - urls { - ... URLFragment +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment } - images { - ... ImageFragment - } - birthdate { - ... FuzzyDateFragment - } - ethnicity - country - eye_color - hair_color - height - measurements { - ... MeasurementsFragment - } - breast_type - career_start_year - career_end_year - tattoos { - ... BodyModificationFragment - } - piercings { - ... BodyModificationFragment - } -} -fragment FuzzyDateFragment on FuzzyDate { - date - accuracy } fragment FingerprintFragment on Fingerprint { algorithm diff --git a/pkg/scraper/stashbox/graphql/generated_models.go b/pkg/scraper/stashbox/graphql/generated_models.go index cfa893c23..341f91d14 100644 --- a/pkg/scraper/stashbox/graphql/generated_models.go +++ b/pkg/scraper/stashbox/graphql/generated_models.go @@ -88,8 +88,8 @@ type DraftEntity struct { ID *string `json:"id,omitempty"` } -func (DraftEntity) IsSceneDraftStudio() {} func (DraftEntity) IsSceneDraftPerformer() {} +func (DraftEntity) IsSceneDraftStudio() {} func (DraftEntity) IsSceneDraftTag() {} type DraftEntityInput struct { @@ -339,8 +339,8 @@ type Performer struct { Updated time.Time `json:"updated"` } -func (Performer) IsEditTarget() {} func (Performer) IsSceneDraftPerformer() {} +func (Performer) IsEditTarget() {} type PerformerAppearance struct { Performer *Performer `json:"performer,omitempty"` @@ -846,8 +846,8 @@ type Studio struct { Updated time.Time `json:"updated"` } -func (Studio) IsSceneDraftStudio() {} func (Studio) IsEditTarget() {} +func (Studio) IsSceneDraftStudio() {} type StudioCreateInput struct { Name string `json:"name"` diff --git a/pkg/scraper/stashbox/graphql/override.go b/pkg/scraper/stashbox/graphql/override.go index 492a55a06..d80b74307 100644 --- a/pkg/scraper/stashbox/graphql/override.go +++ b/pkg/scraper/stashbox/graphql/override.go @@ -5,6 +5,7 @@ import "github.com/99designs/gqlgen/graphql" // Override for generated struct due to mistaken omitempty // https://github.com/Yamashou/gqlgenc/issues/77 type SceneDraftInput struct { + ID *string `json:"id,omitempty"` Title *string `json:"title,omitempty"` Details *string `json:"details,omitempty"` URL *string `json:"url,omitempty"` diff --git a/pkg/scraper/stashbox/stash_box.go b/pkg/scraper/stashbox/stash_box.go index 105fe3d24..232bfdba5 100644 --- a/pkg/scraper/stashbox/stash_box.go +++ b/pkg/scraper/stashbox/stash_box.go @@ -825,6 +825,19 @@ func (c Client) SubmitSceneDraft(ctx context.Context, sceneID int, endpoint stri } } + stashIDs, err := qb.GetStashIDs(sceneID) + if err != nil { + return err + } + var stashID *string + for _, v := range stashIDs { + if v.Endpoint == endpoint { + stashID = &v.StashID + break + } + } + draft.ID = stashID + return nil }); err != nil { return nil, err @@ -910,6 +923,19 @@ func (c Client) SubmitPerformerDraft(ctx context.Context, performer *models.Perf draft.Urls = urls } + stashIDs, err := pqb.GetStashIDs(performer.ID) + if err != nil { + return err + } + var stashID *string + for _, v := range stashIDs { + if v.Endpoint == endpoint { + stashID = &v.StashID + break + } + } + draft.ID = stashID + return nil }); err != nil { return nil, err diff --git a/ui/v2.5/src/components/Changelog/Changelog.tsx b/ui/v2.5/src/components/Changelog/Changelog.tsx index 030d581dc..2a970fdb1 100644 --- a/ui/v2.5/src/components/Changelog/Changelog.tsx +++ b/ui/v2.5/src/components/Changelog/Changelog.tsx @@ -19,6 +19,7 @@ import V0130 from "./versions/v0130.md"; import V0131 from "./versions/v0131.md"; import V0140 from "./versions/v0140.md"; import V0150 from "./versions/v0150.md"; +import V0160 from "./versions/v0160.md"; import { MarkdownPage } from "../Shared/MarkdownPage"; // to avoid use of explicit any @@ -57,9 +58,9 @@ const Changelog: React.FC = () => { // after new release: // add entry to releases, using the current* fields // then update the current fields. - const currentVersion = stashVersion || "v0.15.0"; + const currentVersion = stashVersion || "v0.16.0"; const currentDate = buildDate; - const currentPage = V0150; + const currentPage = V0160; const releases: IStashRelease[] = [ { @@ -68,6 +69,11 @@ const Changelog: React.FC = () => { page: currentPage, defaultOpen: true, }, + { + version: "v0.15.0", + date: "2022-05-18", + page: V0150, + }, { version: "v0.14.0", date: "2022-04-11", diff --git a/ui/v2.5/src/components/Changelog/versions/v0160.md b/ui/v2.5/src/components/Changelog/versions/v0160.md new file mode 100644 index 000000000..61a4dd282 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/v0160.md @@ -0,0 +1,5 @@ +### ✨ New Features +* Support submitting stash-box scene updates for scenes with stash ids. ([#2577](https://github.com/stashapp/stash/pull/2577)) + +### 🐛 Bug fixes +* Fix moved gallery zip files not being rescanned. ([#2611](https://github.com/stashapp/stash/pull/2611)) \ No newline at end of file diff --git a/ui/v2.5/src/components/Dialogs/SubmitDraft.tsx b/ui/v2.5/src/components/Dialogs/SubmitDraft.tsx index c3eceae8b..6fb6d81fa 100644 --- a/ui/v2.5/src/components/Dialogs/SubmitDraft.tsx +++ b/ui/v2.5/src/components/Dialogs/SubmitDraft.tsx @@ -8,7 +8,12 @@ import { FormattedMessage, useIntl } from "react-intl"; interface IProps { show: boolean; - entity: { name?: string | null; id: string; title?: string | null }; + entity: { + name?: string | null; + id: string; + title?: string | null; + stash_ids: { stash_id: string; endpoint: string }[]; + }; boxes: Pick[]; query: DocumentNode; onHide: () => void; @@ -59,6 +64,12 @@ export const SubmitStashBoxDraft: React.FC = ({ const handleSelectBox = (e: React.ChangeEvent) => setSelectedBox(Number.parseInt(e.currentTarget.value) ?? 0); + // If the scene has an attached stash_id from that endpoint, the operation will be an update + const isUpdate = + entity.stash_ids.find( + (id) => id.endpoint === boxes[selectedBox].endpoint + ) !== undefined; + return ( = ({ ))} - +
+ {isUpdate && ( + + + + )} + +
) : ( <> diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index 31ddca247..daba6cde8 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -106,6 +106,7 @@ "view_random": "View Random", "continue": "Continue", "submit": "Submit", + "submit_update": "Submit update", "logout": "Log out", "remove_from_gallery": "Remove from Gallery", "delete_stashid": "Delete StashID", @@ -976,7 +977,8 @@ "selected_stash_box": "Selected Stash-Box endpoint", "submission_successful": "Submission successful", "submission_failed": "Submission failed", - "go_review_draft": "Go to {endpoint_name} to review draft." + "go_review_draft": "Go to {endpoint_name} to review draft.", + "submit_update": "Already exists in {endpoint_name}" }, "performer_tagger": { "network_error": "Network Error",