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:
2026-02-24 12:42:54 +01:00
parent 458b1e362a
commit bbd0889471
6 changed files with 314 additions and 8 deletions
+21
View File
@@ -45,6 +45,22 @@ class TandoorClient:
return {"version": version}
def list_keywords(self) -> list[dict]:
"""Return all keywords as [{name, id}]."""
results = []
page_url = f"{self.api_url}/api/keyword/"
params = {"limit": 100, "format": "json"}
while page_url:
r = self.session.get(page_url, params=params, timeout=10)
if not r.ok:
break
data = r.json()
results.extend({"name": k["name"], "id": k["id"]}
for k in data.get("results", []))
page_url = data.get("next")
params = {} # next URL already has params
return results
def find_duplicate(self, url: str, title: str = "") -> dict | None:
"""Check if a recipe with this source URL already exists."""
if not url and not title:
@@ -145,10 +161,15 @@ class TandoorClient:
"order": 0,
})
# Keywords (tags)
tag_names = recipe.get("tags", [])
keywords = [{"name": t} for t in tag_names] if tag_names else []
return {
"name": recipe["title"],
"description": description,
"source_url": original_url,
"keywords": keywords,
"steps": steps,
"servings": 1,
}