Extract ingredient comments from food field, add import-to-both button

- Global post-processing in scrape() extracts trailing (comment) from
  ingredient food names into the extra/comment field. Works for all parsers.
- Added "Importálás mindkettőbe" button on single import page when both
  Mealie and Tandoor are configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 18:27:58 +01:00
parent 4467265168
commit 2408984421
2 changed files with 80 additions and 4 deletions
+24 -3
View File
@@ -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 ""
+56 -1
View File
@@ -467,7 +467,7 @@
<hr class="section-divider">
<!-- Single mode action buttons -->
<div class="flex mt-2" id="singleActions">
<div class="flex mt-2" id="singleActions" style="flex-wrap:wrap;">
{% if has_mealie %}
<button class="btn btn-success" id="sendMealieBtn" onclick="sendToMealie()">
Importálás Mealie-be
@@ -478,6 +478,11 @@
Importálás Tandoor-ba
</button>
{% endif %}
{% if has_mealie and has_tandoor %}
<button class="btn btn-success" id="sendBothBtn" onclick="sendToBoth()">
Importálás mindkettőbe
</button>
{% endif %}
<span id="sendStatus"></span>
</div>
@@ -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 = '<span class="spinner"></span> 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 = '<span class="text-danger">Hiba: ' + errors.join('; ') + '</span>';
} else if (errors.length > 0) {
status.innerHTML = '<span class="text-warning">Részben sikeres: ' + errors.join('; ') + '</span>';
showResultCard();
} else {
status.innerHTML = '<span class="text-success">&#10003; Mindkettőbe importálva</span>';
showResultCard();
}
btn.disabled = false;
}
function showResultCard() {
const links = Object.entries(importedLinks).map(([name, url]) =>
'<a href="' + escHtml(url) + '" target="_blank" style="color:var(--accent);">Megnyitás ' + name + '-ben &rarr;</a>'