mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Set stash id during performer scrape (#1608)
This commit is contained in:
@@ -23,6 +23,7 @@ fragment ScrapedPerformerData on ScrapedPerformer {
|
||||
death_date
|
||||
hair_color
|
||||
weight
|
||||
remote_site_id
|
||||
}
|
||||
|
||||
fragment ScrapedScenePerformerData on ScrapedScenePerformer {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -74,6 +74,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
// Editing state
|
||||
const [scraper, setScraper] = useState<GQL.Scraper | IStashBox | undefined>();
|
||||
const [newTags, setNewTags] = useState<GQL.ScrapedSceneTag[]>();
|
||||
const [isScraperModalOpen, setIsScraperModalOpen] = useState<boolean>(false);
|
||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||
|
||||
// Network state
|
||||
@@ -351,6 +352,19 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
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<IPerformerDetails> = ({
|
||||
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<IPerformerDetails> = ({
|
||||
// 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<IPerformerDetails> = ({
|
||||
}
|
||||
|
||||
async function onScrapeStashBox(performerResult: GQL.ScrapedScenePerformer) {
|
||||
setScraper(undefined);
|
||||
setIsScraperModalOpen(false);
|
||||
|
||||
const result: Partial<GQL.ScrapedPerformerDataFragment> = {
|
||||
...performerResult,
|
||||
@@ -571,11 +586,17 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
// 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<IPerformerDetails> = ({
|
||||
<div key={s.endpoint}>
|
||||
<Button
|
||||
className="minimal"
|
||||
onClick={() => setScraper({ ...s, index })}
|
||||
onClick={() => onScraperSelected({ ...s, index })}
|
||||
>
|
||||
{s.name ?? "Stash-Box"}
|
||||
</Button>
|
||||
@@ -602,7 +623,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
<Button
|
||||
key={s.name}
|
||||
className="minimal"
|
||||
onClick={() => setScraper(s)}
|
||||
onClick={() => onScraperSelected(s)}
|
||||
>
|
||||
{s.name}
|
||||
</Button>
|
||||
@@ -648,7 +669,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
}
|
||||
|
||||
function maybeRenderScrapeDialog() {
|
||||
if (!scrapedPerformer) {
|
||||
if (!scrapedPerformer || !scraper) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -663,6 +684,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
<PerformerScrapeDialog
|
||||
performer={currentPerformer}
|
||||
scraped={scrapedPerformer}
|
||||
scraper={scraper}
|
||||
onClose={(p) => {
|
||||
onScrapeDialogClosed(p);
|
||||
}}
|
||||
@@ -675,6 +697,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
updatePerformerEditStateFromScraper(p);
|
||||
}
|
||||
setScrapedPerformer(undefined);
|
||||
setScraper(undefined);
|
||||
}
|
||||
|
||||
function maybeRenderScrapeButton() {
|
||||
@@ -731,8 +754,10 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
);
|
||||
}
|
||||
|
||||
const renderScrapeModal = () =>
|
||||
scraper !== undefined && isScraper(scraper) ? (
|
||||
const renderScrapeModal = () => {
|
||||
if (!isScraperModalOpen) return;
|
||||
|
||||
return scraper !== undefined && isScraper(scraper) ? (
|
||||
<PerformerScrapeModal
|
||||
scraper={scraper}
|
||||
onHide={() => setScraper(undefined)}
|
||||
@@ -747,6 +772,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||
name={formik.values.name || ""}
|
||||
/>
|
||||
) : undefined;
|
||||
};
|
||||
|
||||
function renderDeleteAlert() {
|
||||
return (
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
genderToString,
|
||||
stringToGender,
|
||||
} from "src/utils/gender";
|
||||
import { IStashBox } from "./PerformerStashBoxModal";
|
||||
|
||||
function renderScrapedGender(
|
||||
result: ScrapeResult<string>,
|
||||
@@ -119,6 +120,7 @@ function renderScrapedTagsRow(
|
||||
interface IPerformerScrapeDialogProps {
|
||||
performer: Partial<GQL.PerformerUpdateInput>;
|
||||
scraped: GQL.ScrapedPerformer;
|
||||
scraper?: GQL.Scraper | IStashBox;
|
||||
|
||||
onClose: (scrapedPerformer?: GQL.ScrapedPerformer) => void;
|
||||
}
|
||||
@@ -128,6 +130,17 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
||||
) => {
|
||||
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<IPerformerScrapeDialogProps> = (
|
||||
const [details, setDetails] = useState<ScrapeResult<string>>(
|
||||
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 Toast = useToast();
|
||||
@@ -311,6 +330,7 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
||||
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<IPerformerScrapeDialogProps> = (
|
||||
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<IPerformerScrapeDialogProps> = (
|
||||
result={image}
|
||||
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 {
|
||||
isNew?: boolean;
|
||||
placeholder?: string;
|
||||
locked?: boolean;
|
||||
result: ScrapeResult<string>;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
@@ -184,7 +185,7 @@ const ScrapedInputGroup: React.FC<IScrapedInputGroupProps> = (props) => {
|
||||
<FormControl
|
||||
placeholder={props.placeholder}
|
||||
value={props.isNew ? props.result.newValue : props.result.originalValue}
|
||||
readOnly={!props.isNew}
|
||||
readOnly={!props.isNew || props.locked}
|
||||
onChange={(e) => {
|
||||
if (props.isNew && props.onChange) {
|
||||
props.onChange(e.target.value);
|
||||
@@ -199,6 +200,7 @@ interface IScrapedInputGroupRowProps {
|
||||
title: string;
|
||||
placeholder?: string;
|
||||
result: ScrapeResult<string>;
|
||||
locked?: boolean;
|
||||
onChange: (value: ScrapeResult<string>) => void;
|
||||
}
|
||||
|
||||
@@ -220,6 +222,7 @@ export const ScrapedInputGroupRow: React.FC<IScrapedInputGroupRowProps> = (
|
||||
placeholder={props.placeholder || props.title}
|
||||
result={props.result}
|
||||
isNew
|
||||
locked={props.locked}
|
||||
onChange={(value) =>
|
||||
props.onChange(props.result.cloneWithValue(value))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user