diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index ef650b3e..38f45d40 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -89,10 +89,11 @@ from .tl.types import ( MessageMediaWebPage, ChannelParticipantsSearch, PhotoSize, PhotoCachedSize, PhotoSizeEmpty, MessageService, ChatParticipants, User, WebPage, ChannelParticipantsBanned, ChannelParticipantsKicked, - InputMessagesFilterEmpty + InputMessagesFilterEmpty, UpdatesCombined ) from .tl.types.messages import DialogsSlice from .tl.types.account import PasswordInputSettings, NoPassword +from .tl import custom from .extensions import markdown, html __log__ = logging.getLogger(__name__) @@ -599,9 +600,10 @@ class TelegramClient(TelegramBareClient): if _total: _total[0] = getattr(r, 'count', len(r.dialogs)) - messages = {m.id: m for m in r.messages} entities = {utils.get_peer_id(x): x for x in itertools.chain(r.users, r.chats)} + messages = {m.id: custom.Message(self, m, entities, None) + for m in r.messages} # Happens when there are pinned dialogs if len(r.dialogs) > limit: @@ -652,8 +654,7 @@ class TelegramClient(TelegramBareClient): """ return list(self.iter_drafts()) - @staticmethod - def _get_response_message(request, result): + def _get_response_message(self, request, result, input_chat): """ Extracts the response message known a request and Update result. The request may also be the ID of the message to match. @@ -672,26 +673,36 @@ class TelegramClient(TelegramBareClient): if isinstance(result, UpdateShort): updates = [result.update] - elif isinstance(result, Updates): + entities = {} + elif isinstance(result, (Updates, UpdatesCombined)): updates = result.updates + entities = {utils.get_peer_id(x): x + for x in itertools.chain(result.users, result.chats)} else: return + found = None for update in updates: if isinstance(update, (UpdateNewChannelMessage, UpdateNewMessage)): if update.message.id == msg_id: - return update.message + found = update.message + break elif (isinstance(update, UpdateEditMessage) and not isinstance(request.peer, InputPeerChannel)): if request.id == update.message.id: - return update.message + found = update.message + break elif (isinstance(update, UpdateEditChannelMessage) and utils.get_peer_id(request.peer) == utils.get_peer_id(update.message.to_id)): if request.id == update.message.id: - return update.message + found = update.message + break + + if found: + return custom.Message(self, found, entities, input_chat) def _parse_message_text(self, message, parse_mode): """ @@ -839,17 +850,18 @@ class TelegramClient(TelegramBareClient): result = self(request) if isinstance(result, UpdateShortSentMessage): - return Message( + to_id, cls = utils.resolve_id(utils.get_peer_id(entity)) + return custom.Message(self, Message( id=result.id, - to_id=entity, + to_id=cls(to_id), message=message, date=result.date, out=result.out, media=result.media, entities=result.entities - ) + ), {}, input_chat=entity) - return self._get_response_message(request, result) + return self._get_response_message(request, result, entity) def forward_messages(self, entity, messages, from_peer=None): """ @@ -895,13 +907,20 @@ class TelegramClient(TelegramBareClient): to_peer=entity ) result = self(req) + if isinstance(result, (Updates, UpdatesCombined)): + entities = {utils.get_peer_id(x): x + for x in itertools.chain(result.users, result.chats)} + else: + entities = {} + random_to_id = {} id_to_message = {} for update in result.updates: if isinstance(update, UpdateMessageID): random_to_id[update.random_id] = update.id elif isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage)): - id_to_message[update.message.id] = update.message + id_to_message[update.message.id] = custom.Message( + self, update.message, entities, input_chat=entity) result = [id_to_message[random_to_id[rnd]] for rnd in req.random_id] return result[0] if single else result @@ -962,16 +981,16 @@ class TelegramClient(TelegramBareClient): message = entity entity = entity.to_id + entity = self.get_input_entity(entity) text, msg_entities = self._parse_message_text(text, parse_mode) request = EditMessageRequest( - peer=self.get_input_entity(entity), + peer=entity, id=self._get_message_id(message), message=text, no_webpage=not link_preview, entities=msg_entities ) - result = self(request) - return self._get_response_message(request, result) + return self._get_response_message(request, self(request), entity) def delete_messages(self, entity, message_ids, revoke=True): """ @@ -1189,8 +1208,7 @@ class TelegramClient(TelegramBareClient): # IDs are returned in descending order. last_id = message.id - self._make_message_friendly(message, entities) - yield message + yield custom.Message(self, message, entities, entity) have += 1 if len(r.messages) < request.limit: @@ -1204,34 +1222,6 @@ class TelegramClient(TelegramBareClient): time.sleep(max(wait_time - (time.time() - start), 0)) - @staticmethod - def _make_message_friendly(message, entities): - """ - Add a few extra attributes to the :tl:`Message` to be friendlier. - - To make messages more friendly, always add message - to service messages, and action to normal messages. - """ - # TODO Create an actual friendlier class - message.message = getattr(message, 'message', None) - message.action = getattr(message, 'action', None) - message.to = entities[utils.get_peer_id(message.to_id)] - message.sender = ( - None if not message.from_id else - entities[utils.get_peer_id(message.from_id)] - ) - if getattr(message, 'fwd_from', None): - message.fwd_from.sender = ( - None if not message.fwd_from.from_id else - entities[utils.get_peer_id(message.fwd_from.from_id)] - ) - message.fwd_from.channel = ( - None if not message.fwd_from.channel_id else - entities[utils.get_peer_id( - PeerChannel(message.fwd_from.channel_id) - )] - ) - def _iter_ids(self, entity, ids, total): """ Special case for `iter_messages` when it should only fetch some IDs. @@ -1253,8 +1243,7 @@ class TelegramClient(TelegramBareClient): if isinstance(message, MessageEmpty): yield None else: - self._make_message_friendly(message, entities) - yield message + yield custom.Message(self, message, entities, entity) def get_messages(self, *args, **kwargs): """ @@ -1355,6 +1344,9 @@ class TelegramClient(TelegramBareClient): if isinstance(message, int): return message + if isinstance(message, custom.Message): + return message.original_message.id + try: if message.SUBCLASS_OF_ID == 0x790009e3: # hex(crc32(b'Message')) = 0x790009e3 @@ -1676,7 +1668,8 @@ class TelegramClient(TelegramBareClient): reply_to_msg_id=reply_to, message=caption, entities=msg_entities) - return self._get_response_message(request, self(request)) + return self._get_response_message(request, self(request), + entity) as_image = utils.is_image(file) and not force_document use_cache = InputPhoto if as_image else InputDocument @@ -1774,7 +1767,7 @@ class TelegramClient(TelegramBareClient): # send the media message to the desired entity. request = SendMediaRequest(entity, media, reply_to_msg_id=reply_to, message=caption, entities=msg_entities) - msg = self._get_response_message(request, self(request)) + msg = self._get_response_message(request, self(request), entity) if msg and isinstance(file_handle, InputSizedFile): # There was a response message and we didn't use cached # version, so cache whatever we just sent to the database. @@ -1840,7 +1833,7 @@ class TelegramClient(TelegramBareClient): entity, reply_to_msg_id=reply_to, multi_media=media )) return [ - self._get_response_message(update.id, result) + self._get_response_message(update.id, result, entity) for update in result.updates if isinstance(update, UpdateMessageID) ]