added cookmate importer
This commit is contained in:
@ -159,6 +159,7 @@ class ImportExportBase(forms.Form):
|
|||||||
PLANTOEAT = 'PLANTOEAT'
|
PLANTOEAT = 'PLANTOEAT'
|
||||||
COOKBOOKAPP = 'COOKBOOKAPP'
|
COOKBOOKAPP = 'COOKBOOKAPP'
|
||||||
COPYMETHAT = 'COPYMETHAT'
|
COPYMETHAT = 'COPYMETHAT'
|
||||||
|
COOKMATE = 'COOKMATE'
|
||||||
PDF = 'PDF'
|
PDF = 'PDF'
|
||||||
|
|
||||||
type = forms.ChoiceField(choices=(
|
type = forms.ChoiceField(choices=(
|
||||||
@ -167,6 +168,7 @@ class ImportExportBase(forms.Form):
|
|||||||
(PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'),
|
(PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'),
|
||||||
(MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'),
|
(MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'),
|
||||||
(PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), (PDF, 'PDF'), (MELARECIPES, 'Melarecipes'),
|
(PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), (PDF, 'PDF'), (MELARECIPES, 'Melarecipes'),
|
||||||
|
(COOKMATE, 'Cookmate')
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
77
cookbook/integration/cookmate.py
Normal file
77
cookbook/integration/cookmate.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import base64
|
||||||
|
import json
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
|
from cookbook.helper.recipe_url_import import parse_servings, parse_time, parse_servings_text
|
||||||
|
from cookbook.integration.integration import Integration
|
||||||
|
from cookbook.models import Ingredient, Keyword, Recipe, Step
|
||||||
|
|
||||||
|
|
||||||
|
class Cookmate(Integration):
|
||||||
|
|
||||||
|
def import_file_name_filter(self, zip_info_object):
|
||||||
|
return zip_info_object.filename.endswith('.xml')
|
||||||
|
|
||||||
|
def get_files_from_recipes(self, recipes, el, cookie):
|
||||||
|
raise NotImplementedError('Method not implemented in storage integration')
|
||||||
|
|
||||||
|
def get_recipe_from_file(self, file):
|
||||||
|
recipe_xml = file
|
||||||
|
|
||||||
|
recipe = Recipe.objects.create(
|
||||||
|
name=recipe_xml.find('title').text.strip(),
|
||||||
|
created_by=self.request.user, internal=True, space=self.request.space)
|
||||||
|
|
||||||
|
if recipe_xml.find('preptime') is not None:
|
||||||
|
recipe.working_time = parse_time(recipe_xml.find('preptime').text.strip())
|
||||||
|
|
||||||
|
if recipe_xml.find('cooktime') is not None:
|
||||||
|
recipe.waiting_time = parse_time(recipe_xml.find('cooktime').text.strip())
|
||||||
|
|
||||||
|
if recipe_xml.find('quantity') is not None:
|
||||||
|
recipe.servings = parse_servings(recipe_xml.find('quantity').text.strip())
|
||||||
|
recipe.servings_text = parse_servings_text(recipe_xml.find('quantity').text.strip())
|
||||||
|
|
||||||
|
if recipe_xml.find('url') is not None:
|
||||||
|
recipe.source_url = recipe_xml.find('url').text.strip()
|
||||||
|
|
||||||
|
if recipe_xml.find('description') is not None: # description is a list of <li>'s with text
|
||||||
|
if len(recipe_xml.find('description')) > 0:
|
||||||
|
recipe.description = recipe_xml.find('description')[0].text[:512]
|
||||||
|
|
||||||
|
for step in recipe_xml.find('recipetext').getchildren():
|
||||||
|
step = Step.objects.create(
|
||||||
|
instruction=step.text.strip(), space=self.request.space,
|
||||||
|
)
|
||||||
|
recipe.steps.add(step)
|
||||||
|
|
||||||
|
ingredient_parser = IngredientParser(self.request, True)
|
||||||
|
|
||||||
|
for ingredient in recipe_xml.find('ingredient').getchildren():
|
||||||
|
if ingredient.text.strip() != '':
|
||||||
|
amount, unit, food, note = ingredient_parser.parse(ingredient.text.strip())
|
||||||
|
f = ingredient_parser.get_food(food)
|
||||||
|
u = ingredient_parser.get_unit(unit)
|
||||||
|
recipe.steps.first().ingredients.add(Ingredient.objects.create(
|
||||||
|
food=f, unit=u, amount=amount, note=note, original_text=ingredient.text.strip(), space=self.request.space,
|
||||||
|
))
|
||||||
|
|
||||||
|
if recipe_xml.find('imageurl') is not None:
|
||||||
|
try:
|
||||||
|
response = requests.get(recipe_xml.find('imageurl').text.strip())
|
||||||
|
self.import_recipe_image(recipe, BytesIO(response.content))
|
||||||
|
except Exception as e:
|
||||||
|
print('failed to import image ', str(e))
|
||||||
|
|
||||||
|
recipe.save()
|
||||||
|
|
||||||
|
return recipe
|
||||||
|
|
||||||
|
def get_file_from_recipe(self, recipe):
|
||||||
|
raise NotImplementedError('Method not implemented in storage integration')
|
@ -5,6 +5,8 @@ import traceback
|
|||||||
import uuid
|
import uuid
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from zipfile import BadZipFile, ZipFile
|
from zipfile import BadZipFile, ZipFile
|
||||||
|
|
||||||
|
import lxml
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ from django.http import HttpResponse
|
|||||||
from django.utils.formats import date_format
|
from django.utils.formats import date_format
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django_scopes import scope
|
from django_scopes import scope
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
from cookbook.forms import ImportExportBase
|
from cookbook.forms import ImportExportBase
|
||||||
from cookbook.helper.image_processing import get_filetype, handle_image
|
from cookbook.helper.image_processing import get_filetype, handle_image
|
||||||
@ -144,7 +147,7 @@ class Integration:
|
|||||||
il.imported_recipes += 1
|
il.imported_recipes += 1
|
||||||
il.save()
|
il.save()
|
||||||
import_zip.close()
|
import_zip.close()
|
||||||
elif '.zip' in f['name'] or '.paprikarecipes' in f['name']:
|
elif '.zip' in f['name'] or '.paprikarecipes' in f['name'] or '.mcb' in f['name']:
|
||||||
import_zip = ZipFile(f['file'])
|
import_zip = ZipFile(f['file'])
|
||||||
file_list = []
|
file_list = []
|
||||||
for z in import_zip.filelist:
|
for z in import_zip.filelist:
|
||||||
@ -157,9 +160,16 @@ class Integration:
|
|||||||
file_list = self.split_recipe_file(BytesIO(import_zip.read('recipes.html')))
|
file_list = self.split_recipe_file(BytesIO(import_zip.read('recipes.html')))
|
||||||
il.total_recipes += len(file_list)
|
il.total_recipes += len(file_list)
|
||||||
|
|
||||||
|
if isinstance(self, cookbook.integration.cookmate.Cookmate):
|
||||||
|
new_file_list = []
|
||||||
|
for file in file_list:
|
||||||
|
new_file_list += etree.parse(BytesIO(import_zip.read(file.filename))).getroot().getchildren()
|
||||||
|
il.total_recipes = len(new_file_list)
|
||||||
|
file_list = new_file_list
|
||||||
|
|
||||||
for z in file_list:
|
for z in file_list:
|
||||||
try:
|
try:
|
||||||
if isinstance(z, Tag):
|
if not hasattr(z, 'filename'):
|
||||||
recipe = self.get_recipe_from_file(z)
|
recipe = self.get_recipe_from_file(z)
|
||||||
else:
|
else:
|
||||||
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
||||||
|
@ -15,6 +15,7 @@ from cookbook.helper.recipe_search import RecipeSearch
|
|||||||
from cookbook.integration.cheftap import ChefTap
|
from cookbook.integration.cheftap import ChefTap
|
||||||
from cookbook.integration.chowdown import Chowdown
|
from cookbook.integration.chowdown import Chowdown
|
||||||
from cookbook.integration.cookbookapp import CookBookApp
|
from cookbook.integration.cookbookapp import CookBookApp
|
||||||
|
from cookbook.integration.cookmate import Cookmate
|
||||||
from cookbook.integration.copymethat import CopyMeThat
|
from cookbook.integration.copymethat import CopyMeThat
|
||||||
from cookbook.integration.default import Default
|
from cookbook.integration.default import Default
|
||||||
from cookbook.integration.domestica import Domestica
|
from cookbook.integration.domestica import Domestica
|
||||||
@ -77,6 +78,8 @@ def get_integration(request, export_type):
|
|||||||
return PDFexport(request, export_type)
|
return PDFexport(request, export_type)
|
||||||
if export_type == ImportExportBase.MELARECIPES:
|
if export_type == ImportExportBase.MELARECIPES:
|
||||||
return MelaRecipes(request, export_type)
|
return MelaRecipes(request, export_type)
|
||||||
|
if export_type == ImportExportBase.COOKMATE:
|
||||||
|
return Cookmate(request, export_type)
|
||||||
|
|
||||||
|
|
||||||
@group_required('user')
|
@group_required('user')
|
||||||
|
@ -38,7 +38,8 @@ Overview of the capabilities of the different integrations.
|
|||||||
| Plantoeat | ✔️ | ❌ | ✔ |
|
| Plantoeat | ✔️ | ❌ | ✔ |
|
||||||
| CookBookApp | ✔️ | ⌚ | ✔️ |
|
| CookBookApp | ✔️ | ⌚ | ✔️ |
|
||||||
| CopyMeThat | ✔️ | ❌ | ✔️ |
|
| CopyMeThat | ✔️ | ❌ | ✔️ |
|
||||||
| CopyMeThat | ✔️ | ⌚ | ✔️ |
|
| Melarecipes | ✔️ | ⌚ | ✔️ |
|
||||||
|
| Cookmate | ✔️ | ⌚ | ✔️ |
|
||||||
| PDF (experimental) | ⌚️ | ✔️ | ✔️ |
|
| PDF (experimental) | ⌚️ | ✔️ | ✔️ |
|
||||||
|
|
||||||
✔️ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
|
✔️ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
|
||||||
|
@ -5,6 +5,7 @@ export const INTEGRATIONS = [
|
|||||||
{id: 'CHEFTAP', name: "Cheftap", import: true, export: false},
|
{id: 'CHEFTAP', name: "Cheftap", import: true, export: false},
|
||||||
{id: 'CHOWDOWN', name: "Chowdown", import: true, export: false},
|
{id: 'CHOWDOWN', name: "Chowdown", import: true, export: false},
|
||||||
{id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false},
|
{id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false},
|
||||||
|
{id: 'COOKMATE', name: "Cookmate", import: true, export: false},
|
||||||
{id: 'COPYMETHAT', name: "CopyMeThat", import: true, export: false},
|
{id: 'COPYMETHAT', name: "CopyMeThat", import: true, export: false},
|
||||||
{id: 'DOMESTICA', name: "Domestica", import: true, export: false},
|
{id: 'DOMESTICA', name: "Domestica", import: true, export: false},
|
||||||
{id: 'MEALIE', name: "Mealie", import: true, export: false},
|
{id: 'MEALIE', name: "Mealie", import: true, export: false},
|
||||||
|
Reference in New Issue
Block a user