Add Matrix->Telegram location bridging and add user to relaybot files. Fixes #89
This commit is contained in:
@@ -273,7 +273,6 @@ def matrix_to_telegram(html: str) -> Tuple[str, List[TypeMessageEntity]]:
|
|||||||
if should_bridge_plaintext_highlights:
|
if should_bridge_plaintext_highlights:
|
||||||
html = plain_mention_regex.sub(plain_mention_to_html, html)
|
html = plain_mention_regex.sub(plain_mention_to_html, html)
|
||||||
parser.feed(add_surrogates(html))
|
parser.feed(add_surrogates(html))
|
||||||
print([str(e) for e in parser.entities])
|
|
||||||
return remove_surrogates(parser.text.strip()), parser.entities
|
return remove_surrogates(parser.text.strip()), parser.entities
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("Failed to convert Matrix format:\nhtml=%s", html)
|
log.exception("Failed to convert Matrix format:\nhtml=%s", html)
|
||||||
|
|||||||
+63
-24
@@ -516,12 +516,10 @@ class Portal:
|
|||||||
try:
|
try:
|
||||||
current_extension = body[body.rindex("."):]
|
current_extension = body[body.rindex("."):]
|
||||||
if mimetypes.types_map[current_extension] == mime:
|
if mimetypes.types_map[current_extension] == mime:
|
||||||
file_name = body
|
return body
|
||||||
else:
|
|
||||||
file_name = f"matrix_upload{mimetypes.guess_extension(mime)}"
|
|
||||||
except (ValueError, KeyError):
|
except (ValueError, KeyError):
|
||||||
file_name = f"matrix_upload{mimetypes.guess_extension(mime)}"
|
pass
|
||||||
return file_name, None if file_name == body else body
|
return f"matrix_upload{mimetypes.guess_extension(mime)}"
|
||||||
|
|
||||||
async def leave_matrix(self, user, source, event_id):
|
async def leave_matrix(self, user, source, event_id):
|
||||||
if not user.logged_in:
|
if not user.logged_in:
|
||||||
@@ -570,32 +568,53 @@ class Portal:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _preprocess_matrix_message(sender, message):
|
def _preprocess_matrix_message(sender, message):
|
||||||
if message["msgtype"] == "m.emote":
|
msgtype = message["msgtype"]
|
||||||
|
if msgtype == "m.emote":
|
||||||
if "formatted_body" in message:
|
if "formatted_body" in message:
|
||||||
message["formatted_body"] = f"* {sender.displayname} {message['formatted_body']}"
|
message["formatted_body"] = f"* {sender.displayname} {message['formatted_body']}"
|
||||||
message["body"] = f"* {sender.displayname} {message['body']}"
|
message["body"] = f"* {sender.displayname} {message['body']}"
|
||||||
message["msgtype"] = "m.text"
|
message["msgtype"] = "m.text"
|
||||||
elif not sender.logged_in:
|
elif not sender.logged_in:
|
||||||
if "formatted_body" in message:
|
html = message["formatted_body"] if "formatted_body" in message else None
|
||||||
html = message["formatted_body"]
|
|
||||||
message["formatted_body"] = f"<{sender.displayname}> {html}"
|
|
||||||
text = message["body"]
|
text = message["body"]
|
||||||
message["body"] = f"<{sender.displayname}> {text}"
|
if msgtype == "m.text":
|
||||||
return type
|
if html:
|
||||||
|
html = f"<{sender.displayname}> {html}"
|
||||||
|
text = f"<{sender.displayname}> {text}"
|
||||||
|
else:
|
||||||
|
msgtype = msgtype[len("m."):]
|
||||||
|
prefix = {
|
||||||
|
"file": "a ",
|
||||||
|
"image": "an ",
|
||||||
|
"audio": "",
|
||||||
|
"video": "a ",
|
||||||
|
"location": "a ",
|
||||||
|
}.get(msgtype, "")
|
||||||
|
if html:
|
||||||
|
html = f"{sender.displayname} sent {prefix}{msgtype}: {html}"
|
||||||
|
text = ": " + text if text else ""
|
||||||
|
text = f"{sender.displayname} sent {prefix}{msgtype}{text}"
|
||||||
|
if html:
|
||||||
|
message["formatted_body"] = html
|
||||||
|
message["body"] = text
|
||||||
|
|
||||||
|
async def _matrix_event_to_entities(self, client, event):
|
||||||
|
try:
|
||||||
|
if event.get("format", None) == "org.matrix.custom.html":
|
||||||
|
message, entities = formatter.matrix_to_telegram(event["formatted_body"])
|
||||||
|
|
||||||
|
# TODO remove this crap
|
||||||
|
for entity in entities:
|
||||||
|
if isinstance(entity, InputMessageEntityMentionName):
|
||||||
|
entity.user_id = await client.get_input_entity(entity.user_id.user_id)
|
||||||
|
else:
|
||||||
|
message, entities = formatter.matrix_text_to_telegram(event["body"])
|
||||||
|
except KeyError:
|
||||||
|
message, entities = None, None
|
||||||
|
return message, entities
|
||||||
|
|
||||||
async def _handle_matrix_text(self, client, message, reply_to):
|
async def _handle_matrix_text(self, client, message, reply_to):
|
||||||
is_formatted = ("format" in message
|
message, entities = await self._matrix_event_to_entities(client, message)
|
||||||
and message["format"] == "org.matrix.custom.html"
|
|
||||||
and "formatted_body" in message)
|
|
||||||
if is_formatted:
|
|
||||||
message, entities = formatter.matrix_to_telegram(message["formatted_body"])
|
|
||||||
|
|
||||||
# TODO remove this crap
|
|
||||||
for entity in entities:
|
|
||||||
if isinstance(entity, InputMessageEntityMentionName):
|
|
||||||
entity.user_id = await client.get_input_entity(entity.user_id.user_id)
|
|
||||||
else:
|
|
||||||
message, entities = formatter.matrix_text_to_telegram(message["body"])
|
|
||||||
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)
|
||||||
|
|
||||||
async def _handle_matrix_file(self, client, message, reply_to):
|
async def _handle_matrix_file(self, client, message, reply_to):
|
||||||
@@ -604,32 +623,52 @@ class Portal:
|
|||||||
info = message["info"]
|
info = message["info"]
|
||||||
mime = info["mimetype"]
|
mime = info["mimetype"]
|
||||||
|
|
||||||
file_name, caption = self._get_file_meta(message["body"], mime)
|
file_name = self._get_file_meta(message["mxtg_filename"], mime)
|
||||||
|
|
||||||
attributes = [DocumentAttributeFilename(file_name=file_name)]
|
attributes = [DocumentAttributeFilename(file_name=file_name)]
|
||||||
if "w" in info and "h" in info:
|
if "w" in info and "h" in info:
|
||||||
attributes.append(DocumentAttributeImageSize(w=info["w"], h=info["h"]))
|
attributes.append(DocumentAttributeImageSize(w=info["w"], h=info["h"]))
|
||||||
|
|
||||||
|
caption = message["body"] if message["body"] != file_name else None
|
||||||
return await client.send_file(self.peer, file, mime, caption=caption,
|
return await client.send_file(self.peer, file, mime, caption=caption,
|
||||||
attributes=attributes, file_name=file_name,
|
attributes=attributes, file_name=file_name,
|
||||||
reply_to=reply_to)
|
reply_to=reply_to)
|
||||||
|
|
||||||
|
async def _handle_matrix_location(self, client, message, reply_to):
|
||||||
|
try:
|
||||||
|
lat, long = message["geo_uri"][len("geo:"):].split(",")
|
||||||
|
lat, long = float(lat), float(long)
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
self.log.exception("Failed to parse location")
|
||||||
|
return None
|
||||||
|
message, entities = await self._matrix_event_to_entities(client, message)
|
||||||
|
media = MessageMediaGeo(geo=GeoPoint(lat, long))
|
||||||
|
return await client.send_media(self.peer, media, reply_to=reply_to, caption=message,
|
||||||
|
entities=entities)
|
||||||
|
|
||||||
async def handle_matrix_message(self, sender, message, event_id):
|
async def handle_matrix_message(self, sender, message, event_id):
|
||||||
client = sender.client if sender.logged_in else self.bot.client
|
client = sender.client if sender.logged_in else self.bot.client
|
||||||
space = (self.tgid if self.peer_type == "channel" # Channels have their own ID space
|
space = (self.tgid if self.peer_type == "channel" # Channels have their own ID space
|
||||||
else (sender.tgid if sender.logged_in else self.bot.tgid))
|
else (sender.tgid if sender.logged_in else self.bot.tgid))
|
||||||
reply_to = formatter.matrix_reply_to_telegram(message, space, room_id=self.mxid)
|
reply_to = formatter.matrix_reply_to_telegram(message, space, room_id=self.mxid)
|
||||||
|
|
||||||
|
message["mxtg_filename"] = message["body"]
|
||||||
self._preprocess_matrix_message(sender, message)
|
self._preprocess_matrix_message(sender, message)
|
||||||
type = message["msgtype"]
|
type = message["msgtype"]
|
||||||
|
|
||||||
if type == "m.text" or (self.bridge_notices and type == "m.notice"):
|
if type == "m.text" or (self.bridge_notices and type == "m.notice"):
|
||||||
response = await self._handle_matrix_text(client, message, reply_to)
|
response = await self._handle_matrix_text(client, message, reply_to)
|
||||||
|
elif type == "m.location":
|
||||||
|
response = await self._handle_matrix_location(client, message, reply_to)
|
||||||
elif type in ("m.image", "m.file", "m.audio", "m.video"):
|
elif type in ("m.image", "m.file", "m.audio", "m.video"):
|
||||||
response = await self._handle_matrix_file(client, message, reply_to)
|
response = await self._handle_matrix_file(client, message, reply_to)
|
||||||
else:
|
else:
|
||||||
self.log.debug("Unhandled Matrix event: %s", message)
|
self.log.debug("Unhandled Matrix event: %s", message)
|
||||||
|
response = None
|
||||||
|
|
||||||
|
if not response:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.log.debug("Handled Matrix message: %s", response)
|
self.log.debug("Handled Matrix message: %s", response)
|
||||||
self.is_duplicate(response, (event_id, space))
|
self.is_duplicate(response, (event_id, space))
|
||||||
self.db.add(DBMessage(
|
self.db.add(DBMessage(
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ class MautrixTelegramClient(TelegramClient):
|
|||||||
reply_to_msg_id=reply_to)
|
reply_to_msg_id=reply_to)
|
||||||
return self._get_response_message(request, await self(request))
|
return self._get_response_message(request, await self(request))
|
||||||
|
|
||||||
|
async def send_media(self, entity, media, caption=None, entities=None, reply_to=None):
|
||||||
|
request = SendMediaRequest(entity, media, message=caption or "", entities=entities or [],
|
||||||
|
reply_to_msg_id=reply_to)
|
||||||
|
return self._get_response_message(request, await self(request))
|
||||||
|
|
||||||
async def download_file_bytes(self, location):
|
async def download_file_bytes(self, location):
|
||||||
if isinstance(location, Document):
|
if isinstance(location, Document):
|
||||||
location = InputDocumentFileLocation(location.id, location.access_hash,
|
location = InputDocumentFileLocation(location.id, location.access_hash,
|
||||||
|
|||||||
Reference in New Issue
Block a user