From 5c1de7f829f2b0e6bd5c647450ab00a68ed67224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20H=C3=A1la?= Date: Fri, 1 Dec 2023 21:29:05 +0100 Subject: [PATCH 1/5] Replace markdown with mistune - much better performance --- backend/models.py | 1 - backend/templatetags/markdown.py | 0 chords/markdown.py | 20 +++++++++------- chords/plugins/chords.py | 36 +++++++++++++++------------- chords/plugins/paragraph.py | 27 +++++++++++++++++++++ chords/plugins/spaces.py | 41 ++++++++++++++++---------------- chords/settings/base.py | 12 +--------- pyproject.toml | 2 +- 8 files changed, 80 insertions(+), 59 deletions(-) create mode 100644 backend/templatetags/markdown.py create mode 100644 chords/plugins/paragraph.py diff --git a/backend/models.py b/backend/models.py index a323b6d..38c826c 100644 --- a/backend/models.py +++ b/backend/models.py @@ -1,5 +1,4 @@ """Models for backend app""" - from django.conf import settings from django.db.models import ( Model, diff --git a/backend/templatetags/markdown.py b/backend/templatetags/markdown.py new file mode 100644 index 0000000..e69de29 diff --git a/chords/markdown.py b/chords/markdown.py index 7acbde4..b6af3c6 100644 --- a/chords/markdown.py +++ b/chords/markdown.py @@ -1,14 +1,18 @@ """Module containing Rendering function for converting Markdown to HTML""" -from django.conf import settings -from markdown import Markdown +import mistune +from chords.plugins.chords import chords +from chords.plugins.paragraph import paragraph +from chords.plugins.spaces import spaces -def create_markdown(extensions=None): - """Creates new Markdown instance""" - if extensions is None: - extensions = settings.MARKDOWNX_MARKDOWN_EXTENSIONS - return Markdown(extensions=extensions, extension_configs={}) +class CustomHTMLRenderer(mistune.HTMLRenderer): + """Soft breaks are also breaks""" + def softbreak(self) -> str: + return r"
" -RENDERER = create_markdown().convert + +RENDERER = mistune.create_markdown( + escape=False, plugins=[paragraph, chords, spaces], renderer=CustomHTMLRenderer(escape=False) +) diff --git a/chords/plugins/chords.py b/chords/plugins/chords.py index 679257d..8b40a0e 100644 --- a/chords/plugins/chords.py +++ b/chords/plugins/chords.py @@ -1,26 +1,28 @@ """Markdown extension for chords""" -from markdown.extensions import Extension -from markdown.inlinepatterns import SimpleTagInlineProcessor +from mistune import InlineState -CHORD_RE = r"({)(.*?)}" +CHORD_RE = r"\{(?!\s)(?P.+?)(?!\s)\}" -class ChordsExtension(Extension): - """Markdown extension for convert {chord} into chords""" +# pylint: disable=unused-argument +def parse_chords(inline, m, state: InlineState): + """Parses tag""" + text = m.group("chords") + state.append_token({"type": "inline_chords", "raw": text}) + return m.end() - def extendMarkdown(self, md): - # Insert del pattern into markdown parser - md.inlinePatterns.register(ChordPattern(CHORD_RE), "chord", 175) +def render_chords(renderer, text): + """Renders tag into HTML""" + return r'' + text + r" " -class ChordPattern(SimpleTagInlineProcessor): - """Pattern for ChordsExtension""" - def __init__(self, pattern): - super().__init__(pattern, "span") +def chords(md): + """A mistune plugin to support chords. + Inline chords are surrounded by `{}`, such as {Ami} - def handleMatch(self, m, data): - tag, start, end = super().handleMatch(m, data) - tag.set("class", "chord") - tag.text += " " - return tag, start, end + :param md: Markdown instance + """ + md.inline.register("inline_chords", CHORD_RE, parse_chords, before="link") + if md.renderer and md.renderer.NAME == "html": + md.renderer.register("inline_chords", render_chords) diff --git a/chords/plugins/paragraph.py b/chords/plugins/paragraph.py new file mode 100644 index 0000000..49372b1 --- /dev/null +++ b/chords/plugins/paragraph.py @@ -0,0 +1,27 @@ +"""Markdown extension for paragraphs""" +import re +import string + +# because mismatch is too slow, add parsers for paragraph and text + +PARAGRAPH = ( + # start with none punctuation, not number, not whitespace + r"(?:^[^\s\d" + + re.escape(string.punctuation) + + r"][^\n]*\n)+" +) + +__all__ = ["paragraph"] + + +# pylint: disable=unused-argument +def parse_paragraph(block, m, state): + """Parse paragraph""" + text = m.group(0) + state.add_paragraph(text) + return m.end() + + +def paragraph(md): + """Increase the speed of parsing paragraph""" + md.block.register("paragraph", PARAGRAPH, parse_paragraph) diff --git a/chords/plugins/spaces.py b/chords/plugins/spaces.py index ead7034..9ce7bc0 100644 --- a/chords/plugins/spaces.py +++ b/chords/plugins/spaces.py @@ -1,29 +1,28 @@ -"""Spaces markdown extension""" -from markdown.extensions import Extension -from markdown.inlinepatterns import SimpleTagInlineProcessor +"""Markdown extension for spaces""" +from mistune import InlineState -SPACES_RE = r"(\/)(\d+)\/" +SPACES_RE = r"\/(?P\d+)\/" -class SpacesExtension(Extension): - """Markdown extension that transforms /{number}/ into actual spaces""" +# pylint: disable=unused-argument +def parse_chords(inline, m, state: InlineState): + """Parses tag""" + text = m.group("spacers") + state.append_token({"type": "spaces", "raw": text}) + return m.end() - def extendMarkdown(self, md): - md.inlinePatterns.register(SpacesPattern(SPACES_RE), "spaces", 200) +def render_chords(renderer, text): + """Renders tag into HTML""" + return r" " * int(text) -class SpacesPattern(SimpleTagInlineProcessor): - """Pattern for SpacesExtension""" - def __init__(self, pattern): - super().__init__(pattern, "span") +def spaces(md): + """A mistune plugin to insert amount of spaces. + Inline chords are surrounded by `/`, such as /5/ - def handleMatch(self, m, data): - tag, start, end = super().handleMatch(m, data) - tag.set("class", "spaces") - count = int(tag.text) - txt = "" - for _ in range(count): - txt += " " - tag.text = txt - return tag, start, end + :param md: Markdown instance + """ + md.inline.register("spaces", SPACES_RE, parse_chords, before="link") + if md.renderer and md.renderer.NAME == "html": + md.renderer.register("spaces", render_chords) diff --git a/chords/settings/base.py b/chords/settings/base.py index 8679242..2745bae 100644 --- a/chords/settings/base.py +++ b/chords/settings/base.py @@ -15,11 +15,6 @@ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) from pathlib import Path -from markdown.extensions.nl2br import Nl2BrExtension - -from chords.plugins.chords import ChordsExtension -from chords.plugins.spaces import SpacesExtension - BASE_DIR = Path(__file__).resolve().parent.parent @@ -49,12 +44,7 @@ "django_rq", ] -MARKDOWNX_MARKDOWN_EXTENSIONS = [ - Nl2BrExtension(), - ChordsExtension(), - SpacesExtension(), -] - +MARKDOWNX_MARKDOWNIFY_FUNCTION = "chords.markdown.RENDERER" MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", diff --git a/pyproject.toml b/pyproject.toml index fb13996..eb8fdd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ weasyprint = ">=53.0" Pillow = "*" gunicorn = "*" gevent = "*" -markdown = "*" +mistune = ">3" netifaces = "*" django-compressor = "*" libsass = "*" From 9d625447ffa249ec338c22bcd2469f20eca4e29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20H=C3=A1la?= Date: Fri, 1 Dec 2023 21:37:09 +0100 Subject: [PATCH 2/5] Remove legacy templates --- backend/templates/songs/fragments/song.html | 42 --------------------- backend/templates/songs/song.html | 37 ------------------ 2 files changed, 79 deletions(-) delete mode 100644 backend/templates/songs/fragments/song.html delete mode 100644 backend/templates/songs/song.html diff --git a/backend/templates/songs/fragments/song.html b/backend/templates/songs/fragments/song.html deleted file mode 100644 index d43406e..0000000 --- a/backend/templates/songs/fragments/song.html +++ /dev/null @@ -1,42 +0,0 @@ -{% load i18n %} -{% load markdown %} - -
  • - {{ song.song_number }} - {{ song.text }} - {{ song.name }} - {{ song.author }} -
    -

    {{ song.song_number }}. {{ song.name }}

    - {% if song.author %} -
    {{ song.author }}
    - {% endif %} - - {% if user.is_authenticated %} -
    - -
    -
    - -
    - {% endif %} -
    -
    - -
  • \ No newline at end of file diff --git a/backend/templates/songs/song.html b/backend/templates/songs/song.html deleted file mode 100644 index 7f1d46b..0000000 --- a/backend/templates/songs/song.html +++ /dev/null @@ -1,37 +0,0 @@ -{% load markdown %} -{% load i18n %} - -{{ song.song_number }} -{{ song.text }} -{{ song.name }} -{{ song.author }} -
    -

    {{ song.song_number }}. {{ song.name }} {% if song.capo %}/Capo {{ song.capo }}/{% endif %}

    - {% if song.author %} -
    {{ song.author }}
    - {% endif %} - {% if user.is_authenticated %} -
    - -
    - - {% endif %} -
    - \ No newline at end of file From 994bec83e33be1bdb850dd88432b26eb8a744996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20H=C3=A1la?= Date: Fri, 1 Dec 2023 22:14:46 +0100 Subject: [PATCH 3/5] Fix PDF css font paths --- pdf/static/pdf.sass | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdf/static/pdf.sass b/pdf/static/pdf.sass index 948b85a..cd88872 100644 --- a/pdf/static/pdf.sass +++ b/pdf/static/pdf.sass @@ -1,11 +1,11 @@ @font-face font-family: "Open Sans" - src: url(/static/OpenSans-Regular.ttf) + src: url(OpenSans-Regular.ttf) @font-face font-family: "Open Sans" font-weight: bold - src: url(/static/OpenSans-Bold.ttf) + src: url(OpenSans-Bold.ttf) @page @bottom-left From 1e4e54f847f155e95ef3732a0b9b0feb8e59e418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20H=C3=A1la?= Date: Fri, 1 Dec 2023 22:15:00 +0100 Subject: [PATCH 4/5] Change date on PDF to d.m.Y --- pdf/templates/pdf/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf/templates/pdf/index.html b/pdf/templates/pdf/index.html index 1d795cd..ef5f197 100644 --- a/pdf/templates/pdf/index.html +++ b/pdf/templates/pdf/index.html @@ -40,7 +40,7 @@

    {% if request.title %}{{ name }}{% endif %}

    {% if request.show_date %} -

    {% now "m.d.Y" %}

    +

    {% now "d.m.Y" %}

    {% endif %}

    {% trans "Table of Contents" %}

      From 298613f84f97f4b6441b7147d93ccf7e510df771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20H=C3=A1la?= Date: Fri, 1 Dec 2023 22:15:08 +0100 Subject: [PATCH 5/5] Upgrade django to 4.2.7 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index eb8fdd4..9483cc6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.9" -django = "==4.2.5" +django = "==4.2.7" django-bootstrap4 = "*" dj-datatables-view = "*" django-debug-toolbar = "*"