diff --git a/cookbook/forms.py b/cookbook/forms.py index e80fe32f..41aba506 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -110,10 +110,11 @@ class ImportExportBase(forms.Form): MEALIE = 'MEALIE' CHOWDOWN = 'CHOWDOWN' SAFRON = 'SAFRON' + CHEFTAP = 'CHEFTAP' type = forms.ChoiceField(choices=( (DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'), - (MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), + (MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), (CHEFTAP, 'ChefTap'), )) diff --git a/cookbook/integration/cheftap.py b/cookbook/integration/cheftap.py new file mode 100644 index 00000000..112f2f4d --- /dev/null +++ b/cookbook/integration/cheftap.py @@ -0,0 +1,61 @@ +import re + +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 ChefTap(Integration): + + def import_file_name_filter(self, zip_info_object): + print("testing", zip_info_object.filename) + return re.match(r'^recipes/([A-Za-z\d\w\s-])+.txt$', zip_info_object.filename) + + def is_duplicate(self, recipe): + return None + + def get_recipe_from_file(self, file): + source_url = '' + + ingredient_mode = 0 + + ingredients = [] + directions = [] + for i, fl in enumerate(file.readlines(), start=0): + line = fl.decode("utf-8") + if i == 0: + title = line.strip() + else: + if line.startswith('https:') or line.startswith('http:'): + source_url = line.strip() + else: + if ingredient_mode == 1 and len(line.strip()) == 0: + ingredient_mode = 2 + if re.match(r'^([0-9])[^.](.)*$', line) and ingredient_mode < 2: + ingredient_mode = 1 + ingredients.append(line.strip()) + else: + directions.append(line.strip()) + + recipe = Recipe.objects.create(name=title, created_by=self.request.user, internal=True, space=self.request.space, ) + + step = Step.objects.create(instruction='\n'.join(directions)) + + if source_url != '': + step.instruction += '\n' + source_url + + for ingredient in ingredients: + 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 + )) + recipe.steps.add(step) + + 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 c19b5cb6..255e6be7 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -10,6 +10,7 @@ from django.utils.translation import gettext as _ from cookbook.forms import ExportForm, ImportForm, ImportExportBase from cookbook.helper.permission_helper import group_required +from cookbook.integration.cheftap import ChefTap from cookbook.integration.chowdown import Chowdown from cookbook.integration.default import Default from cookbook.integration.mealie import Mealie @@ -32,6 +33,8 @@ def get_integration(request, export_type): return Chowdown(request, export_type) if export_type == ImportExportBase.SAFRON: return Safron(request, export_type) + if export_type == ImportExportBase.CHEFTAP: + return ChefTap(request, export_type) @group_required('user') diff --git a/docs/features/import_export.md b/docs/features/import_export.md index 2c9f786b..5f78103a 100644 --- a/docs/features/import_export.md +++ b/docs/features/import_export.md @@ -28,8 +28,9 @@ Overview of the capabilities of the different integrations. | Chowdown | ✔️ | ⌚ | ✔️ | | Safron | ✔️ | ⌚ | ❌ | | Paprika | ✔️ | ⌚ | ✔️ | +| ChefTap | ✔️ | ❌ | ❌️ | -✔ = implemented, ❌ = not implemented and not possible, ⌚ = not yet implemented +✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented ## Default The default integration is the build in (and preferred) way to import and export recipes. @@ -108,4 +109,17 @@ Then simply upload the entire `.zip` file to the importer. A Paprika export contains a folder with a html representation of your recipes and a `.paprikarecipes` file. The `.paprikarecipes` file is basically just a zip with gzipped contents. Simply upload the whole file and import -all your recipes. \ No newline at end of file +all your recipes. + +## ChefTap +ChefTaps allows you to export your recipes from the app (I think). The export is a zip file containing a folder called +`recipes` which in turn contains `.txt` files with your recipes. + +This format is basically completely unstructured and every export looks different. This makes importing it very hard +and leads to suboptimal results. Images are also not supported as they are not included in the export (at least +the tests I had). + +Usually the import should recognize all ingredients and put everything else into the instructions. If you import fails +or is worse than this feel free to provide me with more example data and I can try to improve the importer. + +As ChefTap cannot import these files anyway there won't be an exporter implemented in Tandoor. \ No newline at end of file