added copy me that importer
This commit is contained in:
parent
b8e0a7cf69
commit
3ff15b6766
@ -152,13 +152,14 @@ class ImportExportBase(forms.Form):
|
|||||||
OPENEATS = 'OPENEATS'
|
OPENEATS = 'OPENEATS'
|
||||||
PLANTOEAT = 'PLANTOEAT'
|
PLANTOEAT = 'PLANTOEAT'
|
||||||
COOKBOOKAPP = 'COOKBOOKAPP'
|
COOKBOOKAPP = 'COOKBOOKAPP'
|
||||||
|
COPYMETHAT = 'COPYMETHAT'
|
||||||
|
|
||||||
type = forms.ChoiceField(choices=(
|
type = forms.ChoiceField(choices=(
|
||||||
(DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'),
|
(DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'),
|
||||||
(MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), (CHEFTAP, 'ChefTap'),
|
(MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), (CHEFTAP, 'ChefTap'),
|
||||||
(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'),
|
(PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
84
cookbook/integration/copymethat.py
Normal file
84
cookbook/integration/copymethat.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import re
|
||||||
|
from io import BytesIO
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
|
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||||
|
from cookbook.helper.recipe_url_import import iso_duration_to_minutes, parse_servings
|
||||||
|
from cookbook.integration.integration import Integration
|
||||||
|
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||||
|
from recipes.settings import DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
class CopyMeThat(Integration):
|
||||||
|
|
||||||
|
def import_file_name_filter(self, zip_info_object):
|
||||||
|
if DEBUG:
|
||||||
|
print("testing", zip_info_object.filename, zip_info_object.filename == 'recipes.html')
|
||||||
|
return zip_info_object.filename == 'recipes.html'
|
||||||
|
|
||||||
|
def get_recipe_from_file(self, file):
|
||||||
|
# 'file' comes is as a beautifulsoup object
|
||||||
|
recipe = Recipe.objects.create(name=file.find("div", {"id": "name"}).text.strip(), created_by=self.request.user, internal=True, space=self.request.space, )
|
||||||
|
|
||||||
|
for category in file.find_all("span", {"class": "recipeCategory"}):
|
||||||
|
keyword, created = Keyword.objects.get_or_create(name=category.text, space=self.request.space)
|
||||||
|
recipe.keywords.add(keyword)
|
||||||
|
|
||||||
|
try:
|
||||||
|
recipe.servings = parse_servings(file.find("a", {"id": "recipeYield"}).text.strip())
|
||||||
|
recipe.working_time = iso_duration_to_minutes(file.find("span", {"meta": "prepTime"}).text.strip())
|
||||||
|
recipe.waiting_time = iso_duration_to_minutes(file.find("span", {"meta": "cookTime"}).text.strip())
|
||||||
|
recipe.save()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
step = Step.objects.create(instruction='', space=self.request.space, )
|
||||||
|
|
||||||
|
ingredient_parser = IngredientParser(self.request, True)
|
||||||
|
for ingredient in file.find_all("li", {"class": "recipeIngredient"}):
|
||||||
|
if ingredient.text == "":
|
||||||
|
continue
|
||||||
|
amount, unit, ingredient, note = ingredient_parser.parse(ingredient.text.strip())
|
||||||
|
f = ingredient_parser.get_food(ingredient)
|
||||||
|
u = ingredient_parser.get_unit(unit)
|
||||||
|
step.ingredients.add(Ingredient.objects.create(
|
||||||
|
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||||
|
))
|
||||||
|
|
||||||
|
for s in file.find_all("li", {"class": "instruction"}):
|
||||||
|
if s.text == "":
|
||||||
|
continue
|
||||||
|
step.instruction += s.text.strip() + ' \n\n'
|
||||||
|
|
||||||
|
for s in file.find_all("li", {"class": "recipeNote"}):
|
||||||
|
if s.text == "":
|
||||||
|
continue
|
||||||
|
step.instruction += s.text.strip() + ' \n\n'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if file.find("a", {"id": "original_link"}).text != '':
|
||||||
|
step.instruction += "\n\nImported from: " + file.find("a", {"id": "original_link"}).text
|
||||||
|
step.save()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
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_="recipeImage").get("src"))), filetype='.jpeg')
|
||||||
|
except Exception as e:
|
||||||
|
print(recipe.name, ': failed to import image ', str(e))
|
||||||
|
|
||||||
|
recipe.save()
|
||||||
|
return recipe
|
||||||
|
|
||||||
|
def split_recipe_file(self, file):
|
||||||
|
soup = BeautifulSoup(file, "html.parser")
|
||||||
|
return soup.find_all("div", {"class": "recipe"})
|
@ -5,6 +5,7 @@ import uuid
|
|||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from zipfile import ZipFile, BadZipFile
|
from zipfile import ZipFile, BadZipFile
|
||||||
|
|
||||||
|
from bs4 import Tag
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
@ -16,7 +17,7 @@ from django_scopes import scope
|
|||||||
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
|
||||||
from cookbook.models import Keyword, Recipe
|
from cookbook.models import Keyword, Recipe
|
||||||
from recipes.settings import DATABASES, DEBUG
|
from recipes.settings import DEBUG
|
||||||
|
|
||||||
|
|
||||||
class Integration:
|
class Integration:
|
||||||
@ -153,9 +154,17 @@ class Integration:
|
|||||||
file_list.append(z)
|
file_list.append(z)
|
||||||
il.total_recipes += len(file_list)
|
il.total_recipes += len(file_list)
|
||||||
|
|
||||||
|
import cookbook
|
||||||
|
if isinstance(self, cookbook.integration.copymethat.CopyMeThat):
|
||||||
|
file_list = self.split_recipe_file(BytesIO(import_zip.read('recipes.html')))
|
||||||
|
il.total_recipes += len(file_list)
|
||||||
|
|
||||||
for z in file_list:
|
for z in file_list:
|
||||||
try:
|
try:
|
||||||
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
if isinstance(z, Tag):
|
||||||
|
recipe = self.get_recipe_from_file(z)
|
||||||
|
else:
|
||||||
|
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
||||||
recipe.keywords.add(self.keyword)
|
recipe.keywords.add(self.keyword)
|
||||||
il.msg += f'{recipe.pk} - {recipe.name} \n'
|
il.msg += f'{recipe.pk} - {recipe.name} \n'
|
||||||
self.handle_duplicates(recipe, import_duplicates)
|
self.handle_duplicates(recipe, import_duplicates)
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
<option value="CHEFTAP">Cheftap</option>
|
<option value="CHEFTAP">Cheftap</option>
|
||||||
<option value="CHOWDOWN">Chowdown</option>
|
<option value="CHOWDOWN">Chowdown</option>
|
||||||
<option value="COOKBOOKAPP">CookBookApp</option>
|
<option value="COOKBOOKAPP">CookBookApp</option>
|
||||||
|
<option value="COPYMETHAT">CopyMeThat</option>
|
||||||
<option value="DOMESTICA">Domestica</option>
|
<option value="DOMESTICA">Domestica</option>
|
||||||
<option value="MEALIE">Mealie</option>
|
<option value="MEALIE">Mealie</option>
|
||||||
<option value="MEALMASTER">Mealmaster</option>
|
<option value="MEALMASTER">Mealmaster</option>
|
||||||
|
@ -11,6 +11,7 @@ from django.utils.translation import gettext as _
|
|||||||
from cookbook.forms import ExportForm, ImportForm, ImportExportBase
|
from cookbook.forms import ExportForm, ImportForm, ImportExportBase
|
||||||
from cookbook.helper.permission_helper import group_required
|
from cookbook.helper.permission_helper import group_required
|
||||||
from cookbook.integration.cookbookapp import CookBookApp
|
from cookbook.integration.cookbookapp import CookBookApp
|
||||||
|
from cookbook.integration.copymethat import CopyMeThat
|
||||||
from cookbook.integration.pepperplate import Pepperplate
|
from cookbook.integration.pepperplate import Pepperplate
|
||||||
from cookbook.integration.cheftap import ChefTap
|
from cookbook.integration.cheftap import ChefTap
|
||||||
from cookbook.integration.chowdown import Chowdown
|
from cookbook.integration.chowdown import Chowdown
|
||||||
@ -65,6 +66,8 @@ def get_integration(request, export_type):
|
|||||||
return Plantoeat(request, export_type)
|
return Plantoeat(request, export_type)
|
||||||
if export_type == ImportExportBase.COOKBOOKAPP:
|
if export_type == ImportExportBase.COOKBOOKAPP:
|
||||||
return CookBookApp(request, export_type)
|
return CookBookApp(request, export_type)
|
||||||
|
if export_type == ImportExportBase.COPYMETHAT:
|
||||||
|
return CopyMeThat(request, export_type)
|
||||||
|
|
||||||
|
|
||||||
@group_required('user')
|
@group_required('user')
|
||||||
|
@ -37,6 +37,7 @@ Overview of the capabilities of the different integrations.
|
|||||||
| OpenEats | ✔️ | ❌ | ⌚ |
|
| OpenEats | ✔️ | ❌ | ⌚ |
|
||||||
| Plantoeat | ✔️ | ❌ | ✔ |
|
| Plantoeat | ✔️ | ❌ | ✔ |
|
||||||
| CookBookApp | ✔️ | ⌚ | ✔️ |
|
| CookBookApp | ✔️ | ⌚ | ✔️ |
|
||||||
|
| CopyMeThat | ✔️ | ❌ | ✔️ |
|
||||||
|
|
||||||
✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
|
✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
|
||||||
|
|
||||||
@ -218,3 +219,7 @@ Plan to eat allows you to export a text file containing all your recipes. Simply
|
|||||||
## CookBookApp
|
## CookBookApp
|
||||||
|
|
||||||
CookBookApp can export .zip files containing .html files. Upload the entire ZIP to Tandoor to import all included recipes.
|
CookBookApp can export .zip files containing .html files. Upload the entire ZIP to Tandoor to import all included recipes.
|
||||||
|
|
||||||
|
## CopyMeThat
|
||||||
|
|
||||||
|
CopyMeThat can export .zip files containing an `.html` file as well as a folder containing all the images. Upload the entire ZIP to Tandoor to import all included recipes.
|
Loading…
Reference in New Issue
Block a user