diff --git a/graphql/documents/data/scrapers.graphql b/graphql/documents/data/scrapers.graphql index f9fa5a879..b84fabfc9 100644 --- a/graphql/documents/data/scrapers.graphql +++ b/graphql/documents/data/scrapers.graphql @@ -23,6 +23,7 @@ fragment ScrapedPerformerData on ScrapedPerformer { death_date hair_color weight + remote_site_id } fragment ScrapedScenePerformerData on ScrapedScenePerformer { diff --git a/graphql/schema/types/scraped-performer.graphql b/graphql/schema/types/scraped-performer.graphql index db6c216a3..2ae1b5a8a 100644 --- a/graphql/schema/types/scraped-performer.graphql +++ b/graphql/schema/types/scraped-performer.graphql @@ -25,6 +25,7 @@ type ScrapedPerformer { death_date: String hair_color: String weight: String + remote_site_id: String } input ScrapedPerformerInput { @@ -51,4 +52,5 @@ input ScrapedPerformerInput { death_date: String hair_color: String weight: String + remote_site_id: String } \ No newline at end of file diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index 0c102bcbe..230fd0ba0 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -46,6 +46,7 @@ type ScrapedPerformer struct { DeathDate *string `graphql:"death_date" json:"death_date"` HairColor *string `graphql:"hair_color" json:"hair_color"` Weight *string `graphql:"weight" json:"weight"` + RemoteSiteID *string `graphql:"remote_site_id" json:"remote_site_id"` } // this type has no Image field diff --git a/ui/v2.5/src/components/Changelog/versions/v090.md b/ui/v2.5/src/components/Changelog/versions/v090.md index f094ae916..eea9b6ea6 100644 --- a/ui/v2.5/src/components/Changelog/versions/v090.md +++ b/ui/v2.5/src/components/Changelog/versions/v090.md @@ -7,6 +7,7 @@ * Added de-DE language option. ([#1578](https://github.com/stashapp/stash/pull/1578)) ### 🐛 Bug fixes +* Include stash id when scraping performer from stash-box. ([#1608](https://github.com/stashapp/stash/pull/1608)) * Fix infinity framerate values causing resolver error. ([#1607](https://github.com/stashapp/stash/pull/1607)) * Fix unsetting performer gender not working correctly. ([#1606](https://github.com/stashapp/stash/pull/1606)) * Fix is missing date scene criterion causing invalid SQL. ([#1577](https://github.com/stashapp/stash/pull/1577)) diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx index da024bb0e..17480cf84 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx @@ -74,6 +74,7 @@ export const PerformerEditPanel: React.FC = ({ // Editing state const [scraper, setScraper] = useState(); const [newTags, setNewTags] = useState(); + const [isScraperModalOpen, setIsScraperModalOpen] = useState(false); const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); // Network state @@ -351,6 +352,19 @@ export const PerformerEditPanel: React.FC = ({ if (state.weight) { formik.setFieldValue("weight", state.weight); } + + const remoteSiteID = state.remote_site_id; + if (remoteSiteID && (scraper as IStashBox).endpoint) { + const newIDs = + formik.values.stash_ids?.filter( + (s) => s.endpoint !== (scraper as IStashBox).endpoint + ) ?? []; + newIDs?.push({ + endpoint: (scraper as IStashBox).endpoint, + stash_id: remoteSiteID, + }); + formik.setFieldValue("stash_ids", newIDs); + } } function onImageLoad(imageData: string) { @@ -507,7 +521,7 @@ export const PerformerEditPanel: React.FC = ({ selectedPerformer: GQL.ScrapedPerformerDataFragment, selectedScraper: GQL.Scraper ) { - setScraper(undefined); + setIsScraperModalOpen(false); try { if (!scraper) return; setIsLoading(true); @@ -525,6 +539,7 @@ export const PerformerEditPanel: React.FC = ({ // if this is a new performer, just dump the data if (isNew) { updatePerformerEditStateFromScraper(result.data.scrapePerformer); + setScraper(undefined); } else { setScrapedPerformer(result.data.scrapePerformer); } @@ -559,7 +574,7 @@ export const PerformerEditPanel: React.FC = ({ } async function onScrapeStashBox(performerResult: GQL.ScrapedScenePerformer) { - setScraper(undefined); + setIsScraperModalOpen(false); const result: Partial = { ...performerResult, @@ -571,11 +586,17 @@ export const PerformerEditPanel: React.FC = ({ // if this is a new performer, just dump the data if (isNew) { updatePerformerEditStateFromScraper(result); + setScraper(undefined); } else { setScrapedPerformer(result); } } + function onScraperSelected(s: GQL.Scraper | IStashBox | undefined) { + setScraper(s); + setIsScraperModalOpen(true); + } + function renderScraperMenu() { if (!performer) { return; @@ -590,7 +611,7 @@ export const PerformerEditPanel: React.FC = ({
@@ -602,7 +623,7 @@ export const PerformerEditPanel: React.FC = ({ @@ -648,7 +669,7 @@ export const PerformerEditPanel: React.FC = ({ } function maybeRenderScrapeDialog() { - if (!scrapedPerformer) { + if (!scrapedPerformer || !scraper) { return; } @@ -663,6 +684,7 @@ export const PerformerEditPanel: React.FC = ({ { onScrapeDialogClosed(p); }} @@ -675,6 +697,7 @@ export const PerformerEditPanel: React.FC = ({ updatePerformerEditStateFromScraper(p); } setScrapedPerformer(undefined); + setScraper(undefined); } function maybeRenderScrapeButton() { @@ -731,8 +754,10 @@ export const PerformerEditPanel: React.FC = ({ ); } - const renderScrapeModal = () => - scraper !== undefined && isScraper(scraper) ? ( + const renderScrapeModal = () => { + if (!isScraperModalOpen) return; + + return scraper !== undefined && isScraper(scraper) ? ( setScraper(undefined)} @@ -747,6 +772,7 @@ export const PerformerEditPanel: React.FC = ({ name={formik.values.name || ""} /> ) : undefined; + }; function renderDeleteAlert() { return ( diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx index af9e8f436..fd90cf433 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx @@ -19,6 +19,7 @@ import { genderToString, stringToGender, } from "src/utils/gender"; +import { IStashBox } from "./PerformerStashBoxModal"; function renderScrapedGender( result: ScrapeResult, @@ -119,6 +120,7 @@ function renderScrapedTagsRow( interface IPerformerScrapeDialogProps { performer: Partial; scraped: GQL.ScrapedPerformer; + scraper?: GQL.Scraper | IStashBox; onClose: (scrapedPerformer?: GQL.ScrapedPerformer) => void; } @@ -128,6 +130,17 @@ export const PerformerScrapeDialog: React.FC = ( ) => { const intl = useIntl(); + const endpoint = (props.scraper as IStashBox).endpoint ?? undefined; + + function getCurrentRemoteSiteID() { + if (!endpoint) { + return; + } + + return props.performer.stash_ids?.find((s) => s.endpoint === endpoint) + ?.stash_id; + } + function translateScrapedGender(scrapedGender?: string | null) { if (!scrapedGender) { return; @@ -227,6 +240,12 @@ export const PerformerScrapeDialog: React.FC = ( const [details, setDetails] = useState>( new ScrapeResult(props.performer.details, props.scraped.details) ); + const [remoteSiteID, setRemoteSiteID] = useState>( + new ScrapeResult( + getCurrentRemoteSiteID(), + props.scraped.remote_site_id + ) + ); const [createTag] = useTagCreate(); const Toast = useToast(); @@ -311,6 +330,7 @@ export const PerformerScrapeDialog: React.FC = ( deathDate, hairColor, weight, + remoteSiteID, ]; // don't show the dialog if nothing was scraped if (allFields.every((r) => !r.scraped)) { @@ -383,6 +403,7 @@ export const PerformerScrapeDialog: React.FC = ( death_date: deathDate.getNewValue(), hair_color: hairColor.getNewValue(), weight: weight.getNewValue(), + remote_site_id: remoteSiteID.getNewValue(), }; } @@ -502,6 +523,12 @@ export const PerformerScrapeDialog: React.FC = ( result={image} onChange={(value) => setImage(value)} /> + setRemoteSiteID(value)} + /> ); } diff --git a/ui/v2.5/src/components/Shared/ScrapeDialog.tsx b/ui/v2.5/src/components/Shared/ScrapeDialog.tsx index f2615f102..44d3ca65a 100644 --- a/ui/v2.5/src/components/Shared/ScrapeDialog.tsx +++ b/ui/v2.5/src/components/Shared/ScrapeDialog.tsx @@ -175,6 +175,7 @@ export const ScrapeDialogRow = ( interface IScrapedInputGroupProps { isNew?: boolean; placeholder?: string; + locked?: boolean; result: ScrapeResult; onChange?: (value: string) => void; } @@ -184,7 +185,7 @@ const ScrapedInputGroup: React.FC = (props) => { { if (props.isNew && props.onChange) { props.onChange(e.target.value); @@ -199,6 +200,7 @@ interface IScrapedInputGroupRowProps { title: string; placeholder?: string; result: ScrapeResult; + locked?: boolean; onChange: (value: ScrapeResult) => void; } @@ -220,6 +222,7 @@ export const ScrapedInputGroupRow: React.FC = ( placeholder={props.placeholder || props.title} result={props.result} isNew + locked={props.locked} onChange={(value) => props.onChange(props.result.cloneWithValue(value)) }