improved paprika importer

This commit is contained in:
vabene1111 2021-03-18 14:43:19 +01:00
parent 48c90c483a
commit fe1ddf1237
3 changed files with 42 additions and 51 deletions

View File

@ -84,7 +84,7 @@ class Integration:
try:
self.files = files
for f in files:
if '.zip' in f.name:
if '.zip' in f.name or '.paprikarecipes' in f.name:
import_zip = ZipFile(f.file)
for z in import_zip.filelist:
if self.import_file_name_filter(z):

View File

@ -1,3 +1,4 @@
import base64
import json
import re
from io import BytesIO
@ -6,51 +7,39 @@ from zipfile import ZipFile
import microdata
from bs4 import BeautifulSoup
from cookbook.helper.ingredient_parser import parse
from cookbook.helper.recipe_url_import import find_recipe_json
from cookbook.integration.integration import Integration
from cookbook.models import Recipe, Step, Food, Ingredient, Unit
import gzip
class Paprika(Integration):
def import_file_name_filter(self, zip_info_object):
print("testing", zip_info_object.filename)
return re.match(r'^Recipes/([A-Za-z\s])+.html$', zip_info_object.filename)
def get_file_from_recipe(self, recipe):
raise NotImplementedError('Method not implemented in storage integration')
def get_recipe_from_file(self, file):
html_text = file.getvalue().decode("utf-8")
with gzip.open(file, 'r') as recipe_zip:
recipe_json = json.loads(recipe_zip.read().decode("utf-8"))
items = microdata.get_items(html_text)
for i in items:
md_json = json.loads(i.json())
if 'schema.org/Recipe' in str(md_json['type']):
recipe_json = find_recipe_json(md_json['properties'], '', space=self.request.space)
recipe = Recipe.objects.create(name=recipe_json['name'].strip(), created_by=self.request.user, internal=True, space=self.request.space)
step = Step.objects.create(
instruction=recipe_json['recipeInstructions']
)
recipe = Recipe.objects.create(
name=recipe_json['name'].strip(), description=recipe_json['description'].strip(),
created_by=self.request.user, internal=True, space=self.request.space)
for ingredient in recipe_json['recipeIngredient']:
f, created = Food.objects.get_or_create(name=ingredient['ingredient']['text'], space=self.request.space)
u, created = Unit.objects.get_or_create(name=ingredient['unit']['text'], space=self.request.space)
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=ingredient['amount'], note=ingredient['note']
))
step = Step.objects.create(
instruction=recipe_json['directions'] + '\n\n' + recipe_json['nutritional_info']
)
recipe.steps.add(step)
for ingredient in recipe_json['ingredients'].split('\n'):
amount, unit, ingredient, note = parse(ingredient)
f, created = Food.objects.get_or_create(name=ingredient, space=self.request.space)
u, created = Unit.objects.get_or_create(name=unit, space=self.request.space)
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=amount, note=note
))
soup = BeautifulSoup(html_text, "html.parser")
image = soup.find('img')
image_name = image.attrs['src'].strip().replace('Images/', '')
recipe.steps.add(step)
for f in self.files:
if '.zip' in f.name:
import_zip = ZipFile(f.file)
for z in import_zip.filelist:
if re.match(f'^Recipes/Images/{image_name}$', z.filename):
self.import_recipe_image(recipe, BytesIO(import_zip.read(z.filename)))
return recipe
self.import_recipe_image(recipe, BytesIO(base64.b64decode(recipe_json['photo_data'])))
return recipe

View File

@ -1,6 +1,10 @@
This application features a very versatile import and export feature in order
to offer the best experience possible and allow you to freely choose where your data goes.
!!! warning "WIP"
The Module is relatively new. There is a know issue with [Timeouts](https://github.com/vabene1111/recipes/issues/417) on large exports.
A fix is being developed and will likely be released with the next version.
The Module is build with maximum flexibility and expandability in mind and allows to easily add new
integrations to allow you to both import and export your recipes into whatever format you desire.
@ -14,6 +18,19 @@ if your favorite one is missing.
Because of this importing as many formats as possible is prioritized over exporting.
Exporter for the different formats will follow over time.
Overview of the capabilities of the different integrations.
| Integration | Import | Export | Images |
| ----------- | ------ | ------ | ------ |
| Default | ✔️ | ✔️ | ✔️ |
| Nextcloud | ✔️ | ⌚ | ✔️ |
| Mealie | ✔️ | ⌚ | ✔️ |
| Chowdown | ✔️ | ⌚ | ✔️ |
| Safron | ✔️ | ⌚ | ❌ |
| Paprika | ✔️ | ⌚ | ✔️ |
✔ = implemented, ❌ = not implemented and not possible, ⌚ = not yet implemented
## Default
The default integration is the build in (and preferred) way to import and export recipes.
It is maintained with new fields added and contains all data to transfer your recipes from one installation to another.
@ -88,22 +105,7 @@ Then simply upload the entire `.zip` file to the importer.
Safron exports do not contain any images. They will be lost during import.
## Paprika
Paprika can create two types of export. The first is a proprietary `.paprikarecipes` file in some kind of binarized format.
The second one is HTML files containing at least a bit of microdata.
A Paprika export contains a folder with a html representation of your recipes and a `.paprikarecipes` file.
If you want to import your Paprika recipes follow these steps
1. create a html export
2. Create a `.zip` file from the `Recipes` folder (next to the `index.html`) the structure should look like this
```
Recipes.zip/
└── Recipes/
├── recipe one.html
├── recipe two.thml
└── Images/
├── 5D5E09CD-8F88-4F61-8121-0727DD3E0E89/
│ └── 5D5E09CD-8F88-4F61-8121-0727DD3E0E89.jpg
└── 7CEE2AC6-DF60-4464-9B61-4F5E347EB90C/
└── 7CEE2AC6-DF60-4464-9B61-4F5E347EB90C.jpg
```
3. Upload the zip file in the import module and import it
The `.paprikarecipes` file is basically just a zip with gzipped contents. Simply upload the whole file and import
all your recipes.