Files
recipe-importer/app/main.py
T
admin 9a59b38fd6 fix: add MEALIE_INTERNAL_URL env var for Docker-to-Docker API calls
When deployed behind Cloudflare Tunnel, requests from the container to
the external Mealie URL fail with 530 (hairpin). MEALIE_INTERNAL_URL
lets the container use the Docker-internal address (e.g. http://mealie:9000)
for API calls while keeping the external URL for browser links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 07:58:59 +01:00

118 lines
4.0 KiB
Python

"""Flask application — recipe importer web UI."""
import os
import traceback
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from app import config
from app.scraper import scrape
from app.mealie import MealieClient
app = Flask(
__name__,
template_folder=os.path.join(os.path.dirname(__file__), "templates"),
static_folder=os.path.join(os.path.dirname(__file__), "static"),
)
app.secret_key = os.environ.get("SECRET_KEY", "recipe-importer-dev-key")
VERSION = os.environ.get("VERSION", "dev")
# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------
@app.route("/")
def index():
"""Redirect to the import page (or settings if not configured)."""
cfg = config.load()
if not cfg.get("mealie_url") or not cfg.get("mealie_api_key"):
return redirect(url_for("settings"))
return redirect(url_for("import_page"))
@app.route("/settings", methods=["GET", "POST"])
def settings():
"""Configure Mealie connection."""
cfg = config.load()
if request.method == "POST":
cfg["mealie_url"] = request.form.get("mealie_url", "").strip().rstrip("/")
cfg["mealie_api_key"] = request.form.get("mealie_api_key", "").strip()
config.save(cfg)
flash("Beállítások mentve.", "success")
return redirect(url_for("settings"))
return render_template("settings.html", cfg=cfg, version=VERSION)
@app.route("/settings/test", methods=["POST"])
def settings_test():
"""AJAX endpoint — test Mealie connection using form values."""
url = (request.form.get("mealie_url") or "").strip().rstrip("/")
key = (request.form.get("mealie_api_key") or "").strip()
if not url or not key:
return jsonify({"ok": False, "error": "Nincs megadva Mealie URL vagy API kulcs."})
try:
client = MealieClient(url, key, api_url=config.MEALIE_INTERNAL_URL)
info = client.test_connection()
return jsonify({"ok": True, "data": info})
except Exception as exc:
return jsonify({"ok": False, "error": str(exc)})
@app.route("/import", methods=["GET"])
def import_page():
"""Show the import form."""
cfg = config.load()
if not cfg.get("mealie_url") or not cfg.get("mealie_api_key"):
flash("Először állítsd be a Mealie kapcsolatot.", "warning")
return redirect(url_for("settings"))
return render_template("import.html", cfg=cfg, version=VERSION)
@app.route("/scrape", methods=["POST"])
def scrape_url():
"""AJAX — scrape a recipe URL and return structured data."""
url = request.form.get("url", "").strip()
if not url:
return jsonify({"ok": False, "error": "Nincs URL megadva."})
try:
data = scrape(url)
return jsonify({"ok": True, "data": data})
except Exception as exc:
return jsonify({"ok": False, "error": str(exc), "trace": traceback.format_exc()})
@app.route("/send", methods=["POST"])
def send_to_mealie():
"""AJAX — send edited recipe data to Mealie."""
cfg = config.load()
if not cfg.get("mealie_url") or not cfg.get("mealie_api_key"):
return jsonify({"ok": False, "error": "Mealie nincs beállítva."})
payload = request.get_json(silent=True)
if not payload:
return jsonify({"ok": False, "error": "Érvénytelen kérés."})
try:
client = MealieClient(cfg["mealie_url"], cfg["mealie_api_key"],
api_url=config.MEALIE_INTERNAL_URL)
slug = client.create_recipe(payload)
recipe_url = f"{cfg['mealie_url']}/g/home/r/{slug}"
return jsonify({"ok": True, "slug": slug, "url": recipe_url})
except Exception as exc:
return jsonify({"ok": False, "error": str(exc), "trace": traceback.format_exc()})
# ---------------------------------------------------------------------------
# Health
# ---------------------------------------------------------------------------
@app.route("/health")
def health():
return jsonify({"status": "ok", "version": VERSION})