mirror of
https://github.com/immich-app/immich.git
synced 2024-12-28 22:51:59 +00:00
format
This commit is contained in:
parent
2315466be3
commit
48bf55dad8
5 changed files with 104 additions and 111 deletions
|
@ -105,7 +105,8 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/await}
|
{/await}
|
||||||
-
|
-
|
||||||
{getExifCount(asset)} {$t('exif')}
|
{getExifCount(asset)}
|
||||||
|
{$t('exif')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,45 +1,37 @@
|
||||||
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
|
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
import type { AssetResponseDto } from '@immich/sdk';
|
||||||
|
|
||||||
describe('choosing a duplicate', () => {
|
describe('choosing a duplicate', () => {
|
||||||
|
it('picks the asset with the largest file size', () => {
|
||||||
it('picks the asset with the largest file size', () => {
|
const assets = [
|
||||||
const assets = [
|
{ exifInfo: { fileSizeInByte: 300 } },
|
||||||
{ exifInfo: { fileSizeInByte: 300 } },
|
{ exifInfo: { fileSizeInByte: 200 } },
|
||||||
{ exifInfo: { fileSizeInByte: 200 } },
|
{ exifInfo: { fileSizeInByte: 100 } },
|
||||||
{ exifInfo: { fileSizeInByte: 100 } },
|
];
|
||||||
];
|
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
||||||
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
});
|
||||||
});
|
|
||||||
|
it('picks the asset with the most exif data if multiple assets have the same file size', () => {
|
||||||
it('picks the asset with the most exif data if multiple assets have the same file size', () => {
|
const assets = [
|
||||||
const assets = [
|
{ exifInfo: { fileSizeInByte: 200, rating: 5, fNumber: 1 } },
|
||||||
{ exifInfo: { fileSizeInByte: 200, rating: 5, fNumber: 1 } },
|
{ exifInfo: { fileSizeInByte: 200, rating: 5 } },
|
||||||
{ exifInfo: { fileSizeInByte: 200, rating: 5 } },
|
{ exifInfo: { fileSizeInByte: 100, rating: 5 } },
|
||||||
{ exifInfo: { fileSizeInByte: 100, rating: 5 } },
|
];
|
||||||
];
|
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
||||||
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
});
|
||||||
});
|
|
||||||
|
it('returns undefined for an empty array', () => {
|
||||||
it('returns undefined for an empty array', () => {
|
const assets: AssetResponseDto[] = [];
|
||||||
const assets: AssetResponseDto[] = [];
|
expect(suggestDuplicate(assets)).toBeUndefined();
|
||||||
expect(suggestDuplicate(assets)).toBeUndefined();
|
});
|
||||||
});
|
|
||||||
|
it('handles assets with no exifInfo', () => {
|
||||||
it('handles assets with no exifInfo', () => {
|
const assets = [{ exifInfo: { fileSizeInByte: 200 } }, {}];
|
||||||
const assets = [
|
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
||||||
{ exifInfo: { fileSizeInByte: 200 } },
|
});
|
||||||
{},
|
|
||||||
];
|
it('handles assets with exifInfo but no fileSizeInByte', () => {
|
||||||
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
const assets = [{ exifInfo: { rating: 5, fNumber: 1 } }, { exifInfo: { rating: 5 } }];
|
||||||
});
|
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
||||||
|
});
|
||||||
it('handles assets with exifInfo but no fileSizeInByte', () => {
|
});
|
||||||
const assets = [
|
|
||||||
{ exifInfo: { rating: 5, fNumber: 1 } },
|
|
||||||
{ exifInfo: { rating: 5 } },
|
|
||||||
];
|
|
||||||
expect(suggestDuplicate(assets as AssetResponseDto[])).toEqual(assets[0]);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
import { getExifCount } from '$lib/utils/exif-utils';
|
||||||
import { sortBy } from 'lodash-es';
|
import type { AssetResponseDto } from '@immich/sdk';
|
||||||
import { getExifCount } from '$lib/utils/exif-utils';
|
import { sortBy } from 'lodash-es';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suggests the best duplicate asset to keep from a list of duplicates.
|
* Suggests the best duplicate asset to keep from a list of duplicates.
|
||||||
*
|
*
|
||||||
* The best asset is determined by the following criteria:
|
* The best asset is determined by the following criteria:
|
||||||
* - The asset with the largest file size
|
* - The asset with the largest file size
|
||||||
* - If there are multiple assets with the same file size, the asset with the most exif data
|
* - If there are multiple assets with the same file size, the asset with the most exif data
|
||||||
*
|
*
|
||||||
* @param assets List of duplicate assets
|
* @param assets List of duplicate assets
|
||||||
* @returns The best asset to keep
|
* @returns The best asset to keep
|
||||||
*/
|
*/
|
||||||
export const suggestDuplicate = (assets: AssetResponseDto[]): AssetResponseDto | undefined => {
|
export const suggestDuplicate = (assets: AssetResponseDto[]): AssetResponseDto | undefined => {
|
||||||
const assetsBySize = sortBy(assets, (asset) => asset.exifInfo?.fileSizeInByte ?? 0);
|
const assetsBySize = sortBy(assets, (asset) => asset.exifInfo?.fileSizeInByte ?? 0);
|
||||||
|
|
||||||
// All assets with the same file size as the largest asset
|
// All assets with the same file size as the largest asset
|
||||||
const highestSizeAssets = assetsBySize.filter((asset) => asset.exifInfo?.fileSizeInByte === assetsBySize.at(-1)?.exifInfo?.fileSizeInByte);
|
const highestSizeAssets = assetsBySize.filter(
|
||||||
|
(asset) => asset.exifInfo?.fileSizeInByte === assetsBySize.at(-1)?.exifInfo?.fileSizeInByte,
|
||||||
// If there are multiple assets with the same file size, return the one with the most exif data
|
);
|
||||||
if(highestSizeAssets.length >= 2) {
|
|
||||||
const assetsByExifCount = sortBy(highestSizeAssets, getExifCount);
|
// If there are multiple assets with the same file size, return the one with the most exif data
|
||||||
return assetsByExifCount.pop();
|
if (highestSizeAssets.length >= 2) {
|
||||||
}
|
const assetsByExifCount = sortBy(highestSizeAssets, getExifCount);
|
||||||
|
return assetsByExifCount.pop();
|
||||||
// Return the asset with the largest file size
|
}
|
||||||
return assetsBySize.pop();
|
|
||||||
};
|
// Return the asset with the largest file size
|
||||||
|
return assetsBySize.pop();
|
||||||
|
};
|
||||||
|
|
|
@ -1,31 +1,29 @@
|
||||||
import { getExifCount } from '$lib/utils/exif-utils';
|
import { getExifCount } from '$lib/utils/exif-utils';
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
import type { AssetResponseDto } from '@immich/sdk';
|
||||||
|
|
||||||
describe('getting the exif count', () => {
|
describe('getting the exif count', () => {
|
||||||
|
it('returns 0 when exifInfo is undefined', () => {
|
||||||
it('returns 0 when exifInfo is undefined', () => {
|
const asset = {};
|
||||||
const asset = {};
|
expect(getExifCount(asset as AssetResponseDto)).toBe(0);
|
||||||
expect(getExifCount(asset as AssetResponseDto)).toBe(0);
|
});
|
||||||
});
|
|
||||||
|
it('returns 0 when exifInfo is empty', () => {
|
||||||
it('returns 0 when exifInfo is empty', () => {
|
const asset = { exifInfo: {} };
|
||||||
const asset = { exifInfo: {} };
|
expect(getExifCount(asset as AssetResponseDto)).toBe(0);
|
||||||
expect(getExifCount(asset as AssetResponseDto)).toBe(0);
|
});
|
||||||
});
|
|
||||||
|
it('returns the correct count of non-null exifInfo properties', () => {
|
||||||
it('returns the correct count of non-null exifInfo properties', () => {
|
const asset = { exifInfo: { fileSizeInByte: 200, rating: 5, fNumber: null } };
|
||||||
const asset = { exifInfo: { fileSizeInByte: 200, rating: 5, fNumber: null } };
|
expect(getExifCount(asset as AssetResponseDto)).toBe(2);
|
||||||
expect(getExifCount(asset as AssetResponseDto)).toBe(2);
|
});
|
||||||
});
|
|
||||||
|
it('ignores null, undefined and empty properties in exifInfo', () => {
|
||||||
it('ignores null, undefined and empty properties in exifInfo', () => {
|
const asset = { exifInfo: { fileSizeInByte: 200, rating: null, fNumber: undefined, description: '' } };
|
||||||
const asset = { exifInfo: { fileSizeInByte: 200, rating: null, fNumber: undefined, description: '' } };
|
expect(getExifCount(asset as AssetResponseDto)).toBe(1);
|
||||||
expect(getExifCount(asset as AssetResponseDto)).toBe(1);
|
});
|
||||||
});
|
|
||||||
|
it('returns the correct count when all exifInfo properties are non-null', () => {
|
||||||
it('returns the correct count when all exifInfo properties are non-null', () => {
|
const asset = { exifInfo: { fileSizeInByte: 200, rating: 5, fNumber: 1, description: 'test' } };
|
||||||
const asset = { exifInfo: { fileSizeInByte: 200, rating: 5, fNumber: 1, description: 'test' } };
|
expect(getExifCount(asset as AssetResponseDto)).toBe(4);
|
||||||
expect(getExifCount(asset as AssetResponseDto)).toBe(4);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
import type { AssetResponseDto } from '@immich/sdk';
|
||||||
|
|
||||||
export const getExifCount = (asset: AssetResponseDto) => {
|
export const getExifCount = (asset: AssetResponseDto) => {
|
||||||
return Object.values(asset.exifInfo ?? {}).filter(Boolean).length;
|
return Object.values(asset.exifInfo ?? {}).filter(Boolean).length;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue