Merge pull request #591 from itsmegb/importer-reciepekeeper
New Importer - Reciepe Keeper
This commit is contained in:
commit
46db6d4186
@ -121,6 +121,7 @@ class ImportExportBase(forms.Form):
|
||||
SAFRON = 'SAFRON'
|
||||
CHEFTAP = 'CHEFTAP'
|
||||
PEPPERPLATE = 'PEPPERPLATE'
|
||||
RECIPEKEEPER = 'RECIPEKEEPER'
|
||||
RECETTETEK = 'RECETTETEK'
|
||||
RECIPESAGE = 'RECIPESAGE'
|
||||
DOMESTICA = 'DOMESTICA'
|
||||
@ -132,7 +133,8 @@ class ImportExportBase(forms.Form):
|
||||
(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'),
|
||||
(MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'),
|
||||
|
||||
))
|
||||
|
||||
|
||||
|
@ -104,7 +104,18 @@ class Integration:
|
||||
try:
|
||||
self.files = files
|
||||
for f in files:
|
||||
if '.zip' in f['name'] or '.paprikarecipes' in f['name']:
|
||||
if 'RecipeKeeper' 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()
|
||||
elif '.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):
|
||||
|
81
cookbook/integration/recipekeeper.py
Normal file
81
cookbook/integration/recipekeeper.py
Normal file
@ -0,0 +1,81 @@
|
||||
import re
|
||||
from bs4 import BeautifulSoup
|
||||
from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
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, Keyword
|
||||
|
||||
|
||||
class RecipeKeeper(Integration):
|
||||
|
||||
def import_file_name_filter(self, zip_info_object):
|
||||
return re.match(r'^recipes.html$', zip_info_object.filename)
|
||||
|
||||
def split_recipe_file(self, file):
|
||||
recipe_html = BeautifulSoup(file, 'html.parser')
|
||||
return recipe_html.find_all('div', class_='recipe-details')
|
||||
|
||||
def get_recipe_from_file(self, file):
|
||||
# 'file' comes is as a beautifulsoup object
|
||||
recipe = Recipe.objects.create(name=file.find("h2", {"itemprop": "name"}).text.strip(), created_by=self.request.user, internal=True, space=self.request.space, )
|
||||
|
||||
# add 'Courses' and 'Categories' as keywords
|
||||
for course in file.find_all("span", {"itemprop": "recipeCourse"}):
|
||||
keyword, created = Keyword.objects.get_or_create(name=course.text, space=self.request.space)
|
||||
recipe.keywords.add(keyword)
|
||||
|
||||
for category in file.find_all("meta", {"itemprop": "recipeCategory"}):
|
||||
keyword, created = Keyword.objects.get_or_create(name=category.get("content"), space=self.request.space)
|
||||
recipe.keywords.add(keyword)
|
||||
|
||||
# TODO: import prep and cook times
|
||||
# Recipe Keeper uses ISO 8601 format for its duration periods.
|
||||
|
||||
source_url_added = False
|
||||
ingredients_added = False
|
||||
for s in file.find("div", {"itemprop": "recipeDirections"}).find_all("p"):
|
||||
|
||||
if s.text == "":
|
||||
continue
|
||||
|
||||
step = Step.objects.create(
|
||||
instruction=s.text
|
||||
)
|
||||
|
||||
if not source_url_added:
|
||||
# If there is a source URL, add it to the first step field.
|
||||
if file.find("span", {"itemprop": "recipeSource"}).text != '':
|
||||
step.instruction += "\n\nImported from: " + file.find("span", {"itemprop": "recipeSource"}).text
|
||||
step.save()
|
||||
source_url_added = True
|
||||
|
||||
if not ingredients_added:
|
||||
ingredients_added = True
|
||||
for ingredient in file.find("div", {"itemprop": "recipeIngredients"}).findChildren("p"):
|
||||
if ingredient.text == "":
|
||||
continue
|
||||
amount, unit, ingredient, note = parse(ingredient.text.strip())
|
||||
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)
|
||||
|
||||
# import the Primary recipe image that is stored in the Zip
|
||||
try:
|
||||
for f in self.files:
|
||||
if '.zip' in f['name']:
|
||||
import_zip = ZipFile(f['file'])
|
||||
self.import_recipe_image(recipe, BytesIO(import_zip.read(file.find("img", class_="recipe-photo").get("src"))))
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
return recipe
|
||||
|
||||
def get_file_from_recipe(self, recipe):
|
||||
raise NotImplementedError('Method not implemented in storage integration')
|
@ -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.recipekeeper import RecipeKeeper
|
||||
from cookbook.integration.recettetek import RecetteTek
|
||||
from cookbook.integration.recipesage import RecipeSage
|
||||
from cookbook.integration.rezkonv import RezKonv
|
||||
@ -46,6 +47,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.RECIPEKEEPER:
|
||||
return RecipeKeeper(request, export_type)
|
||||
if export_type == ImportExportBase.RECETTETEK:
|
||||
return RecetteTek(request, export_type)
|
||||
if export_type == ImportExportBase.RECIPESAGE:
|
||||
|
Loading…
Reference in New Issue
Block a user