import re from html import unescape from typing import cast import mistune from django.conf import settings from django.utils.html import escape from django.utils.translation import gettext as _ from catalog.models import Item, ItemCategory _mistune_plugins = [ "url", "strikethrough", "footnotes", "table", "mark", "superscript", "subscript", "math", "spoiler", "ruby", ] _markdown = mistune.create_markdown(plugins=_mistune_plugins) def convert_leading_space_in_md(body: str) -> str: 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 def render_md(s: str) -> str: return cast(str, _markdown(s)) _RE_HTML_TAG = re.compile(r"<[^>]*>") def html_to_text(h: str) -> str: return unescape(_RE_HTML_TAG.sub(" ", h.replace("\r", ""))) def _spolier(s: str) -> str: sl = s.split(">!", 1) if len(sl) == 1: return escape(s) r = sl[1].split("!<", 1) return ( escape(sl[0]) + '' + escape(r[0]) + "" + (_spolier(r[1]) if len(r) == 2 else "") ) def render_text(s: str) -> str: return _spolier(s).strip().replace("\n", "
") def render_post_with_macro(txt: str, item: Item) -> str: if not txt: return "" return ( txt.replace("[category]", str(ItemCategory(item.category).label)) .replace("[title]", item.display_title) .replace("[url]", item.absolute_url) ) 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 if star_mode == 0: 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 def render_spoiler_text(text, item): if text and text.find(">!") != -1: spoiler_text = _( "regarding {item_title}, may contain spoiler or triggering content" ).format(item_title=item.display_title) return spoiler_text, text.replace(">!", "").replace("!<", "") else: return None, text or ""