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
+35
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
from datetime import datetime, timedelta, timezone
import httpx
@@ -69,3 +71,36 @@ class ImmichClient:
)
resp.raise_for_status()
return resp.content, resp.headers.get("content-type", "image/jpeg")
def get_asset(self, asset_id: str) -> dict:
"""Full asset metadata, including embedded exifInfo (location,
capture date) -- used for the manage-button overlay's location/
date-taken text."""
resp = httpx.get(f"{self.base_url}/api/assets/{asset_id}", headers=self._headers, timeout=10)
resp.raise_for_status()
return resp.json()
def create_share_link(self, asset_id: str, expires_in_s: int) -> str:
"""Creates a public, view-only Immich share link for a single
asset, expiring expires_in_s seconds from now, and returns its
public URL. Used by the manage-button overlay's share QR --
created lazily (only when someone actually scans it), not when
the button's pressed, so the expiry clock starts when it's
actually used."""
expires_at = (datetime.now(timezone.utc) + timedelta(seconds=expires_in_s)).isoformat()
resp = httpx.post(
f"{self.base_url}/api/shared-links",
headers=self._headers,
json={
"type": "INDIVIDUAL",
"assetIds": [asset_id],
"expiresAt": expires_at,
"allowUpload": False,
"allowDownload": True,
"showMetadata": True,
},
timeout=10,
)
resp.raise_for_status()
key = resp.json()["key"]
return f"{self.base_url}/share/{key}"