diff --git a/example-config.yaml b/example-config.yaml index 2534728d..9a601c8f 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -70,12 +70,6 @@ bridge: - username - phone number - # Whether or not to use native Matrix replies. At the time of writing, only riot-web supports - # replies and the format of them is subject to change. - native_replies: true - # If native replies are disabled, should the custom replies contain a link to the message being - # replied to? - link_in_reply: false # Show message editing as a reply to the original message. # If this is false, message edits are not shown at all, as Matrix does not support editing yet. edits_as_replies: false diff --git a/mautrix_telegram/formatter/from_matrix.py b/mautrix_telegram/formatter/from_matrix.py index 72d2edfe..be9b88f8 100644 --- a/mautrix_telegram/formatter/from_matrix.py +++ b/mautrix_telegram/formatter/from_matrix.py @@ -25,7 +25,7 @@ from telethon_aio.tl.types import * from .. import user as u, puppet as pu, portal as po from ..db import Message as DBMessage -from .util import add_surrogates, remove_surrogates +from .util import (add_surrogates, remove_surrogates, trim_reply_fallback_html, trim_reply_fallback_text) log = logging.getLogger("mau.fmt.mx") @@ -232,6 +232,14 @@ def matrix_reply_to_telegram(content, tg_space, room_id=None): reply = content["m.relates_to"]["m.in_reply_to"] room_id = room_id or reply["room_id"] event_id = reply["event_id"] + + try: + if content["format"] == "org.custom.matrix.html": + content["formatted_body"] = trim_reply_fallback_html(content["formatted_body"]) + except KeyError: + pass + content["body"] = trim_reply_fallback_text(content["body"]) + message = DBMessage.query.filter(DBMessage.mxid == event_id, DBMessage.tg_space == tg_space, DBMessage.mx_room == room_id).one_or_none() diff --git a/mautrix_telegram/formatter/from_telegram.py b/mautrix_telegram/formatter/from_telegram.py index 34d81e7f..276f68c3 100644 --- a/mautrix_telegram/formatter/from_telegram.py +++ b/mautrix_telegram/formatter/from_telegram.py @@ -22,7 +22,8 @@ from mautrix_appservice import MatrixRequestError from .. import user as u, puppet as pu, portal as po from ..db import Message as DBMessage -from .util import add_surrogates, remove_surrogates +from .util import (add_surrogates, remove_surrogates, trim_reply_fallback_html, + trim_reply_fallback_text) log = logging.getLogger("mau.fmt.tg") @@ -67,8 +68,7 @@ async def _add_forward_header(source, text, html, fwd_from_id): return text, html -async def _add_reply_header(source, text, html, evt, relates_to, - native_replies, message_link_in_reply, main_intent, reply_text): +async def _add_reply_header(source, text, html, evt, relates_to, main_intent, is_edit): space = (evt.to_id.channel_id if isinstance(evt, Message) and isinstance(evt.to_id, PeerChannel) else source.tgid) @@ -77,42 +77,50 @@ async def _add_reply_header(source, text, html, evt, relates_to, if not msg: return text, html - if native_replies: - relates_to["m.in_reply_to"] = { - "event_id": msg.mxid, - "room_id": msg.mx_room, - } - if reply_text == "Edit": - html = f"Edit: {html or escape(text)}" - text = f"Edit: {text}" - return text, html + relates_to["m.in_reply_to"] = { + "event_id": msg.mxid, + "room_id": msg.mx_room, + } + if is_edit: + html = f"Edit: {html or escape(text)}" + text = f"Edit: {text}" - reply_displayname = "unknown user" try: event = await main_intent.get_event(msg.mx_room, msg.mxid) + content = event["content"] - body = (content["formatted_body"] - if "formatted_body" in content - else escape(content["body"])) - sender = event['sender'] - puppet = pu.Puppet.get_by_mxid(sender, create=False) - reply_displayname = puppet.displayname if puppet else sender - reply_to_user = f"{reply_displayname}" - reply_to_msg = (("{reply_text}") - if message_link_in_reply else "Reply") - quote = f"{reply_to_msg} to {reply_to_user}
{body}" + r_sender = event["sender"] + + r_text_body = trim_reply_fallback_text(content["body"]) + r_html_body = trim_reply_fallback_html(content["formatted_body"] + if "formatted_body" in content + else escape(content["body"])) + + puppet = pu.Puppet.get_by_mxid(r_sender, create=False) + r_displayname = puppet.displayname if puppet else r_sender + r_sender_link = f"{r_displayname}" except (ValueError, KeyError, MatrixRequestError): - quote = f"{reply_text} to unknown user (Failed to fetch message):
{r_msg_link} {r_sender_link} {r_html_body}" + + (html or escape(text))) + + lines = r_text_body.strip().split("\n") + text_with_quote = f"> <{r_displayname}> {lines.pop(0)}" + for line in lines: + if line: + text_with_quote += f"\n> {line}" + text_with_quote += "\n\n" + text_with_quote += text + return text_with_quote, html -async def telegram_to_matrix(evt, source, native_replies=False, message_link_in_reply=False, - main_intent=None, reply_text="Reply"): +async def telegram_to_matrix(evt, source, main_intent=None, is_edit=False): text = add_surrogates(evt.message) html = _telegram_entities_to_matrix_catch(text, evt.entities) if evt.entities else None relates_to = {} @@ -121,8 +129,8 @@ async def telegram_to_matrix(evt, source, native_replies=False, message_link_in_ text, html = await _add_forward_header(source, text, html, evt.fwd_from.from_id) if evt.reply_to_msg_id: - text, html = await _add_reply_header(source, text, html, evt, relates_to, native_replies, - message_link_in_reply, main_intent, reply_text) + text, html = await _add_reply_header(source, text, html, evt, relates_to, main_intent, + is_edit) if isinstance(evt, Message) and evt.post and evt.post_author: if not html: diff --git a/mautrix_telegram/formatter/util.py b/mautrix_telegram/formatter/util.py index ff35519d..ec51844c 100644 --- a/mautrix_telegram/formatter/util.py +++ b/mautrix_telegram/formatter/util.py @@ -1,8 +1,9 @@ -# Unicode surrogate handling -# From https://github.com/LonamiWebs/Telethon/blob/master/telethon/extensions/markdown.py import struct +import re +# Unicode surrogate handling from +# https://github.com/LonamiWebs/Telethon/blob/master/telethon/extensions/markdown.py def add_surrogates(text): if text is None: return None @@ -14,3 +15,19 @@ def remove_surrogates(text): if text is None: return None return text.encode("utf-16", "surrogatepass").decode("utf-16") + + +def trim_reply_fallback_text(text): + if not text.startswith("> ") or "\n" not in text: + return text + lines = text.split("\n") + while len(lines) > 0 and lines[0].startswith("> "): + lines.pop(0) + return "\n".join(lines) + + +HTML_REPLY_FALLBACK_REGEX = re.compile(r"^
[\s\S]+?") + + +def trim_reply_fallback_html(html): + return HTML_REPLY_FALLBACK_REGEX.sub("", html) diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py index 25e642e1..4b737f6e 100644 --- a/mautrix_telegram/portal.py +++ b/mautrix_telegram/portal.py @@ -33,6 +33,7 @@ from mautrix_appservice import MatrixRequestError, IntentError from .db import Portal as DBPortal, Message as DBMessage from . import puppet as p, user as u, formatter, util +from .formatter.util import trim_reply_fallback_html, trim_reply_fallback_text mimetypes.init() @@ -575,9 +576,10 @@ class Portal: message["msgtype"] = "m.text" elif not sender.logged_in: if "formatted_body" in message: - message["formatted_body"] = (f"<{sender.displayname}> " - f"{message['formatted_body']}") - message["body"] = f"<{sender.displayname}> {message['body']}" + html = message["formatted_body"] + message["formatted_body"] = f"<{sender.displayname}> {html}" + text = message["body"] + message["body"] = f"<{sender.displayname}> {text}" return type async def _handle_matrix_text(self, client, message, reply_to): @@ -592,7 +594,8 @@ class Portal: if isinstance(entity, InputMessageEntityMentionName): entity.user_id = await client.get_input_entity(entity.user_id.user_id) - return await client.send_message(self.peer, message, entities=entities, reply_to=reply_to) + return await client.send_message(self.peer, message, entities=entities, + reply_to=reply_to) else: message = formatter.matrix_text_to_telegram(message["body"]) return await client.send_message(self.peer, message, reply_to=reply_to) @@ -922,11 +925,7 @@ class Portal: async def handle_telegram_text(self, source, intent, evt): self.log.debug(f"Sending {evt.message} to {self.mxid} by {intent.mxid}") - text, html, relates_to = await formatter.telegram_to_matrix( - evt, source, - config["bridge.native_replies"], - config["bridge.link_in_reply"], - self.main_intent) + text, html, relates_to = await formatter.telegram_to_matrix(evt, source, self.main_intent) await intent.set_typing(self.mxid, is_typing=False) return await intent.send_text(self.mxid, text, html=html, relates_to=relates_to) @@ -950,11 +949,8 @@ class Portal: return evt.reply_to_msg_id = evt.id - text, html, relates_to = await formatter.telegram_to_matrix( - evt, source, - config["bridge.native_replies"], - config["bridge.link_in_reply"], - self.main_intent, reply_text="Edit") + text, html, relates_to = await formatter.telegram_to_matrix(evt, source, self.main_intent, + is_edit=True) intent = sender.intent if sender else self.main_intent await intent.set_typing(self.mxid, is_typing=False) response = await intent.send_text(self.mxid, text, html=html, relates_to=relates_to)