diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py index 9e7cd677..b4c16666 100644 --- a/pyrogram/client/ext/base_client.py +++ b/pyrogram/client/ext/base_client.py @@ -156,3 +156,6 @@ class BaseClient: def get_profile_photos(self, *args, **kwargs): pass + + def edit_message_text(self, *args, **kwargs): + pass diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index 41270d39..fa107fab 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import base64 import struct from base64 import b64decode, b64encode from typing import Union, List @@ -191,3 +192,14 @@ def parse_deleted_messages(client, update) -> List["pyrogram.Message"]: ) return pyrogram.List(parsed_messages) + + +def unpack_inline_message_id(inline_message_id: str) -> types.InputBotInlineMessageID: + r = inline_message_id + "=" * (-len(inline_message_id) % 4) + r = struct.unpack(" "pyrogram.Message": - """Edit captions of messages. + """Edit caption of media messages. Parameters: - chat_id (``int`` | ``str``): + caption (``str``): + New caption of the media message. + + chat_id (``int`` | ``str``, *optional*): + Required if *inline_message_id* is not specified. Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - message_id (``int``): + message_id (``int``, *optional*): + Required if *inline_message_id* is not specified. Message identifier in the chat specified in chat_id. - caption (``str``): - New caption of the message. + inline_message_id (``str``, *optional*): + Required if *chat_id* and *message_id* are not specified. + Identifier of the inline message. parse_mode (``str``, *optional*): Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline - URLs in your caption. Defaults to "markdown". + URLs in your message. Defaults to "markdown". reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is + returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. """ - style = self.html if parse_mode.lower() == "html" else self.markdown - - r = self.send( - functions.messages.EditMessage( - peer=self.resolve_peer(chat_id), - id=message_id, - reply_markup=reply_markup.write() if reply_markup else None, - **style.parse(caption) - ) + return self.edit_message_text( + text=caption, + chat_id=chat_id, + message_id=message_id, + inline_message_id=inline_message_id, + parse_mode=parse_mode, + reply_markup=reply_markup ) - - for i in r.updates: - if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): - return pyrogram.Message._parse( - self, i.message, - {i.id: i for i in r.users}, - {i.id: i for i in r.chats} - ) diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py index 3793c693..2b3ca5d5 100644 --- a/pyrogram/client/methods/messages/edit_message_media.py +++ b/pyrogram/client/methods/messages/edit_message_media.py @@ -32,35 +32,42 @@ from pyrogram.client.types.input_media import InputMedia class EditMessageMedia(BaseClient): def edit_message_media( self, - chat_id: Union[int, str], - message_id: int, media: InputMedia, + chat_id: Union[int, str] = None, + message_id: int = None, + inline_message_id: str = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "pyrogram.Message": - """Edit audio, document, photo, or video messages. + """Edit animation, audio, document, photo or video messages. If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise, message type can be changed arbitrarily. When inline message is edited, new file can't be uploaded. - Use previously uploaded file via its file_id or specify a URL. On success, if the edited message was sent - by the bot, the edited Message is returned, otherwise True is returned. + Use previously uploaded file via its file_id or specify a URL. Parameters: - chat_id (``int`` | ``str``): + media (:obj:`InputMedia`) + One of the InputMedia objects describing an animation, audio, document, photo or video. + + chat_id (``int`` | ``str``, *optional*): + Required if *inline_message_id* is not specified. Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - message_id (``int``): + message_id (``int``, *optional*): + Required if *inline_message_id* is not specified. Message identifier in the chat specified in chat_id. - media (:obj:`InputMedia`) - One of the InputMedia objects describing an animation, audio, document, photo or video. + inline_message_id (``str``, *optional*): + Required if *chat_id* and *message_id* are not specified. + Identifier of the inline message. reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is + returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. @@ -92,8 +99,7 @@ class EditMessageMedia(BaseClient): ) else: media = utils.get_input_media_from_file_id(media.media, 2) - - if isinstance(media, InputMediaVideo): + elif isinstance(media, InputMediaVideo): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( @@ -130,8 +136,7 @@ class EditMessageMedia(BaseClient): ) else: media = utils.get_input_media_from_file_id(media.media, 4) - - if isinstance(media, InputMediaAudio): + elif isinstance(media, InputMediaAudio): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( @@ -167,8 +172,7 @@ class EditMessageMedia(BaseClient): ) else: media = utils.get_input_media_from_file_id(media.media, 9) - - if isinstance(media, InputMediaAnimation): + elif isinstance(media, InputMediaAnimation): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( @@ -206,8 +210,7 @@ class EditMessageMedia(BaseClient): ) else: media = utils.get_input_media_from_file_id(media.media, 10) - - if isinstance(media, InputMediaDocument): + elif isinstance(media, InputMediaDocument): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( @@ -239,12 +242,22 @@ class EditMessageMedia(BaseClient): else: media = utils.get_input_media_from_file_id(media.media, 5) + if inline_message_id is not None: + return self.send( + functions.messages.EditInlineBotMessage( + id=utils.unpack_inline_message_id(inline_message_id), + media=media, + reply_markup=reply_markup.write() if reply_markup else None, + **style.parse(caption) + ) + ) + r = self.send( functions.messages.EditMessage( peer=self.resolve_peer(chat_id), id=message_id, - reply_markup=reply_markup.write() if reply_markup else None, media=media, + reply_markup=reply_markup.write() if reply_markup else None, **style.parse(caption) ) ) diff --git a/pyrogram/client/methods/messages/edit_message_reply_markup.py b/pyrogram/client/methods/messages/edit_message_reply_markup.py index a058646f..516d7b9c 100644 --- a/pyrogram/client/methods/messages/edit_message_reply_markup.py +++ b/pyrogram/client/methods/messages/edit_message_reply_markup.py @@ -20,43 +20,57 @@ from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram.client.ext import BaseClient, utils class EditMessageReplyMarkup(BaseClient): def edit_message_reply_markup( self, - chat_id: Union[int, str], - message_id: int, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + reply_markup: "pyrogram.InlineKeyboardMarkup" = None, + chat_id: Union[int, str] = None, + message_id: int = None, + inline_message_id: str = None ) -> "pyrogram.Message": """Edit only the reply markup of messages sent by the bot or via the bot (for inline bots). Parameters: - chat_id (``int`` | ``str``): + reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + An InlineKeyboardMarkup object. + + chat_id (``int`` | ``str``, *optional*): + Required if *inline_message_id* is not specified. Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - message_id (``int``): + message_id (``int``, *optional*): + Required if *inline_message_id* is not specified. Message identifier in the chat specified in chat_id. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): - An InlineKeyboardMarkup object. + inline_message_id (``str``, *optional*): + Required if *chat_id* and *message_id* are not specified. + Identifier of the inline message. Returns: - :obj:`Message` | ``bool``: In case the edited message is sent by the bot, the edited message is returned, - otherwise, True is returned in case the edited message is send by the user. + :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is + returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. """ + if inline_message_id is not None: + return self.send( + functions.messages.EditInlineBotMessage( + id=utils.unpack_inline_message_id(inline_message_id), + reply_markup=reply_markup.write() if reply_markup else None, + ) + ) r = self.send( functions.messages.EditMessage( peer=self.resolve_peer(chat_id), id=message_id, - reply_markup=reply_markup.write() if reply_markup else None + reply_markup=reply_markup.write() if reply_markup else None, ) ) diff --git a/pyrogram/client/methods/messages/edit_message_text.py b/pyrogram/client/methods/messages/edit_message_text.py index 69283e89..919e5dc1 100644 --- a/pyrogram/client/methods/messages/edit_message_text.py +++ b/pyrogram/client/methods/messages/edit_message_text.py @@ -20,15 +20,16 @@ from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram.client.ext import BaseClient, utils class EditMessageText(BaseClient): def edit_message_text( self, - chat_id: Union[int, str], - message_id: int, text: str, + chat_id: Union[int, str] = None, + message_id: int = None, + inline_message_id: str = None, parse_mode: str = "", disable_web_page_preview: bool = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None @@ -36,16 +37,22 @@ class EditMessageText(BaseClient): """Edit text messages. Parameters: - chat_id (``int`` | ``str``): + text (``str``): + New text of the message. + + chat_id (``int`` | ``str``, *optional*): + Required if *inline_message_id* is not specified. Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - message_id (``int``): + message_id (``int``, *optional*): + Required if *inline_message_id* is not specified. Message identifier in the chat specified in chat_id. - text (``str``): - New text of the message. + inline_message_id (``str``, *optional*): + Required if *chat_id* and *message_id* are not specified. + Identifier of the inline message. parse_mode (``str``, *optional*): Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline @@ -58,13 +65,24 @@ class EditMessageText(BaseClient): An InlineKeyboardMarkup object. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is + returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. """ style = self.html if parse_mode.lower() == "html" else self.markdown + if inline_message_id is not None: + return self.send( + functions.messages.EditInlineBotMessage( + id=utils.unpack_inline_message_id(inline_message_id), + no_webpage=disable_web_page_preview or None, + reply_markup=reply_markup.write() if reply_markup else None, + **style.parse(text) + ) + ) + r = self.send( functions.messages.EditMessage( peer=self.resolve_peer(chat_id),