From 247fd37560e0b04ab839ff41b839444008fc813d Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 21 Nov 2023 03:12:41 +0100 Subject: [PATCH] add a markdown source field to recipe --- comfyrecipes/parsing.py | 38 ++++++++++++++++++++++++++++++ comfyrecipes/schemas/recipe.json | 1 + comfyrecipes/templates/recipe.html | 1 + pyproject.toml | 2 +- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/comfyrecipes/parsing.py b/comfyrecipes/parsing.py index d702d27..5fb5833 100644 --- a/comfyrecipes/parsing.py +++ b/comfyrecipes/parsing.py @@ -6,6 +6,37 @@ import comfyrecipes.settings as settings import comfyrecipes.issues as issues import jsonschema +import lxml.html.clean +import mistune + + +class SafeHTML: + def __init__(self, clean_html: str) -> None: + self.html = clean_html + + @classmethod + def from_html(cls, dirty_html: str) -> Self: + cleaner = lxml.html.clean.Cleaner( + allow_tags=["a", "b", "em", "i", "strong"], + safe_attrs_only=True, + safe_attrs=["href"], + ) + + html = cleaner.clean_html(dirty_html).strip() + assert isinstance(html, str) + + assert html.startswith("
") + assert html.endswith("
") + html = html[5:-6] + + return cls(html) + + @classmethod + def from_markdown(cls, markdowntxt: str) -> Self: + dirty_html = mistune.html(markdowntxt) + assert isinstance(dirty_html, str) + return cls.from_html(dirty_html) + class Context: def __init__(self) -> None: @@ -219,6 +250,7 @@ class Recipe(Element): self, ctx: Context, title: str, + source: Optional[SafeHTML], ingredients: List[IngredientInstance], subrecipes: List["Recipe"], price: Optional["PriceDB"], @@ -232,6 +264,7 @@ class Recipe(Element): self.subrecipes = subrecipes self.price = price self.stepsections = stepsections + self.source = source @classmethod def from_dict(cls, ctx: Context, dct: Dict[str, Any]) -> Self: @@ -287,9 +320,14 @@ class Recipe(Element): section = StepSection.from_dict(ctx, step) stepsections.append(section) + source = None + if "source" in dct: + source = SafeHTML.from_markdown(dct["source"]) + return cls( ctx=ctx, title=dct["title"], + source=source, ingredients=ingredients, subrecipes=subrecipes, price=price, diff --git a/comfyrecipes/schemas/recipe.json b/comfyrecipes/schemas/recipe.json index a8f9876..e2220b0 100644 --- a/comfyrecipes/schemas/recipe.json +++ b/comfyrecipes/schemas/recipe.json @@ -8,6 +8,7 @@ "additionalProperties": false, "properties": { "title": { "type": "string" }, + "source": { "type": "string" }, "ingredients": { "type": "array", "items": { diff --git a/comfyrecipes/templates/recipe.html b/comfyrecipes/templates/recipe.html index 552920d..0b1bde7 100644 --- a/comfyrecipes/templates/recipe.html +++ b/comfyrecipes/templates/recipe.html @@ -17,6 +17,7 @@ {{getrecipe(subrecipe)}} {% endfor %}

{{rec.title}}

+{% if rec.source != None %}source: {{rec.source.html|safe}}{%endif%} {% if rec.ingredients|length != 0 %}

Ingredients

{% for ing in rec.ingredients %} diff --git a/pyproject.toml b/pyproject.toml index 9cac692..12f1a3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "Smart recipe static site generator" authors = [{ name = "Emi Vasilek", email = "emi.vasilek@gmail.com" }] keywords = ["recipes", "recipe", "static site generator"] requires-python = ">= 3.8" -dependencies = ["jsonschema", "jinja2", "PyYAML"] +dependencies = ["jsonschema", "jinja2", "PyYAML", "mistune", "lxml"] classifiers = [ "Development Status :: 3 - Alpha", "Programming Language :: Python",