Replace the legacy mule-image backend with PhotoPrism plus a thin SvelteKit client and a Node sidecar for endpoints PhotoPrism doesn't expose (file rename), and add a two-phase migrator (metadata via PUT, heaps → albums) for the existing Postgres library. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
/**
|
|
* Adapter that shapes PhotoPrism's `q=stack:true` photo list into a
|
|
* `DuplicateGroup[]` the UI consumes. Mirrors mule-image's
|
|
* `DuplicateGroup` interface so the view code stays declarative.
|
|
*
|
|
* PhotoPrism's `/photos?merged=true` inlines `Files[]` on each row
|
|
* already — no follow-up GET per group needed (confirmed against
|
|
* photoprism/photoprism:latest, May 2026).
|
|
*/
|
|
|
|
import { listPhotos } from '$lib/services/photoprism';
|
|
import type { PpFile, PpPhoto } from '$lib/types/photoprism';
|
|
|
|
export interface DuplicateGroup {
|
|
/** The Photo record that owns this stack. Carries marks, keywords,
|
|
* taken_at — everything the metadata sidebar reads off of. */
|
|
photo: PpPhoto;
|
|
/** The variants the user picks among. Always 2+ entries; groups with
|
|
* a single file are filtered out (PhotoPrism shouldn't return them
|
|
* for `stack:true` anyway, but the guard is cheap). */
|
|
files: PpFile[];
|
|
/** Pre-selected "keep this" file = the one PhotoPrism marks Primary.
|
|
* The view starts with this highlighted and updates it on click. */
|
|
bestFileUid: string;
|
|
}
|
|
|
|
export async function listDuplicateGroups(): Promise<DuplicateGroup[]> {
|
|
const photos = await listPhotos({
|
|
q: 'stack:true',
|
|
count: 200,
|
|
merged: true,
|
|
order: 'newest'
|
|
});
|
|
return photos
|
|
.filter((p) => (p.Files?.length ?? 0) > 1)
|
|
.map((p) => {
|
|
const files = p.Files ?? [];
|
|
const primary = files.find((f) => f.Primary) ?? files[0];
|
|
return { photo: p, files, bestFileUid: primary.UID };
|
|
});
|
|
}
|