Rename, convert, and upload new gallery photos to Cloudflare R2, then update photos.yaml. Use when the user has new photos to add to the gallery.
Process and upload new gallery photos to Cloudflare R2.
Input: Optionally specify the source directory containing new photos. Defaults to photo_temp/.
All photos must follow this format:
YYYYMMDD-{CAMERA_ID}.JPG
YYYYMMDD — the date the photo was taken- (hyphen only, never _)DSC01753, R0000754).JPG (uppercase)List all files in the source directory. Classify each file:
| Category | Detection | Action |
|---|
| Already correct | Matches YYYYMMDD-*.JPG | No change needed |
| Lowercase extension | Matches YYYYMMDD-*.jpg | mv to .JPG |
| Missing date prefix | No YYYYMMDD- prefix | Extract date from EXIF via mdls -name kMDItemContentCreationDate <file>, then rename |
| Underscore separator | Contains _ between date and ID | Replace _ with - |
| PNG format | .png or .PNG extension | Convert to JPEG |
Report the inventory to the user and ask for confirmation before proceeding. If any files are missing a date prefix and EXIF data is unavailable, ask the user to provide the date.
Process files in this order:
sips:
sips -s format jpeg "<input>.png" --out "<output>.JPG"
.jpg to .JPG: Use mv_ with -YYYYMMDD-.png files after successful conversionAfter processing, list all files and confirm they match YYYYMMDD-{CAMERA_ID}.JPG.
IMPORTANT: sips -g pixelWidth/pixelHeight returns raw pixel dimensions and ignores EXIF orientation. Photos taken in portrait mode may report landscape dimensions (e.g. 6192x4128 instead of 4128x6192). Use mdls to get the display-correct dimensions:
mdls -name kMDItemPixelWidth -name kMDItemPixelHeight <file>
mdls applies the EXIF orientation tag, so kMDItemPixelWidth and kMDItemPixelHeight reflect the actual display orientation. Always use mdls values for width and height in photos.yaml.
After obtaining all dimensions, run a cross-check on every photo to catch orientation mismatches:
for f in *.JPG; do
sw=$(sips -g pixelWidth "$f" 2>/dev/null | awk '/pixelWidth/{print $2}')
sh=$(sips -g pixelHeight "$f" 2>/dev/null | awk '/pixelHeight/{print $2}')
mw=$(mdls -name kMDItemPixelWidth "$f" | awk '{print $3}')
mh=$(mdls -name kMDItemPixelHeight "$f" | awk '{print $3}')
if [ "$sw" != "$mw" ] || [ "$sh" != "$mh" ]; then
echo "MISMATCH: $f sips=${sw}x${sh} mdls=${mw}x${mh}"
fi
done
Any file that shows MISMATCH has an EXIF orientation rotation — use the mdls values (not sips) for that file's width and height in photos.yaml.
Upload each file using wrangler with the --remote flag (critical — without it, files only go to local storage):
npx wrangler r2 object put "xuno8-photos/<filename>" --file="<source>/<filename>" --remote
After uploading, verify at least 2-3 files via the public URL:
curl -sI "https://images.xuno8.com/<filename>" | head -3
Expect HTTP/2 200 with content-type: image/jpeg.
src/data/photos.yamlAppend new entries to src/data/photos.yaml. Each entry has this format:
- src: 'YYYYMMDD-CAMERA_ID.JPG'
alt: 'YYYYMMDD-CAMERA_ID'
width: <pixelWidth>
height: <pixelHeight>
src: the exact filename uploaded to R2alt: same as filename without extensionwidth / height: pixel dimensions from step 3npm run build to confirm the site builds successfully