mirror of
https://github.com/immich-app/immich
synced 2026-08-29 13:15:45 +00:00
61 lines
2.2 KiB
TypeScript
61 lines
2.2 KiB
TypeScript
|
|
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Counts all truthy values in the exifInfo object.
|
||
|
|
* This matches the client implementation in web/src/lib/utils/exif-utils.ts
|
||
|
|
*
|
||
|
|
* @param asset Asset with optional exifInfo
|
||
|
|
* @returns Count of truthy EXIF values
|
||
|
|
*/
|
||
|
|
export const getExifCount = (asset: AssetResponseDto): number => {
|
||
|
|
return Object.values(asset.exifInfo ?? {}).filter(Boolean).length;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Suggests the best duplicate asset to keep from a list of duplicates.
|
||
|
|
* This is a direct port of the client logic from web/src/lib/utils/duplicate-utils.ts
|
||
|
|
*
|
||
|
|
* The best asset is determined by the following criteria:
|
||
|
|
* 1. Largest image file size in bytes
|
||
|
|
* 2. Largest count of EXIF data (as tie-breaker)
|
||
|
|
*
|
||
|
|
* @param assets List of duplicate assets
|
||
|
|
* @returns The best asset to keep, or undefined if empty list
|
||
|
|
*/
|
||
|
|
export const suggestDuplicate = (assets: AssetResponseDto[]): AssetResponseDto | undefined => {
|
||
|
|
if (assets.length === 0) {
|
||
|
|
return undefined;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Sort by file size ascending (smallest first)
|
||
|
|
let duplicateAssets = [...assets].toSorted(
|
||
|
|
(a, b) => (a.exifInfo?.fileSizeInByte ?? 0) - (b.exifInfo?.fileSizeInByte ?? 0),
|
||
|
|
);
|
||
|
|
|
||
|
|
// Get the largest file size (last element after sorting)
|
||
|
|
const largestFileSize = duplicateAssets.at(-1)?.exifInfo?.fileSizeInByte ?? 0;
|
||
|
|
|
||
|
|
// Filter to keep only assets with the largest file size
|
||
|
|
duplicateAssets = duplicateAssets.filter((asset) => (asset.exifInfo?.fileSizeInByte ?? 0) === largestFileSize);
|
||
|
|
|
||
|
|
// If there are multiple assets with the same file size, sort by EXIF count
|
||
|
|
if (duplicateAssets.length >= 2) {
|
||
|
|
duplicateAssets = duplicateAssets.toSorted((a, b) => getExifCount(a) - getExifCount(b));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return the last asset (highest EXIF count among highest file size)
|
||
|
|
return duplicateAssets.at(-1);
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Suggests the best duplicate asset IDs to keep from a list of duplicates.
|
||
|
|
* Returns an array with a single asset ID (the best candidate), or empty if no assets.
|
||
|
|
*
|
||
|
|
* @param assets List of duplicate assets
|
||
|
|
* @returns Array of suggested asset IDs to keep (0 or 1 element)
|
||
|
|
*/
|
||
|
|
export const suggestDuplicateKeepAssetIds = (assets: AssetResponseDto[]): string[] => {
|
||
|
|
const suggested = suggestDuplicate(assets);
|
||
|
|
return suggested ? [suggested.id] : [];
|
||
|
|
};
|