import { t } from '@/i18n' import type { MediaItem } from '@/composables/useMedia' import { formatDimensions, formatSize } from '@/lib/mediaFormat' export interface DuplicateGroup { hash: string copies: MediaItem[] suggested: MediaItem header: string } function byAge(first: MediaItem, second: MediaItem) { return Date.parse(first.created_at) - Date.parse(second.created_at) || first.id - second.id } function byPreference(first: MediaItem, second: MediaItem) { return second.used_in - first.used_in || byAge(first, second) } export function groupHeader(copies: MediaItem[]) { const [first] = copies return t('{0} identical images · {1} each · {2}', [ copies.length, formatSize(first!.size), formatDimensions(first!.width, first!.height), ]) } export function groupDuplicates(items: MediaItem[]): DuplicateGroup[] { const byHash = new Map() for (const item of items) { byHash.set(item.sha256, [...(byHash.get(item.sha256) ?? []), item]) } return [...byHash.entries()] .filter(([, copies]) => copies.length > 1) .map(([hash, copies]) => { const sorted = [...copies].sort(byPreference) return { hash, copies: sorted, suggested: sorted[0]!, get header() { return groupHeader(sorted) }, } }) .sort((first, second) => byAge(first.suggested, second.suggested)) } export function mergeArticleCount(copies: MediaItem[], keepId: number) { return copies .filter((copy) => copy.id !== keepId) .reduce((total, copy) => total + copy.used_in, 0) }