mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 21:04:37 +03:00
Fix scene tagger bugs (#1357)
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
* Change performer text query to search by name and alias only.
|
* Change performer text query to search by name and alias only.
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 Bug fixes
|
||||||
|
* Fix performer/studio being cleared when skipped in scene tagger.
|
||||||
* Fixed error when auto-tagging for performers/studios/tags with regex characters in the name.
|
* Fixed error when auto-tagging for performers/studios/tags with regex characters in the name.
|
||||||
* Fix scraped performer image not updating after clearing the current image when creating a new performer.
|
* Fix scraped performer image not updating after clearing the current image when creating a new performer.
|
||||||
* Fix error preventing adding a new library path when an existing library path is missing.
|
* Fix error preventing adding a new library path when an existing library path is missing.
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ const Config: React.FC<IConfigProps> = ({ show, config, setConfig }) => {
|
|||||||
if (!blacklistRef.current) return;
|
if (!blacklistRef.current) return;
|
||||||
|
|
||||||
const input = blacklistRef.current.value;
|
const input = blacklistRef.current.value;
|
||||||
|
if (input.length === 0) return;
|
||||||
|
|
||||||
setConfig({
|
setConfig({
|
||||||
...config,
|
...config,
|
||||||
blacklist: [...config.blacklist, input],
|
blacklist: [...config.blacklist, input],
|
||||||
|
|||||||
@@ -25,28 +25,38 @@ const getDurationStatus = (
|
|||||||
scene: IStashBoxScene,
|
scene: IStashBoxScene,
|
||||||
stashDuration: number | undefined | null
|
stashDuration: number | undefined | null
|
||||||
) => {
|
) => {
|
||||||
const fingerprintDuration =
|
if (!stashDuration) return "";
|
||||||
scene.fingerprints.map((f) => f.duration)?.[0] ?? null;
|
|
||||||
const sceneDuration = scene.duration || fingerprintDuration;
|
const durations = scene.fingerprints
|
||||||
if (!sceneDuration || !stashDuration) return "";
|
.map((f) => f.duration)
|
||||||
const diff = Math.abs(sceneDuration - stashDuration);
|
.map((d) => Math.abs(d - stashDuration));
|
||||||
if (diff < 5) {
|
const matchCount = durations.filter((duration) => duration <= 5).length;
|
||||||
|
|
||||||
|
let match;
|
||||||
|
if (matchCount > 0)
|
||||||
|
match = `Duration matches ${matchCount}/${durations.length} fingerprints`;
|
||||||
|
else if (Math.abs(scene.duration - stashDuration) < 5)
|
||||||
|
match = "Duration is a match";
|
||||||
|
|
||||||
|
if (match)
|
||||||
return (
|
return (
|
||||||
<div className="font-weight-bold">
|
<div className="font-weight-bold">
|
||||||
<SuccessIcon className="mr-2" />
|
<SuccessIcon className="mr-2" />
|
||||||
Duration is a match
|
{match}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return <div>Duration off by {Math.floor(diff)}s</div>;
|
const minDiff = Math.min(scene.duration, ...durations);
|
||||||
|
return <div>Duration off by at least {Math.floor(minDiff)}s</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFingerprintStatus = (
|
const getFingerprintStatus = (
|
||||||
scene: IStashBoxScene,
|
scene: IStashBoxScene,
|
||||||
stashScene: GQL.SlimSceneDataFragment
|
stashScene: GQL.SlimSceneDataFragment
|
||||||
) => {
|
) => {
|
||||||
const checksum = stashScene.checksum ?? stashScene.oshash ?? undefined;
|
const checksumMatch = scene.fingerprints.some(
|
||||||
const checksumMatch = scene.fingerprints.some((f) => f.hash === checksum);
|
(f) => f.hash === stashScene.checksum || f.hash === stashScene.oshash
|
||||||
|
);
|
||||||
const phashMatch = scene.fingerprints.some(
|
const phashMatch = scene.fingerprints.some(
|
||||||
(f) => f.hash === stashScene.phash
|
(f) => f.hash === stashScene.phash
|
||||||
);
|
);
|
||||||
@@ -176,6 +186,8 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
|
|||||||
studioID = res.data.studioUpdate.id;
|
studioID = res.data.studioUpdate.id;
|
||||||
} else if (studio.type === "existing") {
|
} else if (studio.type === "existing") {
|
||||||
studioID = studio.data.id;
|
studioID = studio.data.id;
|
||||||
|
} else if (studio.type === "skip") {
|
||||||
|
studioID = stashScene.studio?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSaveState("Saving performers");
|
setSaveState("Saving performers");
|
||||||
@@ -296,6 +308,10 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
|
|||||||
updatedTags = uniq(newTagIDs);
|
updatedTags = uniq(newTagIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const performer_ids = performerIDs.filter(
|
||||||
|
(id) => id !== "Skip"
|
||||||
|
) as string[];
|
||||||
|
|
||||||
const sceneUpdateResult = await updateScene({
|
const sceneUpdateResult = await updateScene({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
@@ -303,9 +319,10 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
|
|||||||
title: scene.title,
|
title: scene.title,
|
||||||
details: scene.details,
|
details: scene.details,
|
||||||
date: scene.date,
|
date: scene.date,
|
||||||
performer_ids: performerIDs.filter(
|
performer_ids:
|
||||||
(id) => id !== "Skip"
|
performer_ids.length === 0
|
||||||
) as string[],
|
? stashScene.performers.map((p) => p.id)
|
||||||
|
: performer_ids,
|
||||||
studio_id: studioID,
|
studio_id: studioID,
|
||||||
cover_image: imgData,
|
cover_image: imgData,
|
||||||
url: scene.url,
|
url: scene.url,
|
||||||
|
|||||||
@@ -171,12 +171,15 @@ const TaggerList: React.FC<ITaggerListProps> = ({
|
|||||||
const [selectedResult, setSelectedResult] = useState<
|
const [selectedResult, setSelectedResult] = useState<
|
||||||
Record<string, number>
|
Record<string, number>
|
||||||
>();
|
>();
|
||||||
|
const [selectedFingerprintResult, setSelectedFingerprintResult] = useState<
|
||||||
|
Record<string, number>
|
||||||
|
>();
|
||||||
const [taggedScenes, setTaggedScenes] = useState<
|
const [taggedScenes, setTaggedScenes] = useState<
|
||||||
Record<string, Partial<GQL.SlimSceneDataFragment>>
|
Record<string, Partial<GQL.SlimSceneDataFragment>>
|
||||||
>({});
|
>({});
|
||||||
const [loadingFingerprints, setLoadingFingerprints] = useState(false);
|
const [loadingFingerprints, setLoadingFingerprints] = useState(false);
|
||||||
const [fingerprints, setFingerprints] = useState<
|
const [fingerprints, setFingerprints] = useState<
|
||||||
Record<string, IStashBoxScene>
|
Record<string, IStashBoxScene[]>
|
||||||
>({});
|
>({});
|
||||||
const [hideUnmatched, setHideUnmatched] = useState(false);
|
const [hideUnmatched, setHideUnmatched] = useState(false);
|
||||||
const fingerprintQueue =
|
const fingerprintQueue =
|
||||||
@@ -269,7 +272,9 @@ const TaggerList: React.FC<ITaggerListProps> = ({
|
|||||||
|
|
||||||
selectScenes(results.data?.queryStashBoxScene).forEach((scene) => {
|
selectScenes(results.data?.queryStashBoxScene).forEach((scene) => {
|
||||||
scene.fingerprints?.forEach((f) => {
|
scene.fingerprints?.forEach((f) => {
|
||||||
newFingerprints[f.hash] = scene;
|
newFingerprints[f.hash] = newFingerprints[f.hash]
|
||||||
|
? [...newFingerprints[f.hash], scene]
|
||||||
|
: [scene];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -428,21 +433,30 @@ const TaggerList: React.FC<ITaggerListProps> = ({
|
|||||||
|
|
||||||
let searchResult;
|
let searchResult;
|
||||||
if (fingerprintMatch && !isTagged && !hasStashIDs) {
|
if (fingerprintMatch && !isTagged && !hasStashIDs) {
|
||||||
searchResult = (
|
searchResult = sortScenesByDuration(
|
||||||
|
fingerprintMatch,
|
||||||
|
scene.file.duration ?? 0
|
||||||
|
).map((match, i) => (
|
||||||
<StashSearchResult
|
<StashSearchResult
|
||||||
showMales={config.showMales}
|
showMales={config.showMales}
|
||||||
stashScene={scene}
|
stashScene={scene}
|
||||||
isActive
|
isActive={(selectedFingerprintResult?.[scene.id] ?? 0) === i}
|
||||||
setActive={() => {}}
|
setActive={() =>
|
||||||
|
setSelectedFingerprintResult({
|
||||||
|
...selectedFingerprintResult,
|
||||||
|
[scene.id]: i,
|
||||||
|
})
|
||||||
|
}
|
||||||
setScene={handleTaggedScene}
|
setScene={handleTaggedScene}
|
||||||
scene={fingerprintMatch}
|
scene={match}
|
||||||
setCoverImage={config.setCoverImage}
|
setCoverImage={config.setCoverImage}
|
||||||
setTags={config.setTags}
|
setTags={config.setTags}
|
||||||
tagOperation={config.tagOperation}
|
tagOperation={config.tagOperation}
|
||||||
endpoint={selectedEndpoint.endpoint}
|
endpoint={selectedEndpoint.endpoint}
|
||||||
queueFingerprintSubmission={queueFingerprintSubmission}
|
queueFingerprintSubmission={queueFingerprintSubmission}
|
||||||
|
key={match.stash_id}
|
||||||
/>
|
/>
|
||||||
);
|
));
|
||||||
} else if (
|
} else if (
|
||||||
searchResults[scene.id]?.length > 0 &&
|
searchResults[scene.id]?.length > 0 &&
|
||||||
!isTagged &&
|
!isTagged &&
|
||||||
|
|||||||
@@ -165,18 +165,22 @@ export const sortScenesByDuration = (
|
|||||||
targetDuration?: number
|
targetDuration?: number
|
||||||
) =>
|
) =>
|
||||||
scenes.sort((a, b) => {
|
scenes.sort((a, b) => {
|
||||||
const adur =
|
|
||||||
a?.duration || (a?.fingerprints.map((f) => f.duration)?.[0] ?? null);
|
|
||||||
const bdur =
|
|
||||||
b?.duration || (b?.fingerprints.map((f) => f.duration)?.[0] ?? null);
|
|
||||||
if (!adur && !bdur) return 0;
|
|
||||||
if (adur && !bdur) return -1;
|
|
||||||
if (!adur && bdur) return 1;
|
|
||||||
|
|
||||||
if (!targetDuration) return 0;
|
if (!targetDuration) return 0;
|
||||||
|
|
||||||
const aDiff = Math.abs((adur ?? 0) - targetDuration);
|
const aDur = [
|
||||||
const bDiff = Math.abs((bdur ?? 0) - targetDuration);
|
a.duration,
|
||||||
|
...a.fingerprints.map((f) => f.duration),
|
||||||
|
].map((d) => Math.abs(d - targetDuration));
|
||||||
|
const bDur = [
|
||||||
|
b.duration,
|
||||||
|
...b.fingerprints.map((f) => f.duration),
|
||||||
|
].map((d) => Math.abs(d - targetDuration));
|
||||||
|
|
||||||
|
if (aDur.length > 0 && bDur.length === 0) return -1;
|
||||||
|
if (aDur.length === 0 && bDur.length > 0) return 1;
|
||||||
|
|
||||||
|
const aDiff = Math.min(...aDur);
|
||||||
|
const bDiff = Math.min(...bDur);
|
||||||
|
|
||||||
if (aDiff < bDiff) return -1;
|
if (aDiff < bDiff) return -1;
|
||||||
if (aDiff > bDiff) return 1;
|
if (aDiff > bDiff) return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user