diff --git a/app/scraper.py b/app/scraper.py index 93578ae..ce6c9e8 100644 --- a/app/scraper.py +++ b/app/scraper.py @@ -55,12 +55,19 @@ def scrape(url: str) -> dict: soup = BeautifulSoup(resp.text, "lxml") host = _host(url) + result = None for substring, parser in _PARSERS: if substring in host: - return parser(soup, url) + result = parser(soup, url) + break - # Fallback: try generic schema.org / og-tag extraction - return _parse_generic(soup, url) + if result is None: + # Fallback: try generic schema.org / og-tag extraction + result = _parse_generic(soup, url) + + # Post-process: extract parenthesized comments from food into extra + _extract_ingredient_comments(result) + return result def supported_sites() -> list[str]: @@ -642,6 +649,20 @@ def _parse_generic(soup: BeautifulSoup, url: str) -> dict: # --------------------------------------------------------------------------- +def _extract_ingredient_comments(data: dict): + """Move trailing (comment) from food field to extra field for all ingredients.""" + for ing in data.get("ingredients", []): + if "group" in ing: + continue + food = ing.get("food", "") + extra = ing.get("extra", "") + if food and not extra: + m = re.match(r"^(.+?)\s*\(([^)]+)\)\s*$", food) + if m: + ing["food"] = m.group(1).strip() + ing["extra"] = m.group(2).strip() + + def _host(url: str) -> str: from urllib.parse import urlparse return urlparse(url).hostname or "" diff --git a/app/templates/import.html b/app/templates/import.html index 80d627d..26fd81c 100644 --- a/app/templates/import.html +++ b/app/templates/import.html @@ -467,7 +467,7 @@
-
+
{% if has_mealie %} {% endif %} + {% if has_mealie and has_tandoor %} + + {% endif %}
@@ -775,6 +780,56 @@ async function sendToTandoor() { btn.disabled = false; } +async function sendToBoth() { + const recipe = gatherRecipe(); + if (!recipe.title) { alert('A recept neve kötelező!'); return; } + + const btn = document.getElementById('sendBothBtn'); + const status = document.getElementById('sendStatus'); + btn.disabled = true; + status.innerHTML = ' Importálás mindkettőbe...'; + + const errors = []; + try { + const mResp = await fetch('/send', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(recipe), + }); + const mData = await mResp.json(); + if (mData.ok) { + importedLinks['Mealie'] = mData.url; + } else { + errors.push('Mealie: ' + mData.error); + } + } catch (e) { errors.push('Mealie: ' + e.message); } + + try { + const tResp = await fetch('/send-tandoor', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(recipe), + }); + const tData = await tResp.json(); + if (tData.ok) { + importedLinks['Tandoor'] = tData.url; + } else { + errors.push('Tandoor: ' + tData.error); + } + } catch (e) { errors.push('Tandoor: ' + e.message); } + + if (errors.length > 0 && Object.keys(importedLinks).length === 0) { + status.innerHTML = 'Hiba: ' + errors.join('; ') + ''; + } else if (errors.length > 0) { + status.innerHTML = 'Részben sikeres: ' + errors.join('; ') + ''; + showResultCard(); + } else { + status.innerHTML = '✓ Mindkettőbe importálva'; + showResultCard(); + } + btn.disabled = false; +} + function showResultCard() { const links = Object.entries(importedLinks).map(([name, url]) => 'Megnyitás ' + name + '-ben →'