mirror of
https://github.com/stashapp/stash.git
synced 2026-04-14 11:04:07 +02:00
perf(ui): use slim image data in duplicate checker
This fixes a severe performance bottleneck where the image duplicate checker would hang indefinitely or crash the server when finding many duplicates. Previously, the GraphQL query requested the full 'ImageData' fragment for every duplicate found, forcing the backend to resolve and serialize all related entities (galleries, studios, tags, performers) for thousands of images at once. By switching to the 'SlimImageData' fragment (mirroring how the Scene duplicate checker operates), the payload size and resolution time are drastically reduced, allowing the tool to scale correctly.
This commit is contained in:
parent
f2f299307a
commit
eeba66e598
2 changed files with 11 additions and 11 deletions
|
|
@ -38,6 +38,6 @@ query FindImage($id: ID!, $checksum: String) {
|
|||
|
||||
query FindDuplicateImages($distance: Int!) {
|
||||
findDuplicateImages(distance: $distance) {
|
||||
...ImageData
|
||||
...SlimImageData
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
{}
|
||||
);
|
||||
const [selectedImages, setSelectedImages] =
|
||||
useState<GQL.ImageDataFragment[]>();
|
||||
useState<GQL.SlimImageDataFragment[]>();
|
||||
const [deletingImages, setDeletingImages] = useState(false);
|
||||
const [editingImages, setEditingImages] = useState(false);
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
fetchPolicy: "network-only",
|
||||
});
|
||||
|
||||
const getGroupTotalSize = (group: GQL.ImageDataFragment[]) => {
|
||||
const getGroupTotalSize = (group: GQL.SlimImageDataFragment[]) => {
|
||||
return group.reduce((groupTotal, img) => {
|
||||
const imgTotal = img.visual_files.reduce(
|
||||
(fileTotal, file) => fileTotal + (file.size ?? 0),
|
||||
|
|
@ -188,8 +188,8 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
setCheckedImages(updatedImages);
|
||||
};
|
||||
|
||||
const findLargestImage = (group: GQL.ImageDataFragment[]) => {
|
||||
const totalSize = (image: GQL.ImageDataFragment) => {
|
||||
const findLargestImage = (group: GQL.SlimImageDataFragment[]) => {
|
||||
const totalSize = (image: GQL.SlimImageDataFragment) => {
|
||||
return image.visual_files.reduce(
|
||||
(prev: number, f) => Math.max(prev, f.size ?? 0),
|
||||
0
|
||||
|
|
@ -202,8 +202,8 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const findLargestResolutionImage = (group: GQL.ImageDataFragment[]) => {
|
||||
const imgResolution = (image: GQL.ImageDataFragment) => {
|
||||
const findLargestResolutionImage = (group: GQL.SlimImageDataFragment[]) => {
|
||||
const imgResolution = (image: GQL.SlimImageDataFragment) => {
|
||||
return image.visual_files.reduce(
|
||||
(prev: number, f) => Math.max(prev, (f.height ?? 0) * (f.width ?? 0)),
|
||||
0
|
||||
|
|
@ -218,7 +218,7 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
|
||||
const findFirstFileByAge = (
|
||||
oldest: boolean,
|
||||
compareImages: GQL.ImageDataFragment[]
|
||||
compareImages: GQL.SlimImageDataFragment[]
|
||||
) => {
|
||||
let selectedFile: GQL.ImageFileDataFragment | GQL.VideoFileDataFragment;
|
||||
let oldestTimestamp: Date | undefined = undefined;
|
||||
|
|
@ -243,7 +243,7 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
);
|
||||
};
|
||||
|
||||
function checkSameResolution(dataGroup: GQL.ImageDataFragment[]) {
|
||||
function checkSameResolution(dataGroup: GQL.SlimImageDataFragment[]) {
|
||||
const resolutions = dataGroup.map(
|
||||
(s) => (s.visual_files[0]?.width ?? 0) * (s.visual_files[0]?.height ?? 0)
|
||||
);
|
||||
|
|
@ -300,7 +300,7 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
setCheckedImages(checkedArray);
|
||||
};
|
||||
|
||||
const handleDeleteImage = (image: GQL.ImageDataFragment) => {
|
||||
const handleDeleteImage = (image: GQL.SlimImageDataFragment) => {
|
||||
setSelectedImages([image]);
|
||||
setDeletingImages(true);
|
||||
};
|
||||
|
|
@ -372,7 +372,7 @@ const ImageDuplicateChecker: React.FC = () => {
|
|||
);
|
||||
}
|
||||
|
||||
function maybeRenderPopoverButtonGroup(image: GQL.ImageDataFragment) {
|
||||
function maybeRenderPopoverButtonGroup(image: GQL.SlimImageDataFragment) {
|
||||
if (
|
||||
image.tags.length > 0 ||
|
||||
image.performers.length > 0 ||
|
||||
|
|
|
|||
Loading…
Reference in a new issue