Quellcode durchsuchen

add Mealie recipe converter

Daniel Sheffield vor 5 Monaten
Ursprung
Commit
691e65e454
4 geänderte Dateien mit 283 neuen und 1 gelöschten Zeilen
  1. 1 1
      app/parse_recipe.py
  2. 161 0
      convert_to_mealie.py
  3. 114 0
      mealie_units.json
  4. 7 0
      recipes/Hair_Bleach.yaml

+ 1 - 1
app/parse_recipe.py

@@ -20,7 +20,7 @@ def parse_recipe(fh, query_manager: QueryManager):
         match = re.search(
             r'(?P<product>.*) (?P<quantity>[0-9\.]+) ?(?P<unit>.*)', ingredient
         )
-        assert match is not None, f'Could parse {ingredient}'
+        assert match is not None, f'Could not parse: {ingredient}'
         units = query_manager.unique_suggestions('unit', unit=match.group('unit'))
         assert match.group('unit') in units, f"Unknown unit: '{match.group('unit')}'"
         recipe['ingredients'].append(

+ 161 - 0
convert_to_mealie.py

@@ -0,0 +1,161 @@
+import os
+from sys import stdin, stdout, argv
+from uuid import uuid4
+from json import dumps, load
+
+import psycopg
+from psycopg import Cursor
+import pandas as pd
+
+from app.data.QueryManager import QueryManager, display_mapper
+from app.parse_recipe import parse_recipe
+
+try:
+    from db_credentials import HOST, PASSWORD
+    host = f'host={HOST}'
+    password = f'password={PASSWORD}'
+except:
+    host = ''
+    password = ''
+
+user = os.getenv('USER')
+conn = psycopg.connect(f"{host} dbname=grocery user={user} {password}")
+cur: Cursor = conn.cursor()
+query_manager = QueryManager(cur, display_mapper)
+with open(argv[1], 'rb') as f:
+    units = { x['name']: x for x in load(f) }
+
+# {
+#      "id": "7cb5a83d-268a-4898-b24e-08b4753039a5",
+#      "userId": "d0f22cce-fa1c-420e-98ae-d85831c725b1",
+#      "groupId": "c6229a83-ce82-4be1-9683-ff14f83025c9",
+#      "name": "Another",
+#      "slug": "another",
+#      "image": null,
+#      "recipeYield": null,
+#      "totalTime": null,
+#      "prepTime": null,
+#      "cookTime": null,
+#      "performTime": null,
+#      "description": "",
+#      "recipeCategory": [],
+#      "tags": [],
+#      "tools": [],
+#      "rating": null,
+#      "orgURL": null,
+#      "dateAdded": "2024-04-14",
+#      "dateUpdated": "2024-04-14T18:49:34.284815",
+#      "createdAt": "2024-04-14T18:49:34.293412",
+#      "updateAt": "2024-04-14T18:49:34.293418",
+#      "lastMade": null,
+#      "recipeIngredient": [
+#          {
+#              "quantity": 1.0,
+#              "unit": null,
+#              "food": null,
+#              "note": "1 Cup Flour",
+#              "isFood": false,
+#              "disableAmount": true,
+#              "display": "1 Cup Flour",
+#              "title": null,
+#              "originalText": null,
+#              "referenceId": "2e4403e7-fbfb-42b6-b38b-adf38f09bf78"
+#          }
+#      ],
+#      "recipeInstructions": [
+#          {
+#              "id": "f8c85a36-1044-45e7-b22b-e37764d892a9",
+#              "title": "",
+#              "text": "Recipe steps as well as other fields in the recipe page support markdown syntax.\n\n**Add a link**\n\n[My Link](https://demo.mealie.io)\n\n",
+#              "ingredientReferences": []
+#          }
+#      ],
+#      "nutrition": {
+#          "calories": null,
+#          "fatContent": null,
+#          "proteinContent": null,
+#          "carbohydrateContent": null,
+#          "fiberContent": null,
+#          "sodiumContent": null,
+#          "sugarContent": null
+#      },
+#      "settings": {
+#          "public": true,
+#          "showNutrition": true,
+#          "showAssets": true,
+#          "landscapeView": false,
+#          "disableComments": true,
+#          "disableAmount": true,
+#          "locked": false
+#      },
+#      "assets": [],
+#      "notes": [],
+#      "extras": {},
+#      "comments": []
+#  }
+
+cur.execute("BEGIN;")
+with open('units.sql') as f:
+    to_exec = ''
+    quote = False
+    conn.add_notice_handler(lambda x: print(f"[{x.severity}] {x.message_primary}"))
+    for line in filter(lambda x: x.strip() not in ('BEGIN;','ROLLBACK;'), f):
+        if line.startswith("""$$"""):
+            quote = True if not quote else False
+        to_exec += line
+        if not line.strip().endswith(';'):
+            continue
+        if quote:
+            continue
+        cur.execute(to_exec)
+        try:
+            data = pd.DataFrame(cur.fetchall(), columns=[
+                x.name for x in cur.description
+            ])
+            if not data.empty:
+                print()
+                print(cur._last_query)
+            print(data.to_string(index=False))
+
+        except psycopg.ProgrammingError:
+            pass
+        to_exec = ''
+
+parsed = parse_recipe(stdin, query_manager)
+cur.execute('ROLLBACK')
+def unit_mapper(unit):
+    if 'Cup' in unit:
+        return 'cup'
+
+    return unit.replace(' (metric)', '').replace(' (US)', '')
+
+
+mealie = {
+    'recipeYield': parsed['feeds'],
+    'recipeInstructions': [{
+        "id": str(uuid4()),
+        "title": "",
+        "text": line,
+        "ingredientReferences": [],
+    } for line in parsed['instructions'].splitlines()],
+    'recipeIngredient': [{
+        "quantity": quantity,
+        "unit": units[unit_mapper(unit)],
+        "food": None,
+        "note": product,
+        "isFood": False,
+        "disableAmount": False,
+        "display": product,
+        "title": None,
+        "originalText": o,
+        "referenceId": str(uuid4())
+    } for product, quantity, unit, o in map(
+        lambda x: (*x, ' '.join([*x[1:], x[0]])),
+        parsed['ingredients']
+    )]
+}
+stdout.write(dumps(mealie))
+
+cur.close()
+conn.close()
+

+ 114 - 0
mealie_units.json

@@ -0,0 +1,114 @@
+[
+  {
+    "id": "4217d9f1-9b76-44fe-bae1-127cf0aa5894",
+    "name": "Bags",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T21:03:25.930222",
+    "updateAt": "2024-04-14T21:03:25.930244"
+  },
+  {
+    "id": "e41d9068-5a92-4fe7-bef6-e961bd12c6fc",
+    "name": "cup",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T20:17:55.768406",
+    "updateAt": "2024-04-14T20:17:55.768425"
+  },
+  {
+    "id": "6ab91d19-bd5f-46d6-933c-ebb9dd3dd4ba",
+    "name": "g",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T12:48:52.230610",
+    "updateAt": "2024-04-14T12:48:52.230626"
+  },
+  {
+    "id": "f44b3e06-b69b-4292-b0c2-8029d6308d72",
+    "name": "kg",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T12:48:23.868576",
+    "updateAt": "2024-04-14T12:48:23.868589"
+  },
+  {
+    "id": "a5b6233b-0bff-486e-94ee-dd4b0cc9bb57",
+    "name": "mL",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T12:52:30.952337",
+    "updateAt": "2024-04-14T12:52:30.952350"
+  },
+  {
+    "id": "4d772a6e-bd61-469f-9b0c-ce246b8966a5",
+    "name": "Pieces",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T20:18:28.644051",
+    "updateAt": "2024-04-14T20:18:28.644065"
+  },
+  {
+    "id": "7d90812e-4327-45f8-b9e0-34a361920649",
+    "name": "Tbsp",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T20:22:14.527424",
+    "updateAt": "2024-04-14T20:22:14.527439"
+  },
+  {
+    "id": "c1bea0e1-6ad0-4e59-a333-6a766db554e7",
+    "name": "tsp",
+    "pluralName": null,
+    "description": "",
+    "extras": {},
+    "fraction": true,
+    "abbreviation": "",
+    "pluralAbbreviation": "",
+    "useAbbreviation": false,
+    "aliases": [],
+    "createdAt": "2024-04-14T20:18:40.670732",
+    "updateAt": "2024-04-14T20:18:40.670745"
+  }
+]

+ 7 - 0
recipes/Hair_Bleach.yaml

@@ -0,0 +1,7 @@
+feeds: 1
+ingredients:
+- Honey 2 Tbsp (metric)
+- Cinnamon, Ground 1 Tbsp (metric)
+instructions: |-
+  **Honey**
+  **Cinnamon, Ground**