mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Set stash id during performer scrape (#1608)
This commit is contained in:
@@ -23,6 +23,7 @@ fragment ScrapedPerformerData on ScrapedPerformer {
|
|||||||
death_date
|
death_date
|
||||||
hair_color
|
hair_color
|
||||||
weight
|
weight
|
||||||
|
remote_site_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment ScrapedScenePerformerData on ScrapedScenePerformer {
|
fragment ScrapedScenePerformerData on ScrapedScenePerformer {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type ScrapedPerformer {
|
|||||||
death_date: String
|
death_date: String
|
||||||
hair_color: String
|
hair_color: String
|
||||||
weight: String
|
weight: String
|
||||||
|
remote_site_id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ScrapedPerformerInput {
|
input ScrapedPerformerInput {
|
||||||
@@ -51,4 +52,5 @@ input ScrapedPerformerInput {
|
|||||||
death_date: String
|
death_date: String
|
||||||
hair_color: String
|
hair_color: String
|
||||||
weight: String
|
weight: String
|
||||||
|
remote_site_id: String
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,7 @@ type ScrapedPerformer struct {
|
|||||||
DeathDate *string `graphql:"death_date" json:"death_date"`
|
DeathDate *string `graphql:"death_date" json:"death_date"`
|
||||||
HairColor *string `graphql:"hair_color" json:"hair_color"`
|
HairColor *string `graphql:"hair_color" json:"hair_color"`
|
||||||
Weight *string `graphql:"weight" json:"weight"`
|
Weight *string `graphql:"weight" json:"weight"`
|
||||||
|
RemoteSiteID *string `graphql:"remote_site_id" json:"remote_site_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// this type has no Image field
|
// this type has no Image field
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
* Added de-DE language option. ([#1578](https://github.com/stashapp/stash/pull/1578))
|
* Added de-DE language option. ([#1578](https://github.com/stashapp/stash/pull/1578))
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 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 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 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))
|
* Fix is missing date scene criterion causing invalid SQL. ([#1577](https://github.com/stashapp/stash/pull/1577))
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
// Editing state
|
// Editing state
|
||||||
const [scraper, setScraper] = useState<GQL.Scraper | IStashBox | undefined>();
|
const [scraper, setScraper] = useState<GQL.Scraper | IStashBox | undefined>();
|
||||||
const [newTags, setNewTags] = useState<GQL.ScrapedSceneTag[]>();
|
const [newTags, setNewTags] = useState<GQL.ScrapedSceneTag[]>();
|
||||||
|
const [isScraperModalOpen, setIsScraperModalOpen] = useState<boolean>(false);
|
||||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
// Network state
|
// Network state
|
||||||
@@ -351,6 +352,19 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
if (state.weight) {
|
if (state.weight) {
|
||||||
formik.setFieldValue("weight", 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) {
|
function onImageLoad(imageData: string) {
|
||||||
@@ -507,7 +521,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
selectedPerformer: GQL.ScrapedPerformerDataFragment,
|
selectedPerformer: GQL.ScrapedPerformerDataFragment,
|
||||||
selectedScraper: GQL.Scraper
|
selectedScraper: GQL.Scraper
|
||||||
) {
|
) {
|
||||||
setScraper(undefined);
|
setIsScraperModalOpen(false);
|
||||||
try {
|
try {
|
||||||
if (!scraper) return;
|
if (!scraper) return;
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@@ -525,6 +539,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
// if this is a new performer, just dump the data
|
// if this is a new performer, just dump the data
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
updatePerformerEditStateFromScraper(result.data.scrapePerformer);
|
updatePerformerEditStateFromScraper(result.data.scrapePerformer);
|
||||||
|
setScraper(undefined);
|
||||||
} else {
|
} else {
|
||||||
setScrapedPerformer(result.data.scrapePerformer);
|
setScrapedPerformer(result.data.scrapePerformer);
|
||||||
}
|
}
|
||||||
@@ -559,7 +574,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onScrapeStashBox(performerResult: GQL.ScrapedScenePerformer) {
|
async function onScrapeStashBox(performerResult: GQL.ScrapedScenePerformer) {
|
||||||
setScraper(undefined);
|
setIsScraperModalOpen(false);
|
||||||
|
|
||||||
const result: Partial<GQL.ScrapedPerformerDataFragment> = {
|
const result: Partial<GQL.ScrapedPerformerDataFragment> = {
|
||||||
...performerResult,
|
...performerResult,
|
||||||
@@ -571,11 +586,17 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
// if this is a new performer, just dump the data
|
// if this is a new performer, just dump the data
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
updatePerformerEditStateFromScraper(result);
|
updatePerformerEditStateFromScraper(result);
|
||||||
|
setScraper(undefined);
|
||||||
} else {
|
} else {
|
||||||
setScrapedPerformer(result);
|
setScrapedPerformer(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onScraperSelected(s: GQL.Scraper | IStashBox | undefined) {
|
||||||
|
setScraper(s);
|
||||||
|
setIsScraperModalOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
function renderScraperMenu() {
|
function renderScraperMenu() {
|
||||||
if (!performer) {
|
if (!performer) {
|
||||||
return;
|
return;
|
||||||
@@ -590,7 +611,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
<div key={s.endpoint}>
|
<div key={s.endpoint}>
|
||||||
<Button
|
<Button
|
||||||
className="minimal"
|
className="minimal"
|
||||||
onClick={() => setScraper({ ...s, index })}
|
onClick={() => onScraperSelected({ ...s, index })}
|
||||||
>
|
>
|
||||||
{s.name ?? "Stash-Box"}
|
{s.name ?? "Stash-Box"}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -602,7 +623,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
<Button
|
<Button
|
||||||
key={s.name}
|
key={s.name}
|
||||||
className="minimal"
|
className="minimal"
|
||||||
onClick={() => setScraper(s)}
|
onClick={() => onScraperSelected(s)}
|
||||||
>
|
>
|
||||||
{s.name}
|
{s.name}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -648,7 +669,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderScrapeDialog() {
|
function maybeRenderScrapeDialog() {
|
||||||
if (!scrapedPerformer) {
|
if (!scrapedPerformer || !scraper) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,6 +684,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
<PerformerScrapeDialog
|
<PerformerScrapeDialog
|
||||||
performer={currentPerformer}
|
performer={currentPerformer}
|
||||||
scraped={scrapedPerformer}
|
scraped={scrapedPerformer}
|
||||||
|
scraper={scraper}
|
||||||
onClose={(p) => {
|
onClose={(p) => {
|
||||||
onScrapeDialogClosed(p);
|
onScrapeDialogClosed(p);
|
||||||
}}
|
}}
|
||||||
@@ -675,6 +697,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
updatePerformerEditStateFromScraper(p);
|
updatePerformerEditStateFromScraper(p);
|
||||||
}
|
}
|
||||||
setScrapedPerformer(undefined);
|
setScrapedPerformer(undefined);
|
||||||
|
setScraper(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderScrapeButton() {
|
function maybeRenderScrapeButton() {
|
||||||
@@ -731,8 +754,10 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderScrapeModal = () =>
|
const renderScrapeModal = () => {
|
||||||
scraper !== undefined && isScraper(scraper) ? (
|
if (!isScraperModalOpen) return;
|
||||||
|
|
||||||
|
return scraper !== undefined && isScraper(scraper) ? (
|
||||||
<PerformerScrapeModal
|
<PerformerScrapeModal
|
||||||
scraper={scraper}
|
scraper={scraper}
|
||||||
onHide={() => setScraper(undefined)}
|
onHide={() => setScraper(undefined)}
|
||||||
@@ -747,6 +772,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
name={formik.values.name || ""}
|
name={formik.values.name || ""}
|
||||||
/>
|
/>
|
||||||
) : undefined;
|
) : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
function renderDeleteAlert() {
|
function renderDeleteAlert() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
genderToString,
|
genderToString,
|
||||||
stringToGender,
|
stringToGender,
|
||||||
} from "src/utils/gender";
|
} from "src/utils/gender";
|
||||||
|
import { IStashBox } from "./PerformerStashBoxModal";
|
||||||
|
|
||||||
function renderScrapedGender(
|
function renderScrapedGender(
|
||||||
result: ScrapeResult<string>,
|
result: ScrapeResult<string>,
|
||||||
@@ -119,6 +120,7 @@ function renderScrapedTagsRow(
|
|||||||
interface IPerformerScrapeDialogProps {
|
interface IPerformerScrapeDialogProps {
|
||||||
performer: Partial<GQL.PerformerUpdateInput>;
|
performer: Partial<GQL.PerformerUpdateInput>;
|
||||||
scraped: GQL.ScrapedPerformer;
|
scraped: GQL.ScrapedPerformer;
|
||||||
|
scraper?: GQL.Scraper | IStashBox;
|
||||||
|
|
||||||
onClose: (scrapedPerformer?: GQL.ScrapedPerformer) => void;
|
onClose: (scrapedPerformer?: GQL.ScrapedPerformer) => void;
|
||||||
}
|
}
|
||||||
@@ -128,6 +130,17 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||||||
) => {
|
) => {
|
||||||
const intl = useIntl();
|
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) {
|
function translateScrapedGender(scrapedGender?: string | null) {
|
||||||
if (!scrapedGender) {
|
if (!scrapedGender) {
|
||||||
return;
|
return;
|
||||||
@@ -227,6 +240,12 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||||||
const [details, setDetails] = useState<ScrapeResult<string>>(
|
const [details, setDetails] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(props.performer.details, props.scraped.details)
|
new ScrapeResult<string>(props.performer.details, props.scraped.details)
|
||||||
);
|
);
|
||||||
|
const [remoteSiteID, setRemoteSiteID] = useState<ScrapeResult<string>>(
|
||||||
|
new ScrapeResult<string>(
|
||||||
|
getCurrentRemoteSiteID(),
|
||||||
|
props.scraped.remote_site_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const [createTag] = useTagCreate();
|
const [createTag] = useTagCreate();
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
@@ -311,6 +330,7 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||||||
deathDate,
|
deathDate,
|
||||||
hairColor,
|
hairColor,
|
||||||
weight,
|
weight,
|
||||||
|
remoteSiteID,
|
||||||
];
|
];
|
||||||
// don't show the dialog if nothing was scraped
|
// don't show the dialog if nothing was scraped
|
||||||
if (allFields.every((r) => !r.scraped)) {
|
if (allFields.every((r) => !r.scraped)) {
|
||||||
@@ -383,6 +403,7 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||||||
death_date: deathDate.getNewValue(),
|
death_date: deathDate.getNewValue(),
|
||||||
hair_color: hairColor.getNewValue(),
|
hair_color: hairColor.getNewValue(),
|
||||||
weight: weight.getNewValue(),
|
weight: weight.getNewValue(),
|
||||||
|
remote_site_id: remoteSiteID.getNewValue(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,6 +523,12 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||||||
result={image}
|
result={image}
|
||||||
onChange={(value) => setImage(value)}
|
onChange={(value) => setImage(value)}
|
||||||
/>
|
/>
|
||||||
|
<ScrapedInputGroupRow
|
||||||
|
title={intl.formatMessage({ id: "stash_id" })}
|
||||||
|
result={remoteSiteID}
|
||||||
|
locked
|
||||||
|
onChange={(value) => setRemoteSiteID(value)}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ export const ScrapeDialogRow = <T, V extends IHasName>(
|
|||||||
interface IScrapedInputGroupProps {
|
interface IScrapedInputGroupProps {
|
||||||
isNew?: boolean;
|
isNew?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
locked?: boolean;
|
||||||
result: ScrapeResult<string>;
|
result: ScrapeResult<string>;
|
||||||
onChange?: (value: string) => void;
|
onChange?: (value: string) => void;
|
||||||
}
|
}
|
||||||
@@ -184,7 +185,7 @@ const ScrapedInputGroup: React.FC<IScrapedInputGroupProps> = (props) => {
|
|||||||
<FormControl
|
<FormControl
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
value={props.isNew ? props.result.newValue : props.result.originalValue}
|
value={props.isNew ? props.result.newValue : props.result.originalValue}
|
||||||
readOnly={!props.isNew}
|
readOnly={!props.isNew || props.locked}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (props.isNew && props.onChange) {
|
if (props.isNew && props.onChange) {
|
||||||
props.onChange(e.target.value);
|
props.onChange(e.target.value);
|
||||||
@@ -199,6 +200,7 @@ interface IScrapedInputGroupRowProps {
|
|||||||
title: string;
|
title: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
result: ScrapeResult<string>;
|
result: ScrapeResult<string>;
|
||||||
|
locked?: boolean;
|
||||||
onChange: (value: ScrapeResult<string>) => void;
|
onChange: (value: ScrapeResult<string>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +222,7 @@ export const ScrapedInputGroupRow: React.FC<IScrapedInputGroupRowProps> = (
|
|||||||
placeholder={props.placeholder || props.title}
|
placeholder={props.placeholder || props.title}
|
||||||
result={props.result}
|
result={props.result}
|
||||||
isNew
|
isNew
|
||||||
|
locked={props.locked}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
props.onChange(props.result.cloneWithValue(value))
|
props.onChange(props.result.cloneWithValue(value))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user