feat: tag management — scrape, edit, search existing, import to Mealie/Tandoor
- Scraper extracts tags from mindmegette.hu (<a class="tag">) and schema.org keywords - Tag editor UI with removable chips, search/autocomplete for existing tags, custom add - Mealie: auto-create tags via POST /api/organizers/tags, include in recipe PATCH - Tandoor: include keywords in recipe POST (auto-created by name) - New GET /tags endpoint returns existing tags from both services for search Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+40
-1
@@ -63,10 +63,22 @@ class MealieClient:
|
||||
}
|
||||
return None
|
||||
|
||||
def list_tags(self) -> list[dict]:
|
||||
"""Return all tags as [{name, slug, id}]."""
|
||||
r = self.session.get(
|
||||
f"{self.api_url}/api/organizers/tags",
|
||||
params={"page": 1, "perPage": -1},
|
||||
timeout=10,
|
||||
)
|
||||
if not r.ok:
|
||||
return []
|
||||
return [{"name": t["name"], "slug": t["slug"], "id": t["id"]}
|
||||
for t in r.json().get("items", [])]
|
||||
|
||||
def create_recipe(self, recipe: dict) -> str:
|
||||
"""Create a recipe in Mealie from a scraper result dict.
|
||||
|
||||
*recipe* keys: title, description, image_url, ingredients, instructions, original_url.
|
||||
*recipe* keys: title, description, image_url, ingredients, instructions, tags, original_url.
|
||||
Returns the recipe slug.
|
||||
"""
|
||||
# Step 1: create stub
|
||||
@@ -80,6 +92,12 @@ class MealieClient:
|
||||
|
||||
# Step 2: build full payload and PATCH
|
||||
payload = self._build_payload(recipe)
|
||||
|
||||
# Step 2b: resolve tags (create if needed, get {id, name, slug})
|
||||
tag_names = recipe.get("tags", [])
|
||||
if tag_names:
|
||||
payload["tags"] = self._ensure_tags(tag_names)
|
||||
|
||||
r = self.session.patch(
|
||||
f"{self.api_url}/api/recipes/{slug}",
|
||||
json=payload,
|
||||
@@ -173,6 +191,27 @@ class MealieClient:
|
||||
return entry
|
||||
return None
|
||||
|
||||
def _ensure_tags(self, tag_names: list[str]) -> list[dict]:
|
||||
"""Create tags that don't exist yet, return [{id, name, slug}] for all."""
|
||||
existing = {t["name"].lower(): t for t in self.list_tags()}
|
||||
result = []
|
||||
for name in tag_names:
|
||||
key = name.lower()
|
||||
if key in existing:
|
||||
result.append(existing[key])
|
||||
else:
|
||||
r = self.session.post(
|
||||
f"{self.api_url}/api/organizers/tags",
|
||||
json={"name": name},
|
||||
timeout=10,
|
||||
)
|
||||
if r.ok:
|
||||
t = r.json()
|
||||
tag = {"id": t["id"], "name": t["name"], "slug": t["slug"]}
|
||||
existing[key] = tag
|
||||
result.append(tag)
|
||||
return result
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Internal
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user