feat: add Immich API client and photo proxy routes

Implements ImmichClient with list_albums, get_album, get_thumbnail,
get_original methods; wraps connection errors as ConnectionError.
Adds /proxy/thumb/<asset_id> and /proxy/original/<asset_id> Flask routes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 15:55:26 +02:00
parent 102ad7b77b
commit 203737cc3f
3 changed files with 107 additions and 1 deletions
+30
View File
@@ -0,0 +1,30 @@
import requests
class ImmichClient:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url.rstrip("/")
self.headers = {"Authorization": f"Bearer {api_key}"}
def _get(self, path: str, **kwargs):
try:
r = requests.get(f"{self.base_url}{path}",
headers=self.headers, timeout=10, **kwargs)
r.raise_for_status()
return r
except requests.exceptions.ConnectionError as e:
raise ConnectionError(f"Cannot reach Immich: {e}") from e
def list_albums(self) -> list:
return self._get("/api/albums").json()
def get_album(self, album_id: str) -> dict:
return self._get(f"/api/albums/{album_id}",
params={"withoutAssets": "false"}).json()
def get_thumbnail(self, asset_id: str) -> bytes:
return self._get(f"/api/assets/{asset_id}/thumbnail",
params={"size": "preview"}).content
def get_original(self, asset_id: str) -> bytes:
return self._get(f"/api/assets/{asset_id}/original").content
+27 -1
View File
@@ -1,3 +1,29 @@
from flask import Blueprint
from flask import Blueprint, current_app, Response, abort
from app.immich import ImmichClient
bp = Blueprint("proxy", __name__)
def _client() -> ImmichClient:
return ImmichClient(
base_url=current_app.config["IMMICH_URL"],
api_key=current_app.config["IMMICH_API_KEY"],
)
@bp.get("/proxy/thumb/<asset_id>")
def thumb(asset_id):
try:
data = _client().get_thumbnail(asset_id)
except ConnectionError:
abort(502)
return Response(data, content_type="image/jpeg")
@bp.get("/proxy/original/<asset_id>")
def original(asset_id):
try:
data = _client().get_original(asset_id)
except ConnectionError:
abort(502)
return Response(data, content_type="image/jpeg")