Add /spoiler and /unspoiler
This commit is contained in:
		| @@ -138,6 +138,13 @@ class HTMLProcessor: | ||||
|         re.MULTILINE, | ||||
|     ) | ||||
|  | ||||
|     spoiler_regex = re.compile( | ||||
|         r"(<span[^>]+data-mx-spoiler[^>]*>)" | ||||
|         r"(.*?)" | ||||
|         r"(</?span>)", | ||||
|         re.MULTILINE, | ||||
|     ) | ||||
|  | ||||
|     extra_newlines_regex = re.compile(r"\n(\n*)") | ||||
|  | ||||
|  | ||||
| @@ -224,6 +231,7 @@ class HTMLProcessor: | ||||
|         # Client-side modifications | ||||
|  | ||||
|         html = self.quote_regex.sub(r'\1<span class="quote">\2</span>\3', html) | ||||
|         html = self.spoiler_regex.sub(r'\1<font color="#00000000">\2</font>\3', html) | ||||
|  | ||||
|         if not inline: | ||||
|             return html | ||||
| @@ -250,11 +258,11 @@ class HTMLProcessor: | ||||
|             "font": {"color"}, | ||||
|             "a":    {"href", "class", "data-mention"}, | ||||
|             "code": {"class"}, | ||||
|             "span": {"data-mx-spoiler", "data-mx-color"}, | ||||
|         } | ||||
|         attributes = {**inlines_attributes, **{ | ||||
|             "ol":   {"start"}, | ||||
|             "hr":   {"width"}, | ||||
|             "span": {"data-mx-color"}, | ||||
|             "img":  { | ||||
|                 "data-mx-emote", "src", "alt", "title", "width", "height", | ||||
|             }, | ||||
|   | ||||
| @@ -183,6 +183,8 @@ class MatrixClient(nio.AsyncClient): | ||||
|         self.cmd_handler_map = { | ||||
|             "me ":        MatrixClient.handle_cmd_emote, | ||||
|             "react ":     MatrixClient.handle_cmd_react, | ||||
|             "spoiler ":   MatrixClient.handle_cmd_spoiler, | ||||
|             "unspoiler":  MatrixClient.handle_cmd_unspoiler, | ||||
|         } | ||||
|  | ||||
|         try: | ||||
| @@ -655,6 +657,8 @@ class MatrixClient(nio.AsyncClient): | ||||
|         text:                  str, | ||||
|         display_name_mentions: Optional[Dict[str, str]] = None,  # {id: name} | ||||
|         reply_to_event_id:     Optional[str]            = None, | ||||
|         override_to_html:      Optional[str]            = None, | ||||
|         override_echo_body:    Optional[str]            = None, | ||||
|         emote:                 bool                     = False, | ||||
|     ) -> None: | ||||
|         """Send a markdown `m.text` or `m.emote` message .""" | ||||
| @@ -676,6 +680,12 @@ class MatrixClient(nio.AsyncClient): | ||||
|             to_html    = from_md(text, outgoing=True) | ||||
|             echo_body  = from_md(text) | ||||
|  | ||||
|         # override_echo_body will not be effective if it is a reply. | ||||
|         # echo_body is only shown before the event is received back from the | ||||
|         # server, so this is fine if not ideal | ||||
|         to_html   = override_to_html   or to_html | ||||
|         echo_body = override_echo_body or echo_body | ||||
|  | ||||
|         if to_html not in (html.escape(text), f"<p>{html.escape(text)}</p>"): | ||||
|             content["format"]         = "org.matrix.custom.html" | ||||
|             content["formatted_body"] = to_html | ||||
| @@ -762,6 +772,56 @@ class MatrixClient(nio.AsyncClient): | ||||
|             await self.send_reaction(room_id, reaction, reply_to_event_id) | ||||
|  | ||||
|  | ||||
|     async def handle_cmd_spoiler( | ||||
|         self, | ||||
|         room_id:                str, | ||||
|         text:                   str, | ||||
|         display_name_mentions:  Optional[Dict[str, str]]  = None,  # {id: name} | ||||
|         reply_to_event_id:      Optional[str]             = None, | ||||
|     ) -> None: | ||||
|  | ||||
|         from_md = partial( | ||||
|             HTML.from_markdown, display_name_mentions=display_name_mentions, | ||||
|         ) | ||||
|  | ||||
|         to_html    = from_md(text, outgoing=True) | ||||
|         echo_body  = from_md(text) | ||||
|  | ||||
|         to_html    = f"<span data-mx-spoiler>{to_html}</span>" | ||||
|         echo_body  = f"<span data-mx-spoiler>{echo_body}</span>" | ||||
|  | ||||
|  | ||||
|         await self._send_text( | ||||
|             room_id, | ||||
|             text, | ||||
|             display_name_mentions, | ||||
|             reply_to_event_id, | ||||
|             override_to_html = to_html, | ||||
|             override_echo_body = echo_body, | ||||
|         ) | ||||
|  | ||||
|  | ||||
|     async def handle_cmd_unspoiler( | ||||
|         self, | ||||
|         room_id:                str, | ||||
|         text:                   str, | ||||
|         display_name_mentions:  Optional[Dict[str, str]]  = None,  # {id: name} | ||||
|         reply_to_event_id:      Optional[str]             = None, | ||||
|     ) -> None: | ||||
|         if reply_to_event_id is None or reply_to_event_id == '': | ||||
|             await self.send_fake_notice(room_id, "Please reply to a message with /unspoiler to unspoiler it 🙃") | ||||
|         else: | ||||
|             spoiler_event: Event = \ | ||||
|                 self.models[self.user_id, room_id, "events"][reply_to_event_id] | ||||
|  | ||||
|             # get formatted_body, fallback to body, | ||||
|             spoiler = getattr(spoiler_event.source, "formatted_body", None) or \ | ||||
|                       getattr(spoiler_event.source, "body", "") | ||||
|  | ||||
|             unspoiler = re.sub(r'<span[^>]+data-mx-spoiler[^>]*>(.*?)</?span>', r'\1', spoiler) | ||||
|             await self.send_fake_notice(room_id, unspoiler) | ||||
|  | ||||
|  | ||||
|     async def send_reaction( | ||||
|         self, | ||||
|         room_id:   str, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	