Merge branch 'telethon-1.17'

This commit is contained in:
Tulir Asokan
2020-10-22 17:42:25 +03:00
6 changed files with 58 additions and 39 deletions
+6 -2
View File
@@ -31,7 +31,7 @@ from telethon.tl.types import (
UpdateEditChannelMessage, UpdateEditMessage, UpdateNewChannelMessage, UpdateReadHistoryOutbox,
UpdateShortChatMessage, UpdateShortMessage, UpdateUserName, UpdateUserPhoto, UpdateUserStatus,
UpdateUserTyping, User, UserStatusOffline, UserStatusOnline, UpdateReadHistoryInbox,
UpdateReadChannelInbox)
UpdateReadChannelInbox, MessageEmpty)
from mautrix.types import UserID, PresenceState
from mautrix.errors import MatrixError
@@ -164,6 +164,7 @@ class AbstractUser(ABC):
request_retries=config["telegram.connection.request_retries"],
connection=connection,
proxy=proxy,
raise_last_call_error=True,
loop=self.loop,
base_logger=base_logger
@@ -387,12 +388,15 @@ class AbstractUser(ABC):
elif isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage,
UpdateEditMessage, UpdateEditChannelMessage)):
update = update.message
if isinstance(update, MessageEmpty):
return update, None, None
if isinstance(update.to_id, PeerUser) and not update.out:
portal = po.Portal.get_by_tgid(update.from_id, peer_type="user",
tg_receiver=self.tgid)
else:
portal = po.Portal.get_by_entity(update.to_id, receiver_id=self.tgid)
sender = pu.Puppet.get(update.from_id) if update.from_id else None
sender = (pu.Puppet.get(TelegramID(update.from_id.user_id))
if isinstance(update.from_id, PeerUser) else None)
else:
self.log.warning("Unexpected message type in User#get_message_details: "
f"{type(update)}")
+18 -16
View File
@@ -22,7 +22,7 @@ from telethon.tl.types import (MessageEntityMention, MessageEntityMentionName, M
MessageEntityEmail, MessageEntityTextUrl, MessageEntityBold,
MessageEntityItalic, MessageEntityCode, MessageEntityPre,
MessageEntityBotCommand, MessageEntityHashtag, MessageEntityCashtag,
MessageEntityPhone, TypeMessageEntity, PeerChannel,
MessageEntityPhone, TypeMessageEntity, PeerChannel, PeerChat,
MessageEntityBlockquote, MessageEntityStrike, MessageFwdHeader,
MessageEntityUnderline, PeerUser)
from telethon.tl.custom import Message
@@ -45,11 +45,11 @@ log: logging.Logger = logging.getLogger("mau.fmt.tg")
def telegram_reply_to_matrix(evt: Message, source: 'AbstractUser') -> Optional[RelatesTo]:
if evt.reply_to_msg_id:
space = (evt.to_id.channel_id
if isinstance(evt, Message) and isinstance(evt.to_id, PeerChannel)
if evt.reply_to:
space = (evt.peer_id.channel_id
if isinstance(evt, Message) and isinstance(evt.peer_id, PeerChannel)
else source.tgid)
msg = DBMessage.get_one_by_tgid(TelegramID(evt.reply_to_msg_id), space)
msg = DBMessage.get_one_by_tgid(TelegramID(evt.reply_to.reply_to_msg_id), space)
if msg:
return RelatesTo(rel_type=RelationType.REFERENCE, event_id=msg.mxid)
return None
@@ -61,15 +61,15 @@ async def _add_forward_header(source: 'AbstractUser', content: TextMessageEventC
content.format = Format.HTML
content.formatted_body = escape(content.body)
fwd_from_html, fwd_from_text = None, None
if fwd_from.from_id:
user = u.User.get_by_tgid(TelegramID(fwd_from.from_id))
if isinstance(fwd_from.from_id, PeerUser):
user = u.User.get_by_tgid(TelegramID(fwd_from.from_id.user_id))
if user:
fwd_from_text = user.displayname or user.mxid
fwd_from_html = (f"<a href='https://matrix.to/#/{user.mxid}'>"
f"{escape(fwd_from_text)}</a>")
if not fwd_from_text:
puppet = pu.Puppet.get(TelegramID(fwd_from.from_id), create=False)
puppet = pu.Puppet.get(TelegramID(fwd_from.from_id.user_id), create=False)
if puppet and puppet.displayname:
fwd_from_text = puppet.displayname or puppet.mxid
fwd_from_html = (f"<a href='https://matrix.to/#/{puppet.mxid}'>"
@@ -77,14 +77,16 @@ async def _add_forward_header(source: 'AbstractUser', content: TextMessageEventC
if not fwd_from_text:
try:
user = await source.client.get_entity(PeerUser(fwd_from.from_id))
user = await source.client.get_entity(fwd_from.from_id)
if user:
fwd_from_text = pu.Puppet.get_displayname(user, False)
fwd_from_html = f"<b>{escape(fwd_from_text)}</b>"
except (ValueError, RPCError):
fwd_from_text = fwd_from_html = "unknown user"
elif fwd_from.channel_id:
portal = po.Portal.get_by_tgid(TelegramID(fwd_from.channel_id))
elif isinstance(fwd_from.from_id, (PeerChannel, PeerChat)):
from_id = (fwd_from.from_id.chat_id if isinstance(fwd_from.from_id, PeerChat)
else fwd_from.from_id.channel_id)
portal = po.Portal.get_by_tgid(TelegramID(from_id))
if portal:
fwd_from_text = portal.title
if portal.alias:
@@ -94,7 +96,7 @@ async def _add_forward_header(source: 'AbstractUser', content: TextMessageEventC
fwd_from_html = f"channel <b>{escape(fwd_from_text)}</b>"
else:
try:
channel = await source.client.get_entity(PeerChannel(fwd_from.channel_id))
channel = await source.client.get_entity(fwd_from.from_id)
if channel:
fwd_from_text = f"channel {channel.title}"
fwd_from_html = f"channel <b>{escape(channel.title)}</b>"
@@ -116,11 +118,11 @@ async def _add_forward_header(source: 'AbstractUser', content: TextMessageEventC
async def _add_reply_header(source: 'AbstractUser', content: TextMessageEventContent, evt: Message,
main_intent: IntentAPI):
space = (evt.to_id.channel_id
if isinstance(evt, Message) and isinstance(evt.to_id, PeerChannel)
space = (evt.peer_id.channel_id
if isinstance(evt, Message) and isinstance(evt.peer_id, PeerChannel)
else source.tgid)
msg = DBMessage.get_one_by_tgid(TelegramID(evt.reply_to_msg_id), space)
msg = DBMessage.get_one_by_tgid(TelegramID(evt.reply_to.reply_to_msg_id), space)
if not msg:
return
@@ -162,7 +164,7 @@ async def telegram_to_matrix(evt: Message, source: "AbstractUser",
if evt.fwd_from:
await _add_forward_header(source, content, evt.fwd_from)
if evt.reply_to_msg_id and not no_reply_fallback:
if evt.reply_to and not no_reply_fallback:
await _add_reply_header(source, content, evt, main_intent)
if isinstance(evt, Message) and evt.post and evt.post_author:
+22 -10
View File
@@ -87,9 +87,9 @@ class PortalMatrix(BasePortal, ABC):
message = await self._get_state_change_message(event, user, **kwargs)
if not message:
return
response = await self.bot.client.send_message(
self.peer, message,
parse_mode=self._matrix_event_to_entities)
message, entities = formatter.matrix_to_telegram(message)
response = await self.bot.client.send_message(self.peer, message,
formatting_entities=entities)
space = self.tgid if self.peer_type == "channel" else self.bot.tgid
self.dedup.check(response, (event_id, space))
@@ -231,18 +231,22 @@ class PortalMatrix(BasePortal, ABC):
async def _handle_matrix_text(self, sender_id: TelegramID, event_id: EventID,
space: TelegramID, client: 'MautrixTelegramClient',
content: TextMessageEventContent, reply_to: TelegramID) -> None:
if content.formatted_body and content.format == Format.HTML:
message, entities = formatter.matrix_to_telegram(content.formatted_body)
else:
message, entities = formatter.matrix_text_to_telegram(content.body)
async with self.send_lock(sender_id):
lp = self.get_config("telegram_link_preview")
if content.get_edit():
orig_msg = DBMessage.get_by_mxid(content.get_edit(), self.mxid, space)
if orig_msg:
response = await client.edit_message(self.peer, orig_msg.tgid, content,
parse_mode=self._matrix_event_to_entities,
response = await client.edit_message(self.peer, orig_msg.tgid, message,
formatting_entities=entities,
link_preview=lp)
self._add_telegram_message_to_db(event_id, space, -1, response)
return
response = await client.send_message(self.peer, content, reply_to=reply_to,
parse_mode=self._matrix_event_to_entities,
response = await client.send_message(self.peer, message, reply_to=reply_to,
formatting_entities=entities,
link_preview=lp)
self._add_telegram_message_to_db(event_id, space, 0, response)
await self._send_delivery_receipt(event_id)
@@ -297,7 +301,13 @@ class PortalMatrix(BasePortal, ABC):
media = InputMediaUploadedDocument(file=file_handle, attributes=attributes,
mime_type=mime or "application/octet-stream")
caption, entities = self._matrix_event_to_entities(caption) if caption else (None, None)
if caption:
if caption.formatted_body and caption.format == Format.HTML:
caption, entities = formatter.matrix_to_telegram(caption.formatted_body)
else:
caption, entities = formatter.matrix_text_to_telegram(content.body)
else:
caption, entities = None, None
async with self.send_lock(sender_id):
if await self._matrix_document_edit(client, content, space, caption, media, event_id):
@@ -336,7 +346,7 @@ class PortalMatrix(BasePortal, ABC):
except (KeyError, ValueError):
self.log.exception("Failed to parse location")
return None
caption, entities = self._matrix_event_to_entities(content)
caption, entities = formatter.matrix_text_to_telegram(content.body)
media = MessageMediaGeo(geo=GeoPoint(lat, long, access_hash=0))
async with self.send_lock(sender_id):
@@ -372,7 +382,8 @@ class PortalMatrix(BasePortal, ABC):
await self._handle_matrix_message(sender, content, event_id)
except RPCError as e:
if config["bridge.delivery_error_reports"]:
await self._send_bridge_error(f"\u26a0 Your message may not have been bridged: {e}")
await self._send_bridge_error(
f"\u26a0 Your message may not have been bridged: {e}")
raise
async def _handle_matrix_message(self, sender: 'u.User', content: MessageEventContent,
@@ -586,6 +597,7 @@ class PortalMatrix(BasePortal, ABC):
self.log.warning(f"Failed to set room name", exc_info=True)
return ok
def init(context: Context) -> None:
global config
config = context.config
+1 -1
View File
@@ -29,7 +29,7 @@ from telethon.tl.types import (
ChatParticipantCreator, ChannelParticipantCreator, UserProfilePhoto, UserProfilePhotoEmpty)
from mautrix.errors import MForbidden
from mautrix.types import (RoomID, UserID, RoomCreatePreset, EventType, Membership, Member,
from mautrix.types import (RoomID, UserID, RoomCreatePreset, EventType, Membership,
PowerLevelStateEventContent, RoomTopicStateEventContent,
RoomNameStateEventContent, RoomAvatarStateEventContent,
StateEventContent, EventID)
+9 -8
View File
@@ -99,8 +99,7 @@ class PortalTelegram(BasePortal, ABC):
encrypt=self.encrypted)
if not file:
return None
if self.get_config("inline_images") and (evt.message
or evt.fwd_from or evt.reply_to_msg_id):
if self.get_config("inline_images") and (evt.message or evt.fwd_from or evt.reply_to):
content = await formatter.telegram_to_matrix(
evt, source, self.main_intent,
prefix_html=f"<img src='{file.mxc}' alt='Inline Telegram photo'/><br/>",
@@ -439,12 +438,12 @@ class PortalTelegram(BasePortal, ABC):
"max_file_size": min(config["bridge.max_document_size"], 2000) * 1024 * 1024
}
async def backfill(self, source: 'AbstractUser', is_initial: bool = False,
async def backfill(self, source: 'u.User', is_initial: bool = False,
limit: Optional[int] = None, last_id: Optional[int] = None) -> None:
async with self.backfill_method_lock:
await self._locked_backfill(source, is_initial, limit, last_id)
async def _locked_backfill(self, source: 'AbstractUser', is_initial: bool = False,
async def _locked_backfill(self, source: 'u.User', is_initial: bool = False,
limit: Optional[int] = None, last_id: Optional[int] = None) -> None:
limit = limit or (config["bridge.backfill.initial_limit"] if is_initial
else config["bridge.backfill.missed_limit"])
@@ -481,7 +480,7 @@ class PortalTelegram(BasePortal, ABC):
with self.backfill_lock:
await self._backfill(source, min_id, limit)
async def _backfill(self, source: 'AbstractUser', min_id: Optional[int], limit: int) -> None:
async def _backfill(self, source: 'u.User', min_id: Optional[int], limit: int) -> None:
self.backfill_leave = set()
if ((self.peer_type == "user" and self.tgid != source.tgid
and config["bridge.backfill.invite_own_puppet"])):
@@ -514,7 +513,8 @@ class PortalTelegram(BasePortal, ABC):
self.log.debug(f"Iterating all messages starting with {min_id} (approx: {limit})")
messages = client.iter_messages(entity, reverse=True, min_id=min_id)
async for message in messages:
sender = p.Puppet.get(message.from_id) if message.from_id else None
sender = (p.Puppet.get(message.from_id.user_id)
if isinstance(message.from_id, PeerUser) else None)
# TODO handle service messages?
await self.handle_telegram_message(source, sender, message)
count += 1
@@ -522,7 +522,8 @@ class PortalTelegram(BasePortal, ABC):
self.log.debug(f"Fetching up to {limit} most recent messages")
messages = await client.get_messages(entity, limit=limit)
for message in reversed(messages):
sender = p.Puppet.get(message.from_id) if message.from_id else None
sender = (p.Puppet.get(TelegramID(message.from_id.user_id))
if isinstance(message.from_id, PeerUser) else None)
await self.handle_telegram_message(source, sender, message)
count += 1
return count
@@ -533,7 +534,7 @@ class PortalTelegram(BasePortal, ABC):
self.log.trace("Got telegram message %d, but no room exists, creating...", evt.id)
await self.create_matrix_room(source, invites=[source.mxid], update_if_exists=False)
if (self.peer_type == "user" and sender.tgid == self.tg_receiver
if (self.peer_type == "user" and sender and sender.tgid == self.tg_receiver
and not sender.is_real_user and not await self.az.state_store.is_joined(self.mxid,
sender.mxid)):
self.log.debug(f"Ignoring private chat message {evt.id}@{source.tgid} as receiver does"
+2 -2
View File
@@ -5,6 +5,6 @@ python-magic>=0.4,<0.5
commonmark>=0.8,<0.10
aiohttp>=3,<3.7
yarl<1.6
mautrix==0.8.0.beta7
telethon>=1.16,<1.17
mautrix==0.8.0.beta9
telethon>=1.17,<1.18
telethon-session-sqlalchemy>=0.2.14,<0.3