Fix "Show next" staleness bug; add location/date/share-QR to manage overlay
Build and push server image / build-and-push (push) Successful in 32s

Two changes, bundled since they landed in the same session and touch
overlapping files:

1. Fix: "Show next" sent the browser's full queue snapshot to
   POST /api/queue/reorder, which hard-rejected if the server's queue
   had shifted since the last fetch (e.g. right after a queue-length
   trim). New POST /api/queue/promote moves one photo to the front
   authoritatively, with no dependency on client staleness. /reorder
   itself is now tolerant too -- unrecognized IDs are dropped and
   missing ones appended, instead of rejecting the whole request.

2. Feature: the manage button's overlay now also shows the photo's
   location (top-left, only if Immich reverse-geocoded it from GPS
   EXIF), the date it was taken (bottom-right), and a QR code (bottom-
   left) linking to a 30-minute public Immich share link -- created
   lazily when someone actually scans it, not when the button's
   pressed. New server endpoints GET /frame/photo-info and
   GET /frame/share/{asset_id} (scoped to the frame's current/queued
   photos, not any arbitrary Immich asset). Firmware-side, the overlay
   mechanism generalizes from one spliced region to up to four
   (manage_qr_overlay.c), each its own small buffer, still never
   holding the full frame in RAM.
This commit is contained in:
2026-07-19 01:28:25 -04:00
parent 42d7c09f97
commit a358045cea
8 changed files with 523 additions and 83 deletions
+29 -5
View File
@@ -48,11 +48,32 @@ algorithm itself -- it just streams the response straight to the panel.
button (see `firmware/README.md`).
- `GET /frame/config` -- `{"refresh_interval_s": ...}`, polled by the frame
each wake alongside its reachability check
- `GET /frame/photo-info` -- `{"asset_id": ..., "location": ... | null,
"taken_at": ... | null}` for the current photo (same idempotent
current-photo semantics as `/frame/image`). `location` is `city, state`
(or `city, country`, or just `city`) if Immich reverse-geocoded the
photo's GPS EXIF, else `null`; `taken_at` is `MM/DD/YY` from the
photo's EXIF capture date, else `null`. Used by the device's manage
button to build its overlay text
- `GET /frame/share/{asset_id}` -- creates a 30-minute public, view-only
Immich share link for `asset_id` and redirects (302) to it. Only works
for the photo currently showing or in the upcoming queue on this frame
-- not any arbitrary Immich asset. The link is created on first hit
(i.e. when someone actually scans the manage overlay's share QR), not
when the button's pressed, so the 30-minute window starts when it's
actually used
- `GET /api/queue` -- `{"current": {...} | null, "upcoming": [...]}`, each
entry an asset id + thumbnail URL; used by the config UI
- `POST /api/queue/reorder` -- reorders the upcoming queue; body is
`{"queue": [asset_id, ...]}`, must be exactly a permutation of the
current queue
`{"queue": [asset_id, ...]}`. Tolerant of drift from the queue having
changed server-side since the client's last fetch (e.g. a top-up/trim)
-- unrecognized IDs in the body are dropped, and any currently-queued
photo missing from the body is appended rather than lost, instead of
rejecting the whole request
- `POST /api/queue/promote` -- moves one photo to the front of the queue;
body is `{"asset_id": "..."}`. Used by "Show next" in the web UI --
unlike `/reorder`, doesn't depend on the client knowing the queue's
full current order, so it can't fail from staleness
- `GET /api/photo-thumbnail/{asset_id}` -- proxies an Immich thumbnail so
the browser never needs the Immich API key directly
- `GET /health` -- liveness check
@@ -72,9 +93,12 @@ algorithm itself -- it just streams the response straight to the panel.
in sequential or shuffle order per the Order setting. Dragging photos
in the web UI (or using "Show next") only rearranges what's already in
that lookahead; it doesn't add or remove photos from the album.
- `/frame/image` and `/frame/advance` aren't authenticated yet. That's
fine on a trusted home LAN for now, but worth revisiting once the ESP32
side is wired up to send a shared device token.
- `/frame/image`, `/frame/advance`, `/frame/photo-info`, and
`/frame/share/{asset_id}` aren't authenticated yet. That's fine on a
trusted home LAN for now, but worth revisiting once the ESP32 side is
wired up to send a shared device token. `/frame/share` at least is
scoped to only ever create a link for a photo this frame is actually
showing or has queued, not any Immich asset ID someone might guess.
- The 6-color palette RGB values in `app/image_pipeline.py` are
approximations, not measured values (Waveshare doesn't publish exact
color primaries for this panel) -- tune them once you can compare a