Simplify shopping list: drop Keep, fast reset, HTML output for HA iframe

This commit is contained in:
2026-04-22 17:56:49 +02:00
parent 2c3e5bb540
commit 7b7dc22245
4 changed files with 280 additions and 467 deletions
+2 -2
View File
@@ -137,7 +137,7 @@ cards:
- type: markdown - type: markdown
content: | content: |
## Bilka ToGo - kryds-af ## 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 (fredagtorsdag).
- type: button - type: button
name: Opdater Bilka ToGo-liste nu name: Opdater Bilka ToGo-liste nu
@@ -147,5 +147,5 @@ cards:
service: script.mealie_shopping_refresh service: script.mealie_shopping_refresh
- type: iframe - type: iframe
url: /local/bilka_togo_checklist_bilka.md url: /local/bilka_togo_checklist.html
aspect_ratio: 100% aspect_ratio: 100%
+55 -81
View File
@@ -1,14 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Build and merge shopping list for Bilka ToGo. """Build Mealie shopping list for the Friday-Thursday meal plan window.
Flow: Flow:
1) Build Mealie shopping list from meal plan entries in the Friday-Thursday window. 1) Compute next Friday-Thursday window.
2) Merge those Mealie shopping items with a local Google Keep base list. 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: Output:
- /www/bilka_togo_checklist.md - /www/bilka_togo_checklist.html (iframe-renderable in HA)
- /www/bilka_togo_checklist_bilka.md - /www/bilka_togo_checklist.json (machine-readable backup)
- /www/bilka_togo_checklist.json
""" """
from __future__ import annotations from __future__ import annotations
@@ -101,16 +102,8 @@ def classify_category(name: str) -> str:
return 'andet' return 'andet'
def read_keep_items(keep_path: Path) -> list[str]: def read_keep_items(_keep_path: Path) -> list[str]: # noqa: ARG001 (kept for backward compat)
if not keep_path.exists():
return [] 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 friday_to_thursday_window(today: date) -> tuple[date, date]: 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'] return created['id']
def clear_shopping_list_items(base_url: str, token: str, shopping_list_id: str) -> None: def reset_shopping_list(base_url: str, token: str, name: str, shopping_list_id: str) -> str:
items = api_request(base_url, '/api/households/shopping/items?perPage=1000', token).get('items', []) or [] """Delete the list and recreate it. Returns new list id."""
for item in items: api_request(base_url, f'/api/households/shopping/lists/{shopping_list_id}', token, method='DELETE')
if item.get('shoppingListId') == shopping_list_id and item.get('id'): created = api_request(
api_request(base_url, f"/api/households/shopping/items/{item['id']}", token, method='DELETE') 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]: 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() 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] = {} merged: dict[str, dict] = {}
for item in mealie_items: for item in mealie_items:
name = extract_item_name(item) name = extract_item_name(item)
if not name: if not name:
@@ -212,30 +210,9 @@ def merge_items(mealie_items: list[dict], keep_items: list[str]) -> list[dict]:
merged[norm] = { merged[norm] = {
'name': name, 'name': name,
'category': classify_category(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']))) result.sort(key=lambda x: (x['category'], normalize_name(x['name'])))
return result return result
@@ -251,64 +228,61 @@ def write_outputs(root: Path, items: list[dict], start_date: date, end_date: dat
for item in items: for item in items:
grouped[item['category']].append(item) grouped[item['category']].append(item)
lines = [ rows_html = ''
'# 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()}',
'',
]
for category in sorted(grouped.keys()): 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]: for item in grouped[category]:
sources = '/'.join(item['sources']) rows_html += f'<tr><td class="cb"><input type="checkbox"></td><td>{item["name"]}</td></tr>\n'
lines.append(f"- [ ] {item['name']} ({sources})")
lines.append('')
(www / 'bilka_togo_checklist.md').write_text('\n'.join(lines)) html = f"""<!DOCTYPE html>
<html lang="da">
# Bilka-ready checklist: same grouped list, but without source metadata. <head>
bilka_lines = [ <meta charset="utf-8">
'# Bilka ToGo - Klar til bestilling', <meta name="viewport" content="width=device-width,initial-scale=1">
'', <title>Bilka ToGo</title>
'Kryds af hvad I allerede har i huset, og bestil resten.', <style>
f'Plan-vindue: {start_date.isoformat()} til {end_date.isoformat()}', 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; }}
for category in sorted(grouped.keys()): td, th {{ padding: 5px 6px; text-align: left; border-bottom: 1px solid #2c2c2e; }}
bilka_lines.append(f'## {category.title()}') th.cat {{ background: #2c2c2e; color: #ffe066; font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.05em; }}
for item in grouped[category]: td.cb {{ width: 28px; }}
bilka_lines.append(f"- [ ] {item['name']}") input[type=checkbox] {{ width: 18px; height: 18px; accent-color: #30d158; cursor: pointer; }}
bilka_lines.append('') tr:hover td {{ background: #2c2c2e; }}
</style>
(www / 'bilka_togo_checklist_bilka.md').write_text('\n'.join(bilka_lines)) </head>
<body>
<h1>🛒 Bilka ToGo</h1>
<p class="sub">Plan {start_date.strftime('%d/%m')} {end_date.strftime('%d/%m')} &nbsp;·&nbsp; {len(items)} varer</p>
<table>
{rows_html}</table>
</body>
</html>
"""
(www / 'bilka_togo_checklist.html').write_text(html)
def main() -> None: def main() -> None:
root = detect_root() root = detect_root()
token = read_bearer_token(root / 'secrets.yaml') 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()) start_date, end_date = friday_to_thursday_window(date.today())
shopping_list_id = ensure_shopping_list(MEALIE_BASE_URL, token, TARGET_SHOPPING_LIST_NAME) 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) 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) 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) mealie_items = fetch_mealie_items(MEALIE_BASE_URL, token, shopping_list_id=shopping_list_id)
keep_items = read_keep_items(keep_path) items = build_items(mealie_items)
write_outputs(root, items, start_date, end_date)
merged = merge_items(mealie_items, keep_items)
write_outputs(root, merged, start_date, end_date)
print( print(
'OK: ' 'OK: '
f'window={start_date.isoformat()}..{end_date.isoformat()} ' 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)}'
) )
+113
View File
@@ -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 &nbsp;·&nbsp; 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
View File
@@ -1,607 +1,333 @@
{ {
"count": 86, "count": 82,
"items": [ "items": [
{ {
"name": "0,50 squash", "name": "0,50 squash",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "0,50 tsk mediumstærk karry", "name": "0,50 tsk mediumstærk karry",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "0,50 tsk tørret rosmarin", "name": "0,50 tsk tørret rosmarin",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 dl cremefraiche 38%", "name": "1 dl cremefraiche 38%",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 dl grøntsagsbouillon", "name": "1 dl grøntsagsbouillon",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 dl pickles", "name": "1 dl pickles",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 dl rødvin, eller grøntsagsboullion", "name": "1 dl rødvin, eller grøntsagsboullion",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 dl tør hvidvin", "name": "1 dl tør hvidvin",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 fed hvidløg, presset", "name": "1 fed hvidløg, presset",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 gulerødder, Groftrevet", "name": "1 gulerødder, i tern",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "1 håndfuld persille",
"category": "andet"
}, },
{ {
"name": "1 kg kartofler", "name": "1 kg kartofler",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 knivspids muskatnød, fintrevet", "name": "1 knivspids muskatnød, fintrevet",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 knivspids sød paprika", "name": "1 knivspids sød paprika",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "1 løg, i tern",
"category": "andet"
}, },
{ {
"name": "1 rødløg", "name": "1 rødløg",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk dijon sennep", "name": "1 spsk dijon sennep",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk hampefrø", "name": "1 spsk hampefrø",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk honning", "name": "1 spsk honning",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
},
{
"name": "1 spsk ingefær, fintrevet",
"category": "andet",
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk majsstivelse", "name": "1 spsk majsstivelse",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk smør, til stegning", "name": "1 spsk smør, til stegning",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk solsikkekerner", "name": "1 spsk solsikkekerner",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 squash, groftrevet", "name": "1 squash, groftrevet",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 tsk tørret timian", "name": "1 tsk tørret timian",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "10 g smør, til stegning", "name": "10 g smør, til stegning",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "100 g parmesan, fintrevet", "name": "100 g parmesan, fintrevet",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "12 tarteletter",
"category": "andet"
}, },
{ {
"name": "2 æg", "name": "2 æg",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 dl hønsebouillon", "name": "2 dl hønsebouillon",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "2 hønsebryst",
"category": "andet"
},
{
"name": "2 laurbærblade",
"category": "andet"
}, },
{ {
"name": "2 spsk grov sennep", "name": "2 spsk grov sennep",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 spsk rosiner", "name": "2 spsk rosiner",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 spsk smør", "name": "2 spsk smør",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 tsk tørret oregano", "name": "2 tsk tørret oregano",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "200 g aspargessnitter",
"category": "andet"
}, },
{ {
"name": "200 g lasagneplader", "name": "200 g lasagneplader",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "25 g smør, til stegning", "name": "25 g smør, til stegning",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "3 dl grøntsagsbouillon",
"category": "andet"
}, },
{ {
"name": "3 dl mælk", "name": "3 dl mælk",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "3 gulerødder, groftrevet", "name": "3 gulerødder, groftrevet",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
},
{
"name": "30 forårsrulleplader",
"category": "andet",
"sources": [
"Mealie"
]
}, },
{ {
"name": "300 g torskefilet", "name": "300 g torskefilet",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "35 g glasnudler", "name": "4 dl mælk",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "4 fed hvidløg, fintrevet", "name": "4 fed hvidløg, fintrevet",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
}, },
{ {
"name": "4 gulerødder, groftrevet", "name": "4 gulerødder, groftrevet",
"category": "andet", "category": "andet"
"sources": [ },
"Mealie" {
] "name": "40 g smør",
"category": "andet"
}, },
{ {
"name": "5 stængler bladselleri, groftrevet", "name": "5 stængler bladselleri, groftrevet",
"category": "andet", "category": "andet"
"sources": [
"Mealie"
]
},
{
"name": "vand til pensling",
"category": "andet",
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 dl piskefløde", "name": "1 dl piskefløde",
"category": "frost", "category": "frost"
"sources": [
"Mealie"
]
},
{
"name": "1 spsk fishsauce",
"category": "frost",
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 spsk mayonnaise", "name": "2 spsk mayonnaise",
"category": "frost", "category": "frost"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2,50 dl piskefløde", "name": "2,50 dl piskefløde",
"category": "frost", "category": "frost"
"sources": [
"Mealie"
]
}, },
{ {
"name": "0,50 citron, saft herfra", "name": "0,50 citron, saft herfra",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "0,50 øko citron", "name": "0,50 øko citron",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "15 g koncentreret tomatpuré", "name": "15 g koncentreret tomatpuré",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 æble, groftrevet", "name": "2 æble, groftrevet",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "50 g koncentreret tomatpuré", "name": "50 g koncentreret tomatpuré",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "75 g soltørrede tomater i olie, finthakket", "name": "75 g soltørrede tomater i olie, finthakket",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "800 g hakkede tomater på dåse", "name": "800 g hakkede tomater på dåse",
"category": "frugt & grønt", "category": "frugt & grønt"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 håndfuld frisk basilikum", "name": "1 håndfuld frisk basilikum",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 håndfuld frisk dild", "name": "1 håndfuld frisk dild",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
},
{
"name": "1 liter fritureolie",
"category": "kolonial",
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk olivenolie", "name": "1 spsk olivenolie",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 spsk olivenolie, til stegning", "name": "1 spsk olivenolie, til stegning",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
},
{
"name": "1 spsk soja",
"category": "kolonial",
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 tsk olivenolie", "name": "1 tsk olivenolie",
"category": "kolonial", "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"
]
}, },
{ {
"name": "2 spsk hvedemel", "name": "2 spsk hvedemel",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 spsk olivenolie", "name": "2 spsk olivenolie",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "25 g hvedemel", "name": "25 g hvedemel",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "3 dl basmati ris, kogt efter anvisning på emballagen", "name": "3 dl basmati ris, kogt efter anvisning på emballagen",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "30 g hvedemel", "name": "30 g hvedemel",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "40 g hvedemel", "name": "40 g hvedemel",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "400 g pasta", "name": "400 g pasta",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "flagesalt", "name": "flagesalt",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "salt og friskkværnet peber", "name": "salt og friskkværnet peber",
"category": "kolonial", "category": "kolonial"
"sources": [
"Mealie"
]
}, },
{ {
"name": "0,50 dl frisk estragon, finthakket", "name": "0,50 dl frisk estragon, finthakket",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
}, },
{ {
"name": "1 løg, finthakket", "name": "1 løg, finthakket",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
},
{
"name": "1 tsk rød chili, finthakket",
"category": "kød & fisk",
"sources": [
"Mealie"
]
}, },
{ {
"name": "2 løg, finthakket", "name": "2 løg, finthakket",
"category": "kød & fisk", "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"
]
}, },
{ {
"name": "300 g laks, uden skind", "name": "300 g laks, uden skind",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
}, },
{ {
"name": "4 fed hvidløg, finthakket", "name": "4 fed hvidløg, finthakket",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
}, },
{ {
"name": "4 kyllingebryst", "name": "4 kyllingebryst",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
}, },
{ {
"name": "400 g hakket oksekød", "name": "400 g hakket oksekød",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
},
{
"name": "400 g hakket svinekød",
"category": "kød & fisk",
"sources": [
"Mealie"
]
}, },
{ {
"name": "600 g kyllingebryst", "name": "600 g kyllingebryst",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
}, },
{ {
"name": "75 g bacon, i skiver", "name": "75 g bacon, i skiver",
"category": "kød & fisk", "category": "kød & fisk"
"sources": [
"Mealie"
]
}, },
{ {
"name": "125 g frisk mozzarella", "name": "125 g frisk mozzarella",
"category": "mejeri & æg", "category": "mejeri & æg"
"sources": [
"Mealie"
]
}, },
{ {
"name": "400 g haricots verts, fra frost", "name": "400 g haricots verts, fra frost",
"category": "mejeri & æg", "category": "mejeri & æg"
"sources": [
"Mealie"
]
} }
] ]
} }