lib.itmens/journal/models/renderers.py

113 lines
2.8 KiB
Python
Raw Normal View History

import re
2024-07-13 00:16:47 -04:00
from html import unescape
2024-06-14 00:17:27 -04:00
from typing import cast
import mistune
2024-06-13 23:02:12 -04:00
from django.conf import settings
2023-01-31 10:24:57 -05:00
from django.utils.html import escape
2024-06-14 00:17:27 -04:00
from django.utils.translation import gettext as _
2024-06-13 22:13:00 -04:00
from catalog.models import Item, ItemCategory
_mistune_plugins = [
"url",
"strikethrough",
"footnotes",
"table",
"mark",
"superscript",
"subscript",
"math",
"spoiler",
2023-01-30 22:11:47 -05:00
"ruby",
]
_markdown = mistune.create_markdown(plugins=_mistune_plugins)
2023-07-20 21:59:49 -04:00
def convert_leading_space_in_md(body: str) -> str:
2023-06-03 13:47:45 -04:00
body = re.sub(r"^\s+$", "", body, flags=re.MULTILINE)
body = re.sub(
r"^(\u2003*)( +)",
lambda s: "\u2003" * ((len(s[2]) + 1) // 2 + len(s[1])),
body,
flags=re.MULTILINE,
)
return body
2023-07-20 21:59:49 -04:00
def render_md(s: str) -> str:
2023-01-30 17:15:24 -05:00
return cast(str, _markdown(s))
2024-07-13 00:16:47 -04:00
_RE_HTML_TAG = re.compile(r"<[^>]*>")
def html_to_text(h: str) -> str:
2024-07-16 13:51:55 -04:00
return unescape(
_RE_HTML_TAG.sub(
" ", h.replace("\r", "").replace("<br", "\n<br").replace("</p", "\n</p")
)
)
2024-07-13 00:16:47 -04:00
def has_spoiler(s: str) -> bool:
return ">!" in s
2023-07-20 21:59:49 -04:00
def _spolier(s: str) -> str:
2024-04-06 00:13:50 -04:00
sl = s.split(">!", 1)
if len(sl) == 1:
2023-01-31 10:24:57 -05:00
return escape(s)
2024-04-06 00:13:50 -04:00
r = sl[1].split("!<", 1)
2023-01-31 10:24:57 -05:00
return (
2024-04-06 00:13:50 -04:00
escape(sl[0])
+ '<span class="spoiler" _="on click toggle .revealed on me">'
2023-01-31 10:24:57 -05:00
+ escape(r[0])
+ "</span>"
+ (_spolier(r[1]) if len(r) == 2 else "")
)
2023-07-20 21:59:49 -04:00
def render_text(s: str) -> str:
2024-04-08 17:27:45 -04:00
return _spolier(s).strip().replace("\n", "<br>")
2024-06-13 22:13:00 -04:00
def render_post_with_macro(txt: str, item: Item) -> str:
if not txt:
return ""
return (
2024-06-13 22:13:00 -04:00
txt.replace("[category]", str(ItemCategory(item.category).label))
.replace("[title]", item.display_title)
.replace("[url]", item.absolute_url)
)
2024-06-13 23:02:12 -04:00
def render_rating(score: int | None, star_mode=0) -> str:
"""convert score(0~10) to mastodon star emoji code"""
if score is None or score == "" or score == 0:
return ""
solid_stars = score // 2
half_star = int(bool(score % 2))
empty_stars = 5 - solid_stars if not half_star else 5 - solid_stars - 1
2024-07-05 16:26:26 -04:00
if star_mode == 0:
2024-06-13 23:02:12 -04:00
emoji_code = "🌕" * solid_stars + "🌗" * half_star + "🌑" * empty_stars
else:
emoji_code = (
settings.STAR_SOLID * solid_stars
+ settings.STAR_HALF * half_star
+ settings.STAR_EMPTY * empty_stars
)
emoji_code = emoji_code.replace("::", ": :")
emoji_code = " " + emoji_code + " "
return emoji_code
2024-06-14 00:17:27 -04:00
def render_spoiler_text(text, item):
2024-07-05 16:26:26 -04:00
if text and text.find(">!") != -1:
2024-06-14 00:17:27 -04:00
spoiler_text = _(
"regarding {item_title}, may contain spoiler or triggering content"
).format(item_title=item.display_title)
return spoiler_text, text.replace(">!", "").replace("!<", "")
else:
2024-07-05 16:26:26 -04:00
return None, text or ""