From e746dc10c9f07bc78dceeddf9c245a1fef858a7c Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 26 Feb 2026 09:07:56 +0100 Subject: [PATCH] Edit page: auto-expand step textareas, wider layout, image management - Textareas auto-resize to fit content (min 120px) - Edit page container widened to 1100px - Show recipe image with URL input and file upload options - Add image upload endpoint (POST /api/recipes///image) - Add upload_image_bytes() to both Mealie and Tandoor clients Co-Authored-By: Claude Opus 4.6 --- app/main.py | 33 +++++++ app/mealie.py | 19 ++++ app/tandoor.py | 18 ++++ app/templates/recipe_edit.html | 164 +++++++++++++++++++++++++++++---- 4 files changed, 218 insertions(+), 16 deletions(-) diff --git a/app/main.py b/app/main.py index 682cb5a..0a75819 100644 --- a/app/main.py +++ b/app/main.py @@ -349,6 +349,39 @@ def api_update_recipe(backend, recipe_id): return jsonify({"ok": False, "error": str(exc)}) +@app.route("/api/recipes///image", methods=["POST"]) +def api_upload_image(backend, recipe_id): + """AJAX — upload an image file to a recipe.""" + cfg = config.load() + if "image" not in request.files: + return jsonify({"ok": False, "error": "Nincs fájl."}) + file = request.files["image"] + if not file.filename: + return jsonify({"ok": False, "error": "Nincs fájl."}) + + content_type = file.content_type or "image/jpeg" + image_data = file.read() + + try: + if backend == "mealie": + if not cfg.get("mealie_url") or not cfg.get("mealie_api_key"): + return jsonify({"ok": False, "error": "Mealie nincs beállítva."}) + client = MealieClient(cfg["mealie_url"], cfg["mealie_api_key"], + api_url=config.MEALIE_INTERNAL_URL) + client.upload_image_bytes(recipe_id, image_data, content_type) + elif backend == "tandoor": + if not cfg.get("tandoor_url") or not cfg.get("tandoor_api_key"): + return jsonify({"ok": False, "error": "Tandoor nincs beállítva."}) + client = TandoorClient(cfg["tandoor_url"], cfg["tandoor_api_key"], + api_url=config.TANDOOR_INTERNAL_URL) + client.upload_image_bytes(int(recipe_id), image_data, content_type) + else: + return jsonify({"ok": False, "error": "Ismeretlen backend."}) + return jsonify({"ok": True, "message": "Kép feltöltve."}) + except Exception as exc: + return jsonify({"ok": False, "error": str(exc)}) + + @app.route("/api/recipes//delete", methods=["POST"]) def api_delete_recipes(backend): """AJAX — delete one or more recipes.""" diff --git a/app/mealie.py b/app/mealie.py index e87957b..21b820a 100644 --- a/app/mealie.py +++ b/app/mealie.py @@ -214,6 +214,25 @@ class MealieClient: r = self.session.delete(f"{self.api_url}/api/recipes/{slug}", timeout=10) r.raise_for_status() + def upload_image_bytes(self, slug: str, image_data: bytes, + content_type: str = "image/jpeg") -> None: + """Upload raw image bytes to a recipe.""" + ext = "jpg" + if "png" in content_type: + ext = "png" + elif "webp" in content_type: + ext = "webp" + files = { + "image": (f"recipe.{ext}", io.BytesIO(image_data), content_type), + } + r = self.session.put( + f"{self.api_url}/api/recipes/{slug}/image", + files=files, + data={"extension": ext}, + timeout=30, + ) + r.raise_for_status() + def create_recipe(self, recipe: dict) -> str: """Create a recipe in Mealie from a scraper result dict. diff --git a/app/tandoor.py b/app/tandoor.py index ea0bd05..116694b 100644 --- a/app/tandoor.py +++ b/app/tandoor.py @@ -235,6 +235,24 @@ class TandoorClient: "url": f"{self.base_url}/view/recipe/{recipe_id}", } + def upload_image_bytes(self, recipe_id: int, image_data: bytes, + content_type: str = "image/jpeg") -> None: + """Upload raw image bytes to a recipe.""" + ext = "jpg" + if "png" in content_type: + ext = "png" + elif "webp" in content_type: + ext = "webp" + files = { + "image": (f"recipe.{ext}", io.BytesIO(image_data), content_type), + } + r = self.session.put( + f"{self.api_url}/api/recipe/{recipe_id}/image/", + files=files, + timeout=30, + ) + r.raise_for_status() + # ------------------------------------------------------------------ # Internal # ------------------------------------------------------------------ diff --git a/app/templates/recipe_edit.html b/app/templates/recipe_edit.html index 84aa81a..6126cae 100644 --- a/app/templates/recipe_edit.html +++ b/app/templates/recipe_edit.html @@ -3,13 +3,10 @@ {% block head %}