fix(import): capture photo dimensions in fileWatcher + s3AutoImporter (#447)

The aspect-aware gallery layouts (masonry / mosaic / justified) read
photo.width and photo.height to size each card to the source's real
proportions. Two import paths were inserting rows without those
fields, which forced MasonryGalleryLayout to fall back to a hard-coded
800×600 default — every card came out the same shape, so users
reported masonry as "always cropped to 1:1ish" no matter which
thumbnail fit mode they chose.

- fileWatcher.js: extract dims with sharp.metadata() before insert.
- s3AutoImporter.js: same, materialising a tmp local copy via
  withLocalCopy so it works in S3 mode.
- migration 090: backfill any pre-existing rows with NULL dims
  (skips videos, skips S3 deployments — those need the writer fix
  alone since migrations cannot reach the storage backend).
- imageProcessor.js: change DEFAULT_THUMBNAIL_FIT from 'cover' to
  'inside' (only kicks in when the seed setting is missing — existing
  installs keep their saved value). Add UI tooltip recommending
  'inside' for masonry/mosaic/justified, 'cover' for uniform grids.

i18n covers all six locales.
This commit is contained in:
Paul Nothaft
2026-05-11 09:58:08 +02:00
parent fe5295373b
commit 936a277eb8
11 changed files with 167 additions and 9 deletions
@@ -229,6 +229,9 @@ export const ThumbnailsTab: React.FC = () => {
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">
{t('settings.thumbnails.fitHelp', 'How images are resized to fit the thumbnail dimensions. "Cover" crops to fill, "Contain" fits within bounds.')}
</p>
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-2">
{t('settings.thumbnails.fitRecommendation', 'Recommendation: use "Inside" for masonry / mosaic / justified layouts (preserves aspect ratio); "Cover" for uniform 1:1 grid tiles.')}
</p>
</div>
</Card>
+2 -1
View File
@@ -1246,7 +1246,8 @@
"fit_contain": "Einpassen (innerhalb)",
"fit_fill": "Strecken",
"fit_inside": "Innen (verkleinern)",
"fit_outside": "Außen (vergrößern)"
"fit_outside": "Außen (vergrößern)",
"fitRecommendation": "Empfehlung: „Inside\" für Masonry-/Mosaic-/Justified-Layouts (bewahrt das Seitenverhältnis), „Cover\" für gleichförmige 1:1-Kacheln."
},
"categories": {
"title": "Kategorien",
+2 -1
View File
@@ -952,7 +952,8 @@
"fit_contain": "Contain (fit within)",
"fit_fill": "Fill (stretch)",
"fit_inside": "Inside (shrink to fit)",
"fit_outside": "Outside (expand to cover)"
"fit_outside": "Outside (expand to cover)",
"fitRecommendation": "Recommendation: use \"Inside\" for masonry / mosaic / justified layouts (preserves aspect ratio); \"Cover\" for uniform 1:1 grid tiles."
},
"seo": {
"title": "SEO & Robots",
+2 -1
View File
@@ -967,7 +967,8 @@
"fit_cover": "Recouvrir (recadrer pour remplir)",
"fit_contain": "Contenir (ajuster dans les limites)",
"fit_inside": "Intérieur (réduire pour ajuster)",
"fit_outside": "Extérieur (agrandir pour recouvrir)"
"fit_outside": "Extérieur (agrandir pour recouvrir)",
"fitRecommendation": "Recommandation : utilisez « Inside » pour les mises en page masonry/mosaic/justified (préserve les proportions) ; « Cover » pour des tuiles 1:1 uniformes."
},
"seo": {
"title": "SEO et Robots",
+2 -1
View File
@@ -952,7 +952,8 @@
"fit_contain": "Contain (passend binnen)",
"fit_fill": "Vullen (uitrekken)",
"fit_inside": "Binnenkant (verkleinen om te passen)",
"fit_outside": "Buitenkant (vergroten om te bedekken)"
"fit_outside": "Buitenkant (vergroten om te bedekken)",
"fitRecommendation": "Aanbeveling: gebruik \"Inside\" voor masonry/mosaic/justified-lay-outs (behoudt beeldverhouding); \"Cover\" voor uniforme 1:1-tegels."
},
"seo": {
"title": "SEO & Robots",
+2 -1
View File
@@ -969,7 +969,8 @@
"fit_contain": "Contain (ajustar ao espaço)",
"fit_fill": "Fill (esticar)",
"fit_inside": "Inside (encolher para caber)",
"fit_outside": "Outside (expandir para cobrir)"
"fit_outside": "Outside (expandir para cobrir)",
"fitRecommendation": "Recomendação: use \"Inside\" para layouts masonry/mosaic/justified (preserva proporção); \"Cover\" para tiles 1:1 uniformes."
},
"seo": {
"title": "SEO e Robots",
+2 -1
View File
@@ -1027,7 +1027,8 @@
"fit_contain": "Вписывание (внутри)",
"fit_fill": "Растягивание",
"fit_inside": "Внутри (уменьшить)",
"fit_outside": "Снаружи (увеличить)"
"fit_outside": "Снаружи (увеличить)",
"fitRecommendation": "Рекомендация: «Inside» для масонри/мозаики/выровненных раскладок (сохраняет пропорции); «Cover» для одинаковых плиток 1:1."
},
"photoDimensions": {
"title": "Размеры фотографий",