feat: duplicate detection + original URL in description

- Add original recipe URL to Mealie description (appended after blank line)
- Check for duplicate recipes on scrape (match orgURL or URL in description)
- Show warning with link to existing recipe if duplicate found
- User can still import anyway (warning only, not blocking)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 09:02:53 +01:00
parent a27b322409
commit f7810ba33d
4 changed files with 63 additions and 4 deletions
+41 -2
View File
@@ -29,6 +29,40 @@ class MealieClient:
r.raise_for_status()
return r.json()
def find_duplicate(self, url: str, title: str = "") -> dict | None:
"""Check if a recipe with this original URL already exists.
Searches by URL in orgURL and description fields.
Returns {"slug": ..., "name": ..., "url": ...} or None.
"""
if not url:
return None
# Search by title to find candidates (Mealie search matches name)
search_term = title or url.split("/")[-1].replace("-", " ")
r = self.session.get(
f"{self.api_url}/api/recipes",
params={"search": search_term, "perPage": 50},
timeout=10,
)
if not r.ok:
return None
for item in r.json().get("items", []):
detail = self.session.get(
f"{self.api_url}/api/recipes/{item['slug']}", timeout=10
)
if not detail.ok:
continue
data = detail.json()
org = data.get("orgURL", "") or ""
desc = data.get("description", "") or ""
if org == url or url in desc:
return {
"slug": data["slug"],
"name": data.get("name", data["slug"]),
"url": f"{self.base_url}/g/home/r/{data['slug']}",
}
return None
def create_recipe(self, recipe: dict) -> str:
"""Create a recipe in Mealie from a scraper result dict.
@@ -175,12 +209,17 @@ class MealieClient:
"ingredientReferences": [],
})
description = recipe.get("description", "")
original_url = recipe.get("original_url", "")
if original_url and original_url not in description:
description = f"{description}\n\n{original_url}".strip()
return {
"name": recipe["title"],
"description": recipe.get("description", ""),
"description": description,
"recipeIngredient": ingredients,
"recipeInstructions": instructions,
"orgURL": recipe.get("original_url", ""),
"orgURL": original_url,
"recipeYield": "",
}