From 23415f8a61d84573fba8517ccc1ebf20ef5012c2 Mon Sep 17 00:00:00 2001 From: its_me_gb Date: Mon, 26 Apr 2021 14:43:37 +0100 Subject: [PATCH] Initial importer created. --- cookbook/forms.py | 3 +- cookbook/integration/integration.py | 11 +++ cookbook/integration/recettetek.py | 107 ++++++++++++++++++++++++++++ cookbook/views/import_export.py | 3 + 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 cookbook/integration/recettetek.py diff --git a/cookbook/forms.py b/cookbook/forms.py index 39a230e46..7c40a1486 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -112,6 +112,7 @@ class ImportExportBase(forms.Form): SAFRON = 'SAFRON' CHEFTAP = 'CHEFTAP' PEPPERPLATE = 'PEPPERPLATE' + RECETTETEK = 'RECETTETEK' RECIPESAGE = 'RECIPESAGE' DOMESTICA = 'DOMESTICA' MEALMASTER = 'MEALMASTER' @@ -120,7 +121,7 @@ class ImportExportBase(forms.Form): type = forms.ChoiceField(choices=( (DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'), (MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), (CHEFTAP, 'ChefTap'), - (PEPPERPLATE, 'Pepperplate'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'), + (PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'), (MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), )) diff --git a/cookbook/integration/integration.py b/cookbook/integration/integration.py index 33ed72cfc..d2024c0d4 100644 --- a/cookbook/integration/integration.py +++ b/cookbook/integration/integration.py @@ -122,6 +122,17 @@ class Integration: recipe.keywords.add(self.keyword) il.msg += f'{recipe.pk} - {recipe.name} \n' self.handle_duplicates(recipe, import_duplicates) + elif '.rtk' in f['name']: + import_zip = ZipFile(f['file']) + for z in import_zip.filelist: + if self.import_file_name_filter(z): + data_list = self.split_recipe_file(import_zip.read(z.filename).decode('utf-8')) + for d in data_list: + recipe = self.get_recipe_from_file(d) + recipe.keywords.add(self.keyword) + il.msg += f'{recipe.pk} - {recipe.name} \n' + self.handle_duplicates(recipe, import_duplicates) + import_zip.close() else: recipe = self.get_recipe_from_file(f['file']) recipe.keywords.add(self.keyword) diff --git a/cookbook/integration/recettetek.py b/cookbook/integration/recettetek.py new file mode 100644 index 000000000..c1bf490ce --- /dev/null +++ b/cookbook/integration/recettetek.py @@ -0,0 +1,107 @@ +import re +import json +import base64 +import requests +from io import BytesIO +from zipfile import ZipFile +import imghdr +from django.utils.translation import gettext as _ + +from cookbook.helper.ingredient_parser import parse, get_food, get_unit +from cookbook.integration.integration import Integration +from cookbook.models import Recipe, Step, Food, Unit, Ingredient + + +class RecetteTek(Integration): + + def import_file_name_filter(self, zip_info_object): + print("testing", zip_info_object.filename) + return re.match(r'^recipes_0.json$', zip_info_object.filename) + + def split_recipe_file(self, file): + + recipe_json = json.loads(file) + + recipe_list = [r for r in recipe_json] + + return recipe_list + + def get_recipe_from_file(self, file): + + # Create initial recipe with just a title and a decription + recipe = Recipe.objects.create(name=file['title'], created_by=self.request.user, internal=True, space=self.request.space, ) + + try: + if file['description'] != '': + recipe.description = file['description'].strip() + except Exception as e: + print(recipe.name, ': failed to parse recipe description ', str(e)) + + step = Step.objects.create(instruction=file['instructions']) + + try: + # Process the ingredients. Assumes 1 ingredient per line. + for ingredient in file['ingredients'].split('\n'): + if len(ingredient.strip()) > 0: + amount, unit, ingredient, note = parse(ingredient) + f = get_food(ingredient, self.request.space) + u = get_unit(unit, self.request.space) + step.ingredients.add(Ingredient.objects.create( + food=f, unit=u, amount=amount, note=note + )) + except Exception as e: + print(recipe.name, ': failed to parse recipe ingredients ', str(e)) + recipe.steps.add(step) + + # Attempt to import prep/cooking times + try: + if file['quantity'] != '': + recipe.servings = int(file['quantity']) + except Exception as e: + print(recipe.name, ': failed to parse quantity ', str(e)) + + try: + if file['totalTime'] != '': + recipe.waiting_time = int(file['totalTime']) + except Exception as e: + print(recipe.name, ': failed to parse total times ', str(e)) + + try: + if file['preparationTime'] != '': + recipe.working_time = int(file['preparationTime']) + except Exception as e: + print(recipe.name, ': failed to parse prep time ', str(e)) + + try: + if file['cookingTime'] != '': + recipe.waiting_time = int(file['cookingTime']) + except Exception as e: + print(recipe.name, ': failed to parse cooking time ', str(e)) + + recipe.save() + + # Append the original import url if it exists + try: + if file['url'] != '': + step.instruction += '\n\nImported from: ' + file['url'] + step.save() + except Exception as e: + print(recipe.name, ': failed to import source url ', str(e)) + + # TODO: Parse Nutritional Information + + # Grab the original image that was used for the recipe + try: + if file['originalPicture']!= '': + response = requests.get(file['originalPicture']) + if imghdr.what(BytesIO(response.content)) != None: + self.import_recipe_image(recipe, BytesIO(response.content)) + else: + raise Exception("Original image failed to download.") + except Exception as e: + print(recipe.name, ': failed to import image ', str(e)) + + return recipe + + def get_file_from_recipe(self, recipe): + raise NotImplementedError('Method not implemented in storage integration') diff --git a/cookbook/views/import_export.py b/cookbook/views/import_export.py index 127630676..19dde0ef3 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -19,6 +19,7 @@ from cookbook.integration.mealie import Mealie from cookbook.integration.mealmaster import MealMaster from cookbook.integration.nextcloud_cookbook import NextcloudCookbook from cookbook.integration.paprika import Paprika +from cookbook.integration.recettetek import RecetteTek from cookbook.integration.recipesage import RecipeSage from cookbook.integration.rezkonv import RezKonv from cookbook.integration.safron import Safron @@ -44,6 +45,8 @@ def get_integration(request, export_type): return Pepperplate(request, export_type) if export_type == ImportExportBase.DOMESTICA: return Domestica(request, export_type) + if export_type == ImportExportBase.RECETTETEK: + return RecetteTek(request, export_type) if export_type == ImportExportBase.RECIPESAGE: return RecipeSage(request, export_type) if export_type == ImportExportBase.REZKONV: