feat: editable taken_at + folder-based date repair and filter

Lets operators fix corrupted capture dates at scale. Adds an editable
Date Taken field with a folder/filename-derived suggestion hint, a bulk
Date Taken section in the multi-select sidebar that either applies one
date to the whole selection or infers a per-photo date from each path,
a warning badge on thumbnails whose stored date disagrees with the
path, and a "Date issues" filter pill so suspicious photos can be
surfaced and fixed as a group. Edits are written back to EXIF on disk
so rescans don't clobber the fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 11:48:55 +02:00
parent 339e1be510
commit 30d03d8d4d
19 changed files with 1281 additions and 26 deletions

View File

@@ -185,6 +185,39 @@ export const photos = {
return response.data
},
/** Bulk set taken_at — one ISO datetime applied to every listed photo.
* Backend rewrites EXIF on disk per-photo and surfaces per-photo errors
* in the `errors` array so the UI can report a partial apply. */
bulkSetTakenAt: async (photoIds: string[], isoDatetime: string) => {
const response = await api.post('/photos/bulk', {
ids: photoIds,
action: 'set_taken_at',
value: isoDatetime,
})
return response.data as {
status: string
updated: number
skipped: number
errors: { id: string; message: string }[]
}
},
/** Bulk set taken_at with a per-photo map. Used by the "guess from folder"
* flow where every selected photo gets its own suggested date. */
bulkSetTakenAtMap: async (map: Record<string, string>) => {
const response = await api.post('/photos/bulk', {
ids: Object.keys(map),
action: 'set_taken_at_map',
value: map,
})
return response.data as {
status: string
updated: number
skipped: number
errors: { id: string; message: string }[]
}
},
/** Add the listed tags to every listed photo. Idempotent — re-adding
* an existing (photo, tag) pair is a no-op. Returns { added: N }. */
bulkAddTags: async (photoIds: string[], tagIds: string[]) => {