2
0
mirror of https://github.com/pyrogram/pyrogram synced 2025-08-28 21:07:59 +00:00

Implement editing of messages sent via inline bots

- edit_message_text
- edit_message_caption
- edit_message_media
- edit_message_reply_markup
This commit is contained in:
Dan 2019-06-14 02:12:06 +02:00
parent a2d1752e89
commit 22199b0fe5
6 changed files with 122 additions and 65 deletions

View File

@ -156,3 +156,6 @@ class BaseClient:
def get_profile_photos(self, *args, **kwargs): def get_profile_photos(self, *args, **kwargs):
pass pass
def edit_message_text(self, *args, **kwargs):
pass

View File

@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import base64
import struct import struct
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
from typing import Union, List from typing import Union, List
@ -191,3 +192,14 @@ def parse_deleted_messages(client, update) -> List["pyrogram.Message"]:
) )
return pyrogram.List(parsed_messages) 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("<iqq", base64.b64decode(r, altchars="-_"))
return types.InputBotInlineMessageID(
dc_id=r[0],
id=r[1],
access_hash=r[2]
)

View File

@ -19,61 +19,58 @@
from typing import Union from typing import Union
import pyrogram import pyrogram
from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient
class EditMessageCaption(BaseClient): class EditMessageCaption(BaseClient):
def edit_message_caption( def edit_message_caption(
self, self,
chat_id: Union[int, str],
message_id: int,
caption: str, caption: str,
chat_id: Union[int, str] = None,
message_id: int = None,
inline_message_id: str = None,
parse_mode: str = "", parse_mode: str = "",
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> "pyrogram.Message": ) -> "pyrogram.Message":
"""Edit captions of messages. """Edit caption of media messages.
Parameters: 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. Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self". 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). 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. Message identifier in the chat specified in chat_id.
caption (``str``): inline_message_id (``str``, *optional*):
New caption of the message. Required if *chat_id* and *message_id* are not specified.
Identifier of the inline message.
parse_mode (``str``, *optional*): parse_mode (``str``, *optional*):
Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline 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*): reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
An InlineKeyboardMarkup object. An InlineKeyboardMarkup object.
Returns: 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: Raises:
RPCError: In case of a Telegram RPC error. RPCError: In case of a Telegram RPC error.
""" """
style = self.html if parse_mode.lower() == "html" else self.markdown return self.edit_message_text(
text=caption,
r = self.send( chat_id=chat_id,
functions.messages.EditMessage( message_id=message_id,
peer=self.resolve_peer(chat_id), inline_message_id=inline_message_id,
id=message_id, parse_mode=parse_mode,
reply_markup=reply_markup.write() if reply_markup else None, reply_markup=reply_markup
**style.parse(caption)
)
) )
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}
)

View File

@ -32,35 +32,42 @@ from pyrogram.client.types.input_media import InputMedia
class EditMessageMedia(BaseClient): class EditMessageMedia(BaseClient):
def edit_message_media( def edit_message_media(
self, self,
chat_id: Union[int, str],
message_id: int,
media: InputMedia, media: InputMedia,
chat_id: Union[int, str] = None,
message_id: int = None,
inline_message_id: str = None,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> "pyrogram.Message": ) -> "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, 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. 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 Use previously uploaded file via its file_id or specify a URL.
by the bot, the edited Message is returned, otherwise True is returned.
Parameters: 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. Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self". 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). 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. Message identifier in the chat specified in chat_id.
media (:obj:`InputMedia`) inline_message_id (``str``, *optional*):
One of the InputMedia objects describing an animation, audio, document, photo or video. Required if *chat_id* and *message_id* are not specified.
Identifier of the inline message.
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
An InlineKeyboardMarkup object. An InlineKeyboardMarkup object.
Returns: 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: Raises:
RPCError: In case of a Telegram RPC error. RPCError: In case of a Telegram RPC error.
@ -92,8 +99,7 @@ class EditMessageMedia(BaseClient):
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, 2) media = utils.get_input_media_from_file_id(media.media, 2)
elif isinstance(media, InputMediaVideo):
if isinstance(media, InputMediaVideo):
if os.path.exists(media.media): if os.path.exists(media.media):
media = self.send( media = self.send(
functions.messages.UploadMedia( functions.messages.UploadMedia(
@ -130,8 +136,7 @@ class EditMessageMedia(BaseClient):
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, 4) media = utils.get_input_media_from_file_id(media.media, 4)
elif isinstance(media, InputMediaAudio):
if isinstance(media, InputMediaAudio):
if os.path.exists(media.media): if os.path.exists(media.media):
media = self.send( media = self.send(
functions.messages.UploadMedia( functions.messages.UploadMedia(
@ -167,8 +172,7 @@ class EditMessageMedia(BaseClient):
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, 9) media = utils.get_input_media_from_file_id(media.media, 9)
elif isinstance(media, InputMediaAnimation):
if isinstance(media, InputMediaAnimation):
if os.path.exists(media.media): if os.path.exists(media.media):
media = self.send( media = self.send(
functions.messages.UploadMedia( functions.messages.UploadMedia(
@ -206,8 +210,7 @@ class EditMessageMedia(BaseClient):
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, 10) media = utils.get_input_media_from_file_id(media.media, 10)
elif isinstance(media, InputMediaDocument):
if isinstance(media, InputMediaDocument):
if os.path.exists(media.media): if os.path.exists(media.media):
media = self.send( media = self.send(
functions.messages.UploadMedia( functions.messages.UploadMedia(
@ -239,12 +242,22 @@ class EditMessageMedia(BaseClient):
else: else:
media = utils.get_input_media_from_file_id(media.media, 5) 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( r = self.send(
functions.messages.EditMessage( functions.messages.EditMessage(
peer=self.resolve_peer(chat_id), peer=self.resolve_peer(chat_id),
id=message_id, id=message_id,
reply_markup=reply_markup.write() if reply_markup else None,
media=media, media=media,
reply_markup=reply_markup.write() if reply_markup else None,
**style.parse(caption) **style.parse(caption)
) )
) )

View File

@ -20,43 +20,57 @@ from typing import Union
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient, utils
class EditMessageReplyMarkup(BaseClient): class EditMessageReplyMarkup(BaseClient):
def edit_message_reply_markup( def edit_message_reply_markup(
self, self,
chat_id: Union[int, str], reply_markup: "pyrogram.InlineKeyboardMarkup" = None,
message_id: int, chat_id: Union[int, str] = None,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None message_id: int = None,
inline_message_id: str = None
) -> "pyrogram.Message": ) -> "pyrogram.Message":
"""Edit only the reply markup of messages sent by the bot or via the bot (for inline bots). """Edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
Parameters: 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. Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self". 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). 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. Message identifier in the chat specified in chat_id.
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): inline_message_id (``str``, *optional*):
An InlineKeyboardMarkup object. Required if *chat_id* and *message_id* are not specified.
Identifier of the inline message.
Returns: Returns:
:obj:`Message` | ``bool``: In case the edited message is sent by the bot, the edited message is returned, :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is
otherwise, True is returned in case the edited message is send by the user. returned, otherwise True is returned (message sent via the bot, as inline query result).
Raises: Raises:
RPCError: In case of a Telegram RPC error. 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( r = self.send(
functions.messages.EditMessage( functions.messages.EditMessage(
peer=self.resolve_peer(chat_id), peer=self.resolve_peer(chat_id),
id=message_id, id=message_id,
reply_markup=reply_markup.write() if reply_markup else None reply_markup=reply_markup.write() if reply_markup else None,
) )
) )

View File

@ -20,15 +20,16 @@ from typing import Union
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient, utils
class EditMessageText(BaseClient): class EditMessageText(BaseClient):
def edit_message_text( def edit_message_text(
self, self,
chat_id: Union[int, str],
message_id: int,
text: str, text: str,
chat_id: Union[int, str] = None,
message_id: int = None,
inline_message_id: str = None,
parse_mode: str = "", parse_mode: str = "",
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
@ -36,16 +37,22 @@ class EditMessageText(BaseClient):
"""Edit text messages. """Edit text messages.
Parameters: 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. Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self". 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). 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. Message identifier in the chat specified in chat_id.
text (``str``): inline_message_id (``str``, *optional*):
New text of the message. Required if *chat_id* and *message_id* are not specified.
Identifier of the inline message.
parse_mode (``str``, *optional*): parse_mode (``str``, *optional*):
Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline 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. An InlineKeyboardMarkup object.
Returns: 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: Raises:
RPCError: In case of a Telegram RPC error. RPCError: In case of a Telegram RPC error.
""" """
style = self.html if parse_mode.lower() == "html" else self.markdown 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( r = self.send(
functions.messages.EditMessage( functions.messages.EditMessage(
peer=self.resolve_peer(chat_id), peer=self.resolve_peer(chat_id),