Files
picpeak/backend
Paul Nothaft f3d0f161c9 fix(external-media): pre-generate thumbnails so reference-mode galleries load fast (#423)
External (source_origin='external') photos always had thumbnail_path=NULL,
so the gallery returned thumbnail_url=null and every layout fell back to
streaming the full original from the NAS via the secure-image route.
With ~100 NAS-mounted photos that meant minutes of wall-clock load time,
sequential per tile.

Two halves:

1. import-external route generates the thumbnail right after each
   successful insert and writes thumbnail_path on the row. Best-effort:
   a single failure logs a warning and leaves thumbnail_path=NULL —
   ensureThumbnail will retry lazily on first view. Synchronous in the
   loop adds ~100-300ms per image; for the worst-case 1000-photo import
   that's still under the typical request timeout.

2. ensureThumbnail() in imageProcessor handles external photos too —
   resolves the local NAS mount path via resolvePhotoFilePath instead of
   the storage-backend key. This covers existing externals already in
   the database that were imported before this fix: first gallery view
   per photo regenerates the thumbnail, subsequent views are fast.

Filename-collision protection: external thumbnails use
`thumb_ext<photoId>_<basename>` so two events both referencing
e.g. `IMG_0001.jpg` on different NAS subtrees can't clobber each other's
thumbnail. generateThumbnail accepts a new options.outputBasename to
support this without changing the managed-photo behaviour.

Verified locally with a 3-photo external dir and a real NAS-style import:
  POST /api/admin/external-media/events/N/import-external
  → {imported:3, thumbnailsGenerated:3, thumbnailsFailed:0}
  /api/gallery/<slug>/photos returns thumbnail_url for every photo
  Lazy-regen path: clearing thumbnail_path + deleting the file, then
  hitting /thumbnail/N regenerates and repopulates the row in 42ms.

Closes #423.
2026-05-08 19:17:15 +02:00
..