feat(web): bulk deduplicate (#10448)

* bulk deduplicate

* notification for keeping all duplicates

* fix notification

* remove unused text

* pr feedback

* wording

* formatting
This commit is contained in:
Mert
2024-06-19 12:11:59 -04:00
committed by GitHub
parent 86cbc6e125
commit b3f9641edf
4 changed files with 123 additions and 24 deletions

View File

@@ -4,9 +4,9 @@
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import DuplicateAsset from '$lib/components/utilities-page/duplicates/duplicate-asset.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { suggestDuplicateByFileSize } from '$lib/utils';
import { type AssetResponseDto } from '@immich/sdk';
import { mdiCheck, mdiTrashCanOutline } from '@mdi/js';
import { sortBy } from 'lodash-es';
import { onDestroy, onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -20,7 +20,7 @@
$: trashCount = assets.length - selectedAssetIds.size;
onMount(() => {
const suggestedAsset = sortBy(assets, (asset) => asset.exifInfo?.fileSizeInByte).pop();
const suggestedAsset = suggestDuplicateByFileSize(assets);
if (!suggestedAsset) {
selectedAssetIds = new Set(assets[0].id);

View File

@@ -323,6 +323,9 @@
"back": "Back",
"backward": "Backward",
"blurred_background": "Blurred background",
"bulk_delete_duplicates_confirmation": "Are you sure you want to bulk delete {count} duplicate assets? This will keep the largest asset of each group and permanently delete all other duplicates. You cannot undo this action!",
"bulk_keep_duplicates_confirmation": "Are you sure you want to keep {count} duplicate assets? This will resolve all duplicate groups without deleting anything.",
"bulk_trash_duplicates_confirmation": "Are you sure you want to bulk trash {count} duplicate assets? This will keep the largest asset of each group and trash all other duplicates.",
"camera": "Camera",
"camera_brand": "Camera brand",
"camera_model": "Camera model",
@@ -392,6 +395,7 @@
"date_before": "Date before",
"date_range": "Date range",
"day": "Day",
"deduplicate_all": "Deduplicate All",
"default_locale": "Default Locale",
"default_locale_description": "Format dates and numbers based on your browser locale",
"delete": "Delete",
@@ -699,6 +703,7 @@
"permanent_deletion_warning_setting_description": "Show a warning when permanently deleting assets",
"permanently_delete": "Permanently delete",
"permanently_deleted_asset": "Permanently deleted asset",
"permanently_deleted_assets": "Permanently deleted {count, plural, one {# asset} other {# assets}}",
"photos": "Photos",
"photos_count": "{count, plural, one {{count, number} Photo} other {{count, number} Photos}}",
"photos_from_previous_years": "Photos from previous years",
@@ -740,6 +745,7 @@
"reset": "Reset",
"reset_password": "Reset password",
"reset_people_visibility": "Reset people visibility",
"resolved_all_duplicates": "Resolved all duplicates",
"restore": "Restore",
"restore_all": "Restore all",
"restore_user": "Restore user",

View File

@@ -15,9 +15,11 @@ import {
linkOAuthAccount,
startOAuth,
unlinkOAuthAccount,
type AssetResponseDto,
type SharedLinkResponseDto,
} from '@immich/sdk';
import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiImageRefreshOutline } from '@mdi/js';
import { sortBy } from 'lodash-es';
import { t } from 'svelte-i18n';
import { derived, get } from 'svelte/store';
@@ -310,3 +312,7 @@ export const withError = async <T>(fn: () => Promise<T>): Promise<[undefined, T]
return [error, undefined];
}
};
export const suggestDuplicateByFileSize = (assets: AssetResponseDto[]): AssetResponseDto | undefined => {
return sortBy(assets, (asset) => asset.exifInfo?.fileSizeInByte).pop();
};