Add /spoiler and /unspoiler
This commit is contained in:
		| @@ -138,6 +138,13 @@ class HTMLProcessor: | |||||||
|         re.MULTILINE, |         re.MULTILINE, | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |     spoiler_regex = re.compile( | ||||||
|  |         r"(<span[^>]+data-mx-spoiler[^>]*>)" | ||||||
|  |         r"(.*?)" | ||||||
|  |         r"(</?span>)", | ||||||
|  |         re.MULTILINE, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|     extra_newlines_regex = re.compile(r"\n(\n*)") |     extra_newlines_regex = re.compile(r"\n(\n*)") | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -224,6 +231,7 @@ class HTMLProcessor: | |||||||
|         # Client-side modifications |         # Client-side modifications | ||||||
|  |  | ||||||
|         html = self.quote_regex.sub(r'\1<span class="quote">\2</span>\3', html) |         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: |         if not inline: | ||||||
|             return html |             return html | ||||||
| @@ -250,11 +258,11 @@ class HTMLProcessor: | |||||||
|             "font": {"color"}, |             "font": {"color"}, | ||||||
|             "a":    {"href", "class", "data-mention"}, |             "a":    {"href", "class", "data-mention"}, | ||||||
|             "code": {"class"}, |             "code": {"class"}, | ||||||
|  |             "span": {"data-mx-spoiler", "data-mx-color"}, | ||||||
|         } |         } | ||||||
|         attributes = {**inlines_attributes, **{ |         attributes = {**inlines_attributes, **{ | ||||||
|             "ol":   {"start"}, |             "ol":   {"start"}, | ||||||
|             "hr":   {"width"}, |             "hr":   {"width"}, | ||||||
|             "span": {"data-mx-color"}, |  | ||||||
|             "img":  { |             "img":  { | ||||||
|                 "data-mx-emote", "src", "alt", "title", "width", "height", |                 "data-mx-emote", "src", "alt", "title", "width", "height", | ||||||
|             }, |             }, | ||||||
|   | |||||||
| @@ -183,6 +183,8 @@ class MatrixClient(nio.AsyncClient): | |||||||
|         self.cmd_handler_map = { |         self.cmd_handler_map = { | ||||||
|             "me ":        MatrixClient.handle_cmd_emote, |             "me ":        MatrixClient.handle_cmd_emote, | ||||||
|             "react ":     MatrixClient.handle_cmd_react, |             "react ":     MatrixClient.handle_cmd_react, | ||||||
|  |             "spoiler ":   MatrixClient.handle_cmd_spoiler, | ||||||
|  |             "unspoiler":  MatrixClient.handle_cmd_unspoiler, | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
| @@ -655,6 +657,8 @@ class MatrixClient(nio.AsyncClient): | |||||||
|         text:                  str, |         text:                  str, | ||||||
|         display_name_mentions: Optional[Dict[str, str]] = None,  # {id: name} |         display_name_mentions: Optional[Dict[str, str]] = None,  # {id: name} | ||||||
|         reply_to_event_id:     Optional[str]            = None, |         reply_to_event_id:     Optional[str]            = None, | ||||||
|  |         override_to_html:      Optional[str]            = None, | ||||||
|  |         override_echo_body:    Optional[str]            = None, | ||||||
|         emote:                 bool                     = False, |         emote:                 bool                     = False, | ||||||
|     ) -> None: |     ) -> None: | ||||||
|         """Send a markdown `m.text` or `m.emote` message .""" |         """Send a markdown `m.text` or `m.emote` message .""" | ||||||
| @@ -676,6 +680,12 @@ class MatrixClient(nio.AsyncClient): | |||||||
|             to_html    = from_md(text, outgoing=True) |             to_html    = from_md(text, outgoing=True) | ||||||
|             echo_body  = from_md(text) |             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>"): |         if to_html not in (html.escape(text), f"<p>{html.escape(text)}</p>"): | ||||||
|             content["format"]         = "org.matrix.custom.html" |             content["format"]         = "org.matrix.custom.html" | ||||||
|             content["formatted_body"] = to_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) |             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( |     async def send_reaction( | ||||||
|         self, |         self, | ||||||
|         room_id:   str, |         room_id:   str, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	