Add "now displaying" / "up next" preview pair to the frame header
Build and push server image / test (push) Successful in 37s
Build and push server image / build-and-push (push) Successful in 2m40s
Build and push server image / deploy (push) Successful in 57s

The server now records exactly what was last sent to the device on
every device-facing render (/frame/image, /frame/advance, /frame/back,
and the global hold actions), persisted as Frame.last_displayed_image/
_at and served back via GET /api/frames/{id}/now-displaying. The
header thumbnail is split into that frozen "now displaying" snapshot
and the existing live "up next" re-render, with an arrow between them
-- so editing a layout shows the change immediately on the right while
the left stays exactly what's actually on the panel until the device's
next real wake.
This commit is contained in:
2026-07-28 00:41:11 +00:00
parent 684225422c
commit aa4a382c1b
10 changed files with 373 additions and 70 deletions
+19
View File
@@ -271,6 +271,25 @@ def api_frame_preview(
return Response(content=png, media_type="image/png")
@router.get("/api/frames/{frame_id}/now-displaying")
def api_frame_now_displaying(frame: Frame = Depends(require_frame_view)):
"""Exactly what was last actually sent to this frame's device (see
routers/device.py's _record_last_displayed) -- the frozen "now
displaying" half of the header preview pair, as opposed to /preview's
always-live "up next" re-render. 404 (not a placeholder image) until
the device has fetched at least once, so the web UI can show its own
empty state instead of a broken image. X-Displayed-At carries the
capture time (unix seconds) for a "N ago" label -- a header, not the
body, since the body is the raw PNG bytes."""
if frame.last_displayed_image is None:
raise HTTPException(404, "This frame hasn't displayed anything yet")
return Response(
content=frame.last_displayed_image,
media_type="image/png",
headers={"X-Displayed-At": str(frame.last_displayed_at)},
)
@router.get("/api/frames/{frame_id}/battery-log")
def api_battery_log(frame: Frame = Depends(require_frame_view), db: Session = Depends(get_db)):
rows = db.execute(