feat: settings panel + thumbnail pipeline fixes
- photos.py: stop crashing in FileResponse when a thumb hasn't been generated; return a clean 404 with Retry-After so the frontend can back off. - thumbs.py: fix process_video_thumbnail (overwrite_output, robust duration probe across stream/format, eager frame load + temp cleanup) so videos stop ending up as the gray placeholder. - library.py: new /maintenance/* endpoints — thumbnail-stats, regenerate-thumbnails (with media_type / only_failed filters), and a manual data-integrity cleanup trigger. - Frontend Settings panel (gear in TopBar) surfacing those endpoints plus a re-scan button and live thumbnail status counts. - PhotoThumbnail: stretch the auto-retry schedule for slow RAW jobs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -207,6 +207,29 @@ export const photos = {
|
||||
}
|
||||
|
||||
// Library API
|
||||
export type MediaType = 'photo' | 'raw' | 'heic' | 'video'
|
||||
|
||||
export interface ThumbnailStats {
|
||||
total: number
|
||||
pending: number
|
||||
processing: number
|
||||
completed: number
|
||||
failed: number
|
||||
by_media_type: Record<string, number>
|
||||
}
|
||||
|
||||
export interface RegenerateResult {
|
||||
status: string
|
||||
matched: number
|
||||
queued: number
|
||||
cleared_dirs: number
|
||||
file_errors: number
|
||||
filters: {
|
||||
media_types: MediaType[] | null
|
||||
only_failed: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const library = {
|
||||
scan: async () => {
|
||||
const response = await api.post('/library/scan')
|
||||
@@ -222,6 +245,33 @@ export const library = {
|
||||
const response = await api.get('/library/stats')
|
||||
return response.data
|
||||
},
|
||||
|
||||
/** Maintenance / admin actions surfaced via the Settings panel. */
|
||||
maintenance: {
|
||||
thumbnailStats: async (): Promise<ThumbnailStats> => {
|
||||
const response = await api.get('/library/maintenance/thumbnail-stats')
|
||||
return response.data
|
||||
},
|
||||
|
||||
/** Reset on-disk thumbs and re-queue Celery generation. With no
|
||||
* filters, every photo in the library is re-queued. */
|
||||
regenerateThumbnails: async (
|
||||
body: { media_types?: MediaType[]; only_failed?: boolean } = {}
|
||||
): Promise<RegenerateResult> => {
|
||||
const response = await api.post(
|
||||
'/library/maintenance/regenerate-thumbnails',
|
||||
body
|
||||
)
|
||||
return response.data
|
||||
},
|
||||
|
||||
/** Re-run the source-roots / folders / photos integrity cleanup that
|
||||
* normally runs on backend startup. */
|
||||
cleanup: async (): Promise<{ status: string; message?: string }> => {
|
||||
const response = await api.post('/library/maintenance/cleanup')
|
||||
return response.data
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export interface LibraryStats {
|
||||
|
||||
Reference in New Issue
Block a user