diff --git a/cookbook/forms.py b/cookbook/forms.py index f6296c35..d905d768 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -129,13 +129,14 @@ class ImportExportBase(forms.Form): MEALMASTER = 'MEALMASTER' REZKONV = 'REZKONV' OPENEATS = 'OPENEATS' + PLANTOEAT = 'PLANTOEAT' type = forms.ChoiceField(choices=( (DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'), (MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), (CHEFTAP, 'ChefTap'), (PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'), (MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'), - + (PLANTOEAT, 'Plantoeat'), )) diff --git a/cookbook/integration/plantoeat.py b/cookbook/integration/plantoeat.py new file mode 100644 index 00000000..32e871f9 --- /dev/null +++ b/cookbook/integration/plantoeat.py @@ -0,0 +1,93 @@ +from io import BytesIO + +import requests + +from cookbook.helper.ingredient_parser import parse, get_food, get_unit +from cookbook.integration.integration import Integration +from cookbook.models import Recipe, Step, Ingredient, Keyword + + +class Plantoeat(Integration): + + def get_recipe_from_file(self, file): + ingredient_mode = False + direction_mode = False + + image_url = None + tags = None + ingredients = [] + directions = [] + description = '' + for line in file.replace('\r', '').split('\n'): + if line.strip() != '': + if 'Title:' in line: + title = line.replace('Title:', '').replace('"', '').strip() + if 'Description:' in line: + description = line.replace('Description:', '').strip() + if 'Source:' in line or 'Serves:' in line or 'Prep Time:' in line or 'Cook Time:' in line: + directions.append(line.strip() + '\n') + if 'Photo Url:' in line: + image_url = line.replace('Photo Url:', '').strip() + if 'Tags:' in line: + tags = line.replace('Tags:', '').strip() + if ingredient_mode: + if len(line) > 2 and 'Instructions:' not in line: + ingredients.append(line.strip()) + if direction_mode: + if len(line) > 2: + directions.append(line.strip() + '\n') + if 'Ingredients:' in line: + ingredient_mode = True + if 'Directions:' in line: + ingredient_mode = False + direction_mode = True + + recipe = Recipe.objects.create(name=title, description=description, created_by=self.request.user, internal=True, space=self.request.space) + + step = Step.objects.create( + instruction='\n'.join(directions) + '\n\n', space=self.request.space, + ) + + if tags: + for k in tags.split(','): + keyword, created = Keyword.objects.get_or_create(name=k.strip(), space=self.request.space) + recipe.keywords.add(keyword) + + for ingredient in ingredients: + 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, space=self.request.space, + )) + recipe.steps.add(step) + + if image_url: + try: + response = requests.get(image_url) + self.import_recipe_image(recipe, BytesIO(response.content)) + except Exception as e: + print('failed to import image ', str(e)) + + return recipe + + def split_recipe_file(self, file): + recipe_list = [] + current_recipe = '' + + for fl in file.readlines(): + line = fl.decode("ANSI") + if line.startswith('--------------'): + if current_recipe != '': + recipe_list.append(current_recipe) + current_recipe = '' + else: + current_recipe = '' + else: + current_recipe += line + '\n' + + if current_recipe != '': + recipe_list.append(current_recipe) + + return recipe_list diff --git a/cookbook/models.py b/cookbook/models.py index e46a1153..886a0e82 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -41,7 +41,6 @@ class TreeManager(MP_NodeManager): def get_or_create(self, **kwargs): kwargs['name'] = kwargs['name'].strip() try: - print(f'checking name {kwargs["name"]}') return self.get(name__exact=kwargs['name'], space=kwargs['space']), False except self.model.DoesNotExist: with scopes_disabled(): diff --git a/cookbook/templates/url_import.html b/cookbook/templates/url_import.html index 9da96d3c..da180f34 100644 --- a/cookbook/templates/url_import.html +++ b/cookbook/templates/url_import.html @@ -84,6 +84,7 @@ + diff --git a/cookbook/views/import_export.py b/cookbook/views/import_export.py index 48e131c4..26135d54 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -20,6 +20,7 @@ from cookbook.integration.mealmaster import MealMaster from cookbook.integration.nextcloud_cookbook import NextcloudCookbook from cookbook.integration.openeats import OpenEats from cookbook.integration.paprika import Paprika +from cookbook.integration.plantoeat import Plantoeat from cookbook.integration.recipekeeper import RecipeKeeper from cookbook.integration.recettetek import RecetteTek from cookbook.integration.recipesage import RecipeSage @@ -59,6 +60,8 @@ def get_integration(request, export_type): return MealMaster(request, export_type) if export_type == ImportExportBase.OPENEATS: return OpenEats(request, export_type) + if export_type == ImportExportBase.PLANTOEAT: + return Plantoeat(request, export_type) @group_required('user') diff --git a/docs/features/import_export.md b/docs/features/import_export.md index 90612af2..576f964a 100644 --- a/docs/features/import_export.md +++ b/docs/features/import_export.md @@ -35,7 +35,7 @@ Overview of the capabilities of the different integrations. | MealMaster | ✔️ | ❌ | ❌ | | RezKonv | ✔️ | ❌ | ❌ | | OpenEats | ✔️ | ❌ | ⌚ | -| OpenEats | ✔️ | ❌ | ✔ | +| Plantoeat | ✔️ | ❌ | ✔ | ✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented