diff --git a/services/travel-memories/app/immich.py b/services/travel-memories/app/immich.py new file mode 100644 index 0000000..5e34a0e --- /dev/null +++ b/services/travel-memories/app/immich.py @@ -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 diff --git a/services/travel-memories/app/routes/proxy.py b/services/travel-memories/app/routes/proxy.py index e3ff80e..5a7f520 100644 --- a/services/travel-memories/app/routes/proxy.py +++ b/services/travel-memories/app/routes/proxy.py @@ -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/") +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/") +def original(asset_id): + try: + data = _client().get_original(asset_id) + except ConnectionError: + abort(502) + return Response(data, content_type="image/jpeg") diff --git a/services/travel-memories/tests/test_immich.py b/services/travel-memories/tests/test_immich.py new file mode 100644 index 0000000..8db956e --- /dev/null +++ b/services/travel-memories/tests/test_immich.py @@ -0,0 +1,50 @@ +import pytest +from app.immich import ImmichClient + + +@pytest.fixture +def client(mock_immich): + return ImmichClient( + base_url=f"http://127.0.0.1:8099", + api_key="test-key", + ) + + +def test_list_albums(client): + albums = client.list_albums() + assert len(albums) == 1 + assert albums[0]["albumName"] == "Central Asia 2023" + + +def test_get_album(client): + album = client.get_album("album-1") + assert len(album["assets"]) == 3 + + +def test_get_thumbnail_returns_bytes(client): + data = client.get_thumbnail("asset-1") + assert isinstance(data, bytes) + assert len(data) > 0 + + +def test_get_original_returns_bytes(client): + data = client.get_original("asset-1") + assert isinstance(data, bytes) + + +def test_list_albums_connection_error_raises(monkeypatch): + client = ImmichClient(base_url="http://127.0.0.1:1", api_key="x") + with pytest.raises(ConnectionError): + client.list_albums() + + +def test_proxy_thumb_route(base_url, page, seed_state): + seed_state("phase2_state") + page.goto(f"{base_url}/proxy/thumb/asset-1") + assert page.evaluate("document.contentType").startswith("image/") + + +def test_proxy_original_route(base_url, page, seed_state): + seed_state("phase2_state") + page.goto(f"{base_url}/proxy/original/asset-1") + assert page.evaluate("document.contentType").startswith("image/")