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:
+23
-2
@@ -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
|
||||
|
||||
if result is None:
|
||||
# Fallback: try generic schema.org / og-tag extraction
|
||||
return _parse_generic(soup, url)
|
||||
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 ""
|
||||
|
||||
@@ -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">✓ 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 →</a>'
|
||||
|
||||
Reference in New Issue
Block a user