From 34a3293a072aaece5f8749ae8ff0649bb2d4ecec Mon Sep 17 00:00:00 2001 From: Thomas Faour Date: Sat, 18 Jul 2026 15:19:05 -0400 Subject: [PATCH] Fix /frame/image 404: Immich v3 doesn't embed assets in album responses GET /api/albums/{id} was assumed to return an "assets" array alongside the album metadata (that's what the original plan/prior art expected), but on Immich 3.0.3 AlbumResponseDto only has assetCount -- no assets field at all. Confirmed against the OpenAPI spec served at /api/spec.json and by testing directly against a real instance: the assumption was simply wrong for this API version, not a permissions issue (the album metadata call succeeds fine with a valid 200). Assets for an album now come from POST /api/search/metadata with an albumIds filter, which returns them under assets.items. Verified end-to-end against the real Immich instance and album -- /frame/image now returns a proper 200 with exactly 192,000 bytes, spread across all six panel colors (not a degenerate all-white/black response). Only fetches the first page of search results; fine for a photo frame cycling through an album, but would need nextPage handling for anyone pointing this at a very large album. --- server/app/immich_client.py | 19 ++++++++++++++++--- server/app/main.py | 3 +-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/server/app/immich_client.py b/server/app/immich_client.py index fe32743..21d6c06 100644 --- a/server/app/immich_client.py +++ b/server/app/immich_client.py @@ -15,10 +15,23 @@ class ImmichClient: resp.raise_for_status() return resp.json() - def get_album(self, album_id: str) -> dict: - resp = httpx.get(f"{self.base_url}/api/albums/{album_id}", headers=self._headers, timeout=10) + def list_album_assets(self, album_id: str) -> list[dict]: + """GET /api/albums/{id} doesn't embed assets in this Immich version + (AlbumResponseDto only has assetCount) -- assets live behind the + general search API instead, filtered by albumIds. + + Only returns the first page. Fine for a photo frame cycling + through an album; worth adding nextPage pagination if someone + points this at an album large enough to need it. + """ + resp = httpx.post( + f"{self.base_url}/api/search/metadata", + headers=self._headers, + json={"albumIds": [album_id]}, + timeout=15, + ) resp.raise_for_status() - return resp.json() + return resp.json().get("assets", {}).get("items", []) def download_asset_preview(self, asset_id: str) -> bytes: resp = httpx.get( diff --git a/server/app/main.py b/server/app/main.py index 5f10348..bfe36d0 100644 --- a/server/app/main.py +++ b/server/app/main.py @@ -71,11 +71,10 @@ def frame_image(): client = ImmichClient(cfg.immich_url, cfg.immich_api_key) try: - album = client.get_album(cfg.album_id) + assets = client.list_album_assets(cfg.album_id) except httpx.HTTPError as e: raise HTTPException(502, f"Could not reach Immich at {cfg.immich_url}: {e}") from e - assets = album.get("assets", []) if not assets: raise HTTPException(404, "Album has no photos")