Simplify shopping list: drop Keep, fast reset, HTML output for HA iframe
This commit is contained in:
@@ -137,7 +137,7 @@ cards:
|
||||
- type: markdown
|
||||
content: |
|
||||
## Bilka ToGo - kryds-af
|
||||
Tryk på knappen for at flette Mealie-indkøb med jeres Google Keep-basisliste.
|
||||
Tryk på knappen for at hente ingredienser fra ugeplanen (fredag–torsdag).
|
||||
|
||||
- type: button
|
||||
name: Opdater Bilka ToGo-liste nu
|
||||
@@ -147,5 +147,5 @@ cards:
|
||||
service: script.mealie_shopping_refresh
|
||||
|
||||
- type: iframe
|
||||
url: /local/bilka_togo_checklist_bilka.md
|
||||
url: /local/bilka_togo_checklist.html
|
||||
aspect_ratio: 100%
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build and merge shopping list for Bilka ToGo.
|
||||
"""Build Mealie shopping list for the Friday-Thursday meal plan window.
|
||||
|
||||
Flow:
|
||||
1) Build Mealie shopping list from meal plan entries in the Friday-Thursday window.
|
||||
2) Merge those Mealie shopping items with a local Google Keep base list.
|
||||
1) Compute next Friday-Thursday window.
|
||||
2) Ensure/clear the 'Bilka ToGo' Mealie shopping list.
|
||||
3) Add all recipes from the meal plan window to the list.
|
||||
4) Fetch the resulting shopping items and write a styled HTML file for display in HA.
|
||||
|
||||
Output:
|
||||
- /www/bilka_togo_checklist.md
|
||||
- /www/bilka_togo_checklist_bilka.md
|
||||
- /www/bilka_togo_checklist.json
|
||||
- /www/bilka_togo_checklist.html (iframe-renderable in HA)
|
||||
- /www/bilka_togo_checklist.json (machine-readable backup)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -101,16 +102,8 @@ def classify_category(name: str) -> str:
|
||||
return 'andet'
|
||||
|
||||
|
||||
def read_keep_items(keep_path: Path) -> list[str]:
|
||||
if not keep_path.exists():
|
||||
return []
|
||||
items: list[str] = []
|
||||
for line in keep_path.read_text().splitlines():
|
||||
stripped = line.strip()
|
||||
if not stripped or stripped.startswith('#'):
|
||||
continue
|
||||
items.append(stripped)
|
||||
return items
|
||||
def read_keep_items(_keep_path: Path) -> list[str]: # noqa: ARG001 (kept for backward compat)
|
||||
return []
|
||||
|
||||
|
||||
def friday_to_thursday_window(today: date) -> tuple[date, date]:
|
||||
@@ -136,11 +129,17 @@ def ensure_shopping_list(base_url: str, token: str, name: str) -> str:
|
||||
return created['id']
|
||||
|
||||
|
||||
def clear_shopping_list_items(base_url: str, token: str, shopping_list_id: str) -> None:
|
||||
items = api_request(base_url, '/api/households/shopping/items?perPage=1000', token).get('items', []) or []
|
||||
for item in items:
|
||||
if item.get('shoppingListId') == shopping_list_id and item.get('id'):
|
||||
api_request(base_url, f"/api/households/shopping/items/{item['id']}", token, method='DELETE')
|
||||
def reset_shopping_list(base_url: str, token: str, name: str, shopping_list_id: str) -> str:
|
||||
"""Delete the list and recreate it. Returns new list id."""
|
||||
api_request(base_url, f'/api/households/shopping/lists/{shopping_list_id}', token, method='DELETE')
|
||||
created = api_request(
|
||||
base_url,
|
||||
'/api/households/shopping/lists',
|
||||
token,
|
||||
method='POST',
|
||||
payload={'name': name},
|
||||
)
|
||||
return created['id']
|
||||
|
||||
|
||||
def get_mealplan_recipe_ids(base_url: str, token: str, start_date: date, end_date: date) -> list[str]:
|
||||
@@ -200,9 +199,8 @@ def extract_item_name(item: dict) -> str:
|
||||
return (food.get('name') or '').strip()
|
||||
|
||||
|
||||
def merge_items(mealie_items: list[dict], keep_items: list[str]) -> list[dict]:
|
||||
def build_items(mealie_items: list[dict]) -> list[dict]:
|
||||
merged: dict[str, dict] = {}
|
||||
|
||||
for item in mealie_items:
|
||||
name = extract_item_name(item)
|
||||
if not name:
|
||||
@@ -212,30 +210,9 @@ def merge_items(mealie_items: list[dict], keep_items: list[str]) -> list[dict]:
|
||||
merged[norm] = {
|
||||
'name': name,
|
||||
'category': classify_category(name),
|
||||
'sources': set(),
|
||||
}
|
||||
merged[norm]['sources'].add('Mealie')
|
||||
|
||||
for name in keep_items:
|
||||
norm = normalize_name(name)
|
||||
if norm not in merged:
|
||||
merged[norm] = {
|
||||
'name': name,
|
||||
'category': classify_category(name),
|
||||
'sources': set(),
|
||||
}
|
||||
merged[norm]['sources'].add('Google Keep')
|
||||
|
||||
result = []
|
||||
for _, row in merged.items():
|
||||
result.append(
|
||||
{
|
||||
'name': row['name'],
|
||||
'category': row['category'],
|
||||
'sources': sorted(row['sources']),
|
||||
}
|
||||
)
|
||||
|
||||
result = [v for v in merged.values()]
|
||||
result.sort(key=lambda x: (x['category'], normalize_name(x['name'])))
|
||||
return result
|
||||
|
||||
@@ -251,64 +228,61 @@ def write_outputs(root: Path, items: list[dict], start_date: date, end_date: dat
|
||||
for item in items:
|
||||
grouped[item['category']].append(item)
|
||||
|
||||
lines = [
|
||||
'# Bilka ToGo - Kryds-af-liste',
|
||||
'',
|
||||
'Gå listen igennem derhjemme først, og bestil kun de varer du mangler.',
|
||||
f'Plan-vindue: {start_date.isoformat()} til {end_date.isoformat()}',
|
||||
'',
|
||||
]
|
||||
|
||||
rows_html = ''
|
||||
for category in sorted(grouped.keys()):
|
||||
lines.append(f'## {category.title()}')
|
||||
rows_html += f'<tr><th colspan="2" class="cat">{category.title()}</th></tr>\n'
|
||||
for item in grouped[category]:
|
||||
sources = '/'.join(item['sources'])
|
||||
lines.append(f"- [ ] {item['name']} ({sources})")
|
||||
lines.append('')
|
||||
rows_html += f'<tr><td class="cb"><input type="checkbox"></td><td>{item["name"]}</td></tr>\n'
|
||||
|
||||
(www / 'bilka_togo_checklist.md').write_text('\n'.join(lines))
|
||||
|
||||
# Bilka-ready checklist: same grouped list, but without source metadata.
|
||||
bilka_lines = [
|
||||
'# Bilka ToGo - Klar til bestilling',
|
||||
'',
|
||||
'Kryds af hvad I allerede har i huset, og bestil resten.',
|
||||
f'Plan-vindue: {start_date.isoformat()} til {end_date.isoformat()}',
|
||||
'',
|
||||
]
|
||||
|
||||
for category in sorted(grouped.keys()):
|
||||
bilka_lines.append(f'## {category.title()}')
|
||||
for item in grouped[category]:
|
||||
bilka_lines.append(f"- [ ] {item['name']}")
|
||||
bilka_lines.append('')
|
||||
|
||||
(www / 'bilka_togo_checklist_bilka.md').write_text('\n'.join(bilka_lines))
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html lang="da">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Bilka ToGo</title>
|
||||
<style>
|
||||
body {{ font-family: sans-serif; padding: 8px; background: #1c1c1e; color: #e5e5ea; margin: 0; }}
|
||||
h1 {{ font-size: 1.1em; margin-bottom: 2px; color: #fff; }}
|
||||
p.sub {{ font-size: 0.8em; color: #8e8e93; margin: 0 0 10px; }}
|
||||
table {{ width: 100%; border-collapse: collapse; }}
|
||||
td, th {{ padding: 5px 6px; text-align: left; border-bottom: 1px solid #2c2c2e; }}
|
||||
th.cat {{ background: #2c2c2e; color: #ffe066; font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.05em; }}
|
||||
td.cb {{ width: 28px; }}
|
||||
input[type=checkbox] {{ width: 18px; height: 18px; accent-color: #30d158; cursor: pointer; }}
|
||||
tr:hover td {{ background: #2c2c2e; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🛒 Bilka ToGo</h1>
|
||||
<p class="sub">Plan {start_date.strftime('%d/%m')} – {end_date.strftime('%d/%m')} · {len(items)} varer</p>
|
||||
<table>
|
||||
{rows_html}</table>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
(www / 'bilka_togo_checklist.html').write_text(html)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
root = detect_root()
|
||||
token = read_bearer_token(root / 'secrets.yaml')
|
||||
keep_path = root / 'dokumenter' / 'google_keep_indkoeb.txt'
|
||||
|
||||
start_date, end_date = friday_to_thursday_window(date.today())
|
||||
|
||||
shopping_list_id = ensure_shopping_list(MEALIE_BASE_URL, token, TARGET_SHOPPING_LIST_NAME)
|
||||
clear_shopping_list_items(MEALIE_BASE_URL, token, shopping_list_id)
|
||||
shopping_list_id = reset_shopping_list(MEALIE_BASE_URL, token, TARGET_SHOPPING_LIST_NAME, shopping_list_id)
|
||||
|
||||
recipe_ids = get_mealplan_recipe_ids(MEALIE_BASE_URL, token, start_date, end_date)
|
||||
added_recipes = add_recipes_to_shopping_list(MEALIE_BASE_URL, token, shopping_list_id, recipe_ids)
|
||||
|
||||
mealie_items = fetch_mealie_items(MEALIE_BASE_URL, token, shopping_list_id=shopping_list_id)
|
||||
keep_items = read_keep_items(keep_path)
|
||||
|
||||
merged = merge_items(mealie_items, keep_items)
|
||||
write_outputs(root, merged, start_date, end_date)
|
||||
items = build_items(mealie_items)
|
||||
write_outputs(root, items, start_date, end_date)
|
||||
|
||||
print(
|
||||
'OK: '
|
||||
f'window={start_date.isoformat()}..{end_date.isoformat()} '
|
||||
f'recipes_added={added_recipes} merged_items={len(merged)}'
|
||||
f'recipes_added={added_recipes} items={len(items)}'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="da">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Bilka ToGo</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; padding: 8px; background: #1c1c1e; color: #e5e5ea; margin: 0; }
|
||||
h1 { font-size: 1.1em; margin-bottom: 2px; color: #fff; }
|
||||
p.sub { font-size: 0.8em; color: #8e8e93; margin: 0 0 10px; }
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
td, th { padding: 5px 6px; text-align: left; border-bottom: 1px solid #2c2c2e; }
|
||||
th.cat { background: #2c2c2e; color: #ffe066; font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
td.cb { width: 28px; }
|
||||
input[type=checkbox] { width: 18px; height: 18px; accent-color: #30d158; cursor: pointer; }
|
||||
tr:hover td { background: #2c2c2e; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🛒 Bilka ToGo</h1>
|
||||
<p class="sub">Plan 24/04 – 30/04 · 82 varer</p>
|
||||
<table>
|
||||
<tr><th colspan="2" class="cat">Andet</th></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>0,50 squash</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>0,50 tsk mediumstærk karry</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>0,50 tsk tørret rosmarin</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 dl cremefraiche 38%</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 dl grøntsagsbouillon</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 dl pickles</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 dl rødvin, eller grøntsagsboullion</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 dl tør hvidvin</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 fed hvidløg, presset</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 gulerødder, i tern</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 håndfuld persille</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 kg kartofler</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 knivspids muskatnød, fintrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 knivspids sød paprika</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 løg, i tern</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 rødløg</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk dijon sennep</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk hampefrø</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk honning</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk majsstivelse</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk smør, til stegning</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk solsikkekerner</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 squash, groftrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 tsk tørret timian</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>10 g smør, til stegning</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>100 g parmesan, fintrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>12 tarteletter</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 æg</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 dl hønsebouillon</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 hønsebryst</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 laurbærblade</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 spsk grov sennep</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 spsk rosiner</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 spsk smør</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 tsk tørret oregano</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>200 g aspargessnitter</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>200 g lasagneplader</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>25 g smør, til stegning</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>3 dl grøntsagsbouillon</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>3 dl mælk</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>3 gulerødder, groftrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>300 g torskefilet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>4 dl mælk</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>4 fed hvidløg, fintrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>4 gulerødder, groftrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>40 g smør</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>5 stængler bladselleri, groftrevet</td></tr>
|
||||
<tr><th colspan="2" class="cat">Frost</th></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 dl piskefløde</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 spsk mayonnaise</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2,50 dl piskefløde</td></tr>
|
||||
<tr><th colspan="2" class="cat">Frugt & Grønt</th></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>0,50 citron, saft herfra</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>0,50 øko citron</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>15 g koncentreret tomatpuré</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 æble, groftrevet</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>50 g koncentreret tomatpuré</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>75 g soltørrede tomater i olie, finthakket</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>800 g hakkede tomater på dåse</td></tr>
|
||||
<tr><th colspan="2" class="cat">Kolonial</th></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 håndfuld frisk basilikum</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 håndfuld frisk dild</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk olivenolie</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 spsk olivenolie, til stegning</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 tsk olivenolie</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 spsk hvedemel</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 spsk olivenolie</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>25 g hvedemel</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>3 dl basmati ris, kogt efter anvisning på emballagen</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>30 g hvedemel</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>40 g hvedemel</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>400 g pasta</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>flagesalt</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>salt og friskkværnet peber</td></tr>
|
||||
<tr><th colspan="2" class="cat">Kød & Fisk</th></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>0,50 dl frisk estragon, finthakket</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>1 løg, finthakket</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>2 løg, finthakket</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>300 g laks, uden skind</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>4 fed hvidløg, finthakket</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>4 kyllingebryst</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>400 g hakket oksekød</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>600 g kyllingebryst</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>75 g bacon, i skiver</td></tr>
|
||||
<tr><th colspan="2" class="cat">Mejeri & Æg</th></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>125 g frisk mozzarella</td></tr>
|
||||
<tr><td class="cb"><input type="checkbox"></td><td>400 g haricots verts, fra frost</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
+109
-383
@@ -1,607 +1,333 @@
|
||||
{
|
||||
"count": 86,
|
||||
"count": 82,
|
||||
"items": [
|
||||
{
|
||||
"name": "0,50 squash",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "0,50 tsk mediumstærk karry",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "0,50 tsk tørret rosmarin",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 dl cremefraiche 38%",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 dl grøntsagsbouillon",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 dl pickles",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 dl rødvin, eller grøntsagsboullion",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 dl tør hvidvin",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 fed hvidløg, presset",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 gulerødder, Groftrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"name": "1 gulerødder, i tern",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 håndfuld persille",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 kg kartofler",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 knivspids muskatnød, fintrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 knivspids sød paprika",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 løg, i tern",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 rødløg",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk dijon sennep",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk hampefrø",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk honning",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 spsk ingefær, fintrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk majsstivelse",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk smør, til stegning",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk solsikkekerner",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 squash, groftrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 tsk tørret timian",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "10 g smør, til stegning",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "100 g parmesan, fintrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "12 tarteletter",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 æg",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 dl hønsebouillon",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 hønsebryst",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 laurbærblade",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 spsk grov sennep",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 spsk rosiner",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 spsk smør",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "2 tsk tørret oregano",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "200 g aspargessnitter",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "200 g lasagneplader",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "25 g smør, til stegning",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "3 dl grøntsagsbouillon",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "3 dl mælk",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "3 gulerødder, groftrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "30 forårsrulleplader",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "300 g torskefilet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "35 g glasnudler",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"name": "4 dl mælk",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "4 fed hvidløg, fintrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "4 gulerødder, groftrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "40 g smør",
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "5 stængler bladselleri, groftrevet",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "vand til pensling",
|
||||
"category": "andet",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "andet"
|
||||
},
|
||||
{
|
||||
"name": "1 dl piskefløde",
|
||||
"category": "frost",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 spsk fishsauce",
|
||||
"category": "frost",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frost"
|
||||
},
|
||||
{
|
||||
"name": "2 spsk mayonnaise",
|
||||
"category": "frost",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frost"
|
||||
},
|
||||
{
|
||||
"name": "2,50 dl piskefløde",
|
||||
"category": "frost",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frost"
|
||||
},
|
||||
{
|
||||
"name": "0,50 citron, saft herfra",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "0,50 øko citron",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "15 g koncentreret tomatpuré",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "2 æble, groftrevet",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "50 g koncentreret tomatpuré",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "75 g soltørrede tomater i olie, finthakket",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "800 g hakkede tomater på dåse",
|
||||
"category": "frugt & grønt",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "frugt & grønt"
|
||||
},
|
||||
{
|
||||
"name": "1 håndfuld frisk basilikum",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "1 håndfuld frisk dild",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 liter fritureolie",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk olivenolie",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "1 spsk olivenolie, til stegning",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 spsk soja",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "1 tsk olivenolie",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 tsk sesamolie, eller anden olie til stegning",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 tsk sukker",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "2 spsk hvedemel",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "2 spsk olivenolie",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "25 g hvedemel",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "3 dl basmati ris, kogt efter anvisning på emballagen",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "30 g hvedemel",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "40 g hvedemel",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "400 g pasta",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "flagesalt",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "salt og friskkværnet peber",
|
||||
"category": "kolonial",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kolonial"
|
||||
},
|
||||
{
|
||||
"name": "0,50 dl frisk estragon, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "1 løg, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "1 tsk rød chili, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "2 løg, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "250 g champignon, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "3 fed hvidløg, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "300 g laks, uden skind",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "4 fed hvidløg, finthakket",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "4 kyllingebryst",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "400 g hakket oksekød",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "400 g hakket svinekød",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "600 g kyllingebryst",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "75 g bacon, i skiver",
|
||||
"category": "kød & fisk",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "kød & fisk"
|
||||
},
|
||||
{
|
||||
"name": "125 g frisk mozzarella",
|
||||
"category": "mejeri & æg",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "mejeri & æg"
|
||||
},
|
||||
{
|
||||
"name": "400 g haricots verts, fra frost",
|
||||
"category": "mejeri & æg",
|
||||
"sources": [
|
||||
"Mealie"
|
||||
]
|
||||
"category": "mejeri & æg"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user