feat: M1 foundation packages + trip-cluster app #1

Merged
m038 merged 19 commits from feat/m1-foundation-trip-cluster into master 2026-06-27 19:10:50 +02:00
5 changed files with 60 additions and 1 deletions
Showing only changes of commit da5b1de2a2 - Show all commits
+2 -1
View File
@@ -1,3 +1,4 @@
from photoflow.immich.client import ImmichClient from photoflow.immich.client import ImmichClient
from photoflow.immich import pipeline
__all__ = ["ImmichClient"] __all__ = ["ImmichClient", "pipeline"]
+19
View File
@@ -72,3 +72,22 @@ class ImmichClient:
timeout=self.timeout) timeout=self.timeout)
r.raise_for_status() r.raise_for_status()
return r.content return r.content
def upsert_tag(self, name: str) -> str:
r = self.session.put(self._url("/api/tags"),
json={"tags": [name]}, timeout=self.timeout)
r.raise_for_status()
for tag in r.json():
if tag.get("value") == name or tag.get("name") == name:
return tag["id"]
resolved = self.resolve_tag_id(name)
if resolved is None:
raise RuntimeError(f"upsert_tag: could not resolve id for {name!r}")
return resolved
def tag_assets(self, tag_id: str, asset_ids: list[str]) -> None:
if not asset_ids:
return
r = self.session.put(self._url(f"/api/tags/{tag_id}/assets"),
json={"ids": asset_ids}, timeout=self.timeout)
r.raise_for_status()
+11
View File
@@ -0,0 +1,11 @@
ROOT = "_pipeline"
PROCESSED = f"{ROOT}/processed"
NON_TRIP = f"{ROOT}/non-trip"
def ai_rating(n: int) -> str:
return f"{ROOT}/ai-rating/{n}"
def is_pipeline_tag(name: str) -> bool:
return name == ROOT or name.startswith(ROOT + "/")
+13
View File
@@ -48,3 +48,16 @@ def test_download_thumbnail(httpserver):
b"\xff\xd8\xffjpegbytes", content_type="image/jpeg") b"\xff\xd8\xffjpegbytes", content_type="image/jpeg")
c = ImmichClient(httpserver.url_for(""), "k") c = ImmichClient(httpserver.url_for(""), "k")
assert c.download_thumbnail("a").startswith(b"\xff\xd8\xff") assert c.download_thumbnail("a").startswith(b"\xff\xd8\xff")
def test_upsert_tag_returns_id_by_value(httpserver):
httpserver.expect_request("/api/tags", method="PUT").respond_with_json(
[{"id": "p1", "name": "non-trip", "value": "_pipeline/non-trip"}])
c = ImmichClient(httpserver.url_for(""), "k")
assert c.upsert_tag("_pipeline/non-trip") == "p1"
def test_tag_assets_posts_ids(httpserver):
httpserver.expect_request("/api/tags/p1/assets", method="PUT").respond_with_json({"ok": True})
c = ImmichClient(httpserver.url_for(""), "k")
c.tag_assets("p1", ["a", "b"]) # should not raise
+15
View File
@@ -0,0 +1,15 @@
from photoflow.immich import pipeline
def test_constants_and_helpers():
assert pipeline.ROOT == "_pipeline"
assert pipeline.PROCESSED == "_pipeline/processed"
assert pipeline.NON_TRIP == "_pipeline/non-trip"
assert pipeline.ai_rating(4) == "_pipeline/ai-rating/4"
def test_is_pipeline_tag():
assert pipeline.is_pipeline_tag("_pipeline/processed") is True
assert pipeline.is_pipeline_tag("_pipeline") is True
assert pipeline.is_pipeline_tag("Italy 2019") is False
assert pipeline.is_pipeline_tag("Kiev") is False