From ecc90caba2749e6f558de3c1badb0209f291f91f Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 24 Apr 2022 11:56:07 +0200 Subject: [PATCH] Handle edited messages using a separate handler --- docs/source/api/decorators.rst | 2 + docs/source/api/handlers.rst | 2 + pyrogram/dispatcher.py | 110 ++++++++++-------- pyrogram/filters.py | 10 -- pyrogram/handlers/__init__.py | 1 + pyrogram/handlers/edited_message_handler.py | 49 ++++++++ pyrogram/handlers/message_handler.py | 4 +- pyrogram/methods/decorators/__init__.py | 2 + .../methods/decorators/on_edited_message.py | 61 ++++++++++ pyrogram/methods/decorators/on_message.py | 2 +- 10 files changed, 184 insertions(+), 59 deletions(-) create mode 100644 pyrogram/handlers/edited_message_handler.py create mode 100644 pyrogram/methods/decorators/on_edited_message.py diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index 130f15ce..2e7a04f2 100644 --- a/docs/source/api/decorators.rst +++ b/docs/source/api/decorators.rst @@ -36,6 +36,7 @@ Index :columns: 3 - :meth:`~Client.on_message` + - :meth:`~Client.on_edited_message` - :meth:`~Client.on_callback_query` - :meth:`~Client.on_inline_query` - :meth:`~Client.on_chosen_inline_result` @@ -54,6 +55,7 @@ Details .. Decorators .. autodecorator:: pyrogram.Client.on_message() +.. autodecorator:: pyrogram.Client.on_edited_message() .. autodecorator:: pyrogram.Client.on_callback_query() .. autodecorator:: pyrogram.Client.on_inline_query() .. autodecorator:: pyrogram.Client.on_chosen_inline_result() diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst index 96941429..8a8ac714 100644 --- a/docs/source/api/handlers.rst +++ b/docs/source/api/handlers.rst @@ -36,6 +36,7 @@ Index :columns: 3 - :class:`MessageHandler` + - :class:`EditedMessageHandler` - :class:`DeletedMessagesHandler` - :class:`CallbackQueryHandler` - :class:`InlineQueryHandler` @@ -53,6 +54,7 @@ Details .. Handlers .. autoclass:: MessageHandler() +.. autoclass:: EditedMessageHandler() .. autoclass:: DeletedMessagesHandler() .. autoclass:: CallbackQueryHandler() .. autoclass:: InlineQueryHandler() diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index 0c425f4d..b0ad87f7 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -24,7 +24,7 @@ from collections import OrderedDict import pyrogram from pyrogram import utils from pyrogram.handlers import ( - CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, + CallbackQueryHandler, MessageHandler, EditedMessageHandler, DeletedMessagesHandler, UserStatusHandler, RawUpdateHandler, InlineQueryHandler, PollHandler, ChosenInlineResultHandler, ChatMemberUpdatedHandler, ChatJoinRequestHandler ) @@ -42,33 +42,16 @@ log = logging.getLogger(__name__) class Dispatcher: - NEW_MESSAGE_UPDATES = ( - UpdateNewMessage, - UpdateNewChannelMessage, - UpdateNewScheduledMessage - ) - - EDIT_MESSAGE_UPDATES = ( - UpdateEditMessage, - UpdateEditChannelMessage, - ) - - DELETE_MESSAGES_UPDATES = ( - UpdateDeleteMessages, - UpdateDeleteChannelMessages - ) - - CALLBACK_QUERY_UPDATES = ( - UpdateBotCallbackQuery, - UpdateInlineBotCallbackQuery - ) - - CHAT_MEMBER_UPDATES = ( - UpdateChatParticipant, - UpdateChannelParticipant - ) - - MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES + NEW_MESSAGE_UPDATES = (UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage) + EDIT_MESSAGE_UPDATES = (UpdateEditMessage, UpdateEditChannelMessage) + DELETE_MESSAGES_UPDATES = (UpdateDeleteMessages, UpdateDeleteChannelMessages) + CALLBACK_QUERY_UPDATES = (UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery) + CHAT_MEMBER_UPDATES = (UpdateChatParticipant, UpdateChannelParticipant) + USER_STATUS_UPDATES = (UpdateUserStatus,) + BOT_INLINE_QUERY_UPDATES = (UpdateBotInlineQuery,) + POLL_UPDATES = (UpdateMessagePoll,) + CHOSEN_INLINE_RESULT_UPDATES = (UpdateBotInlineSend,) + CHAT_JOIN_REQUEST_UPDATES = (UpdateBotChatInviteRequester,) def __init__(self, client: "pyrogram.Client"): self.client = client @@ -81,45 +64,80 @@ class Dispatcher: self.groups = OrderedDict() async def message_parser(update, users, chats): - return await pyrogram.types.Message._parse( - self.client, update.message, users, chats, - isinstance(update, UpdateNewScheduledMessage) - ), MessageHandler + return ( + await pyrogram.types.Message._parse(self.client, update.message, users, chats, + isinstance(update, UpdateNewScheduledMessage)), + MessageHandler + ) + + async def edited_message_parser(update, users, chats): + # Edited messages are parsed the same way as new messages, but the handler is different + parsed, _ = await message_parser(update, users, chats) + + return ( + parsed, + EditedMessageHandler + ) async def deleted_messages_parser(update, users, chats): - return utils.parse_deleted_messages(self.client, update), DeletedMessagesHandler + return ( + utils.parse_deleted_messages(self.client, update), + DeletedMessagesHandler + ) async def callback_query_parser(update, users, chats): - return await pyrogram.types.CallbackQuery._parse(self.client, update, users), CallbackQueryHandler + return ( + await pyrogram.types.CallbackQuery._parse(self.client, update, users), + CallbackQueryHandler + ) async def user_status_parser(update, users, chats): - return pyrogram.types.User._parse_user_status(self.client, update), UserStatusHandler + return ( + pyrogram.types.User._parse_user_status(self.client, update), + UserStatusHandler + ) async def inline_query_parser(update, users, chats): - return pyrogram.types.InlineQuery._parse(self.client, update, users), InlineQueryHandler + return ( + pyrogram.types.InlineQuery._parse(self.client, update, users), + InlineQueryHandler + ) async def poll_parser(update, users, chats): - return pyrogram.types.Poll._parse_update(self.client, update), PollHandler + return ( + pyrogram.types.Poll._parse_update(self.client, update), + PollHandler + ) async def chosen_inline_result_parser(update, users, chats): - return pyrogram.types.ChosenInlineResult._parse(self.client, update, users), ChosenInlineResultHandler + return ( + pyrogram.types.ChosenInlineResult._parse(self.client, update, users), + ChosenInlineResultHandler + ) async def chat_member_updated_parser(update, users, chats): - return pyrogram.types.ChatMemberUpdated._parse(self.client, update, users, chats), ChatMemberUpdatedHandler + return ( + pyrogram.types.ChatMemberUpdated._parse(self.client, update, users, chats), + ChatMemberUpdatedHandler + ) async def chat_join_request_parser(update, users, chats): - return pyrogram.types.ChatJoinRequest._parse(self.client, update, users, chats), ChatJoinRequestHandler + return ( + pyrogram.types.ChatJoinRequest._parse(self.client, update, users, chats), + ChatJoinRequestHandler + ) self.update_parsers = { - Dispatcher.MESSAGE_UPDATES: message_parser, + Dispatcher.NEW_MESSAGE_UPDATES: message_parser, + Dispatcher.EDIT_MESSAGE_UPDATES: edited_message_parser, Dispatcher.DELETE_MESSAGES_UPDATES: deleted_messages_parser, Dispatcher.CALLBACK_QUERY_UPDATES: callback_query_parser, - (UpdateUserStatus,): user_status_parser, - (UpdateBotInlineQuery,): inline_query_parser, - (UpdateMessagePoll,): poll_parser, - (UpdateBotInlineSend,): chosen_inline_result_parser, + Dispatcher.USER_STATUS_UPDATES: user_status_parser, + Dispatcher.BOT_INLINE_QUERY_UPDATES: inline_query_parser, + Dispatcher.POLL_UPDATES: poll_parser, + Dispatcher.CHOSEN_INLINE_RESULT_UPDATES: chosen_inline_result_parser, Dispatcher.CHAT_MEMBER_UPDATES: chat_member_updated_parser, - (UpdateBotChatInviteRequester,): chat_join_request_parser + Dispatcher.CHAT_JOIN_REQUEST_UPDATES: chat_join_request_parser } self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple} diff --git a/pyrogram/filters.py b/pyrogram/filters.py index 348e6e7a..078ed4fa 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -250,16 +250,6 @@ caption = create(caption_filter) # endregion -# region edited_filter -async def edited_filter(_, __, m: Message): - return bool(m.edit_date) - - -edited = create(edited_filter) -"""Filter edited messages.""" - - -# endregion # region audio_filter async def audio_filter(_, __, m: Message): diff --git a/pyrogram/handlers/__init__.py b/pyrogram/handlers/__init__.py index 2b7ef0a2..1c762958 100644 --- a/pyrogram/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -22,6 +22,7 @@ from .chat_member_updated_handler import ChatMemberUpdatedHandler from .chosen_inline_result_handler import ChosenInlineResultHandler from .deleted_messages_handler import DeletedMessagesHandler from .disconnect_handler import DisconnectHandler +from .edited_message_handler import EditedMessageHandler from .inline_query_handler import InlineQueryHandler from .message_handler import MessageHandler from .poll_handler import PollHandler diff --git a/pyrogram/handlers/edited_message_handler.py b/pyrogram/handlers/edited_message_handler.py new file mode 100644 index 00000000..78deaf0f --- /dev/null +++ b/pyrogram/handlers/edited_message_handler.py @@ -0,0 +1,49 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Callable + +from .handler import Handler + + +class EditedMessageHandler(Handler): + """The EditedMessage handler class. Used to handle edited messages. + It is intended to be used with :meth:`~pyrogram.Client.add_handler` + + For a nicer way to register this handler, have a look at the + :meth:`~pyrogram.Client.on_edited_message` decorator. + + Parameters: + callback (``Callable``): + Pass a function that will be called when a new edited message arrives. It takes *(client, message)* + as positional arguments (look at the section below for a detailed description). + + filters (:obj:`Filters`): + Pass one or more filters to allow only a subset of messages to be passed + in your callback function. + + Other parameters: + client (:obj:`~pyrogram.Client`): + The Client itself, useful when you want to call other API methods inside the message handler. + + edited_message (:obj:`~pyrogram.types.Message`): + The received edited message. + """ + + def __init__(self, callback: Callable, filters=None): + super().__init__(callback, filters) diff --git a/pyrogram/handlers/message_handler.py b/pyrogram/handlers/message_handler.py index 63a334fc..f5a35b55 100644 --- a/pyrogram/handlers/message_handler.py +++ b/pyrogram/handlers/message_handler.py @@ -22,8 +22,8 @@ from .handler import Handler class MessageHandler(Handler): - """The Message handler class. Used to handle text, media and service messages coming from - any chat (private, group, channel). It is intended to be used with :meth:`~pyrogram.Client.add_handler` + """The Message handler class. Used to handle new messages. + It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the :meth:`~pyrogram.Client.on_message` decorator. diff --git a/pyrogram/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py index da0ed9ab..1fc61185 100644 --- a/pyrogram/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -22,6 +22,7 @@ from .on_chat_member_updated import OnChatMemberUpdated from .on_chosen_inline_result import OnChosenInlineResult from .on_deleted_messages import OnDeletedMessages from .on_disconnect import OnDisconnect +from .on_edited_message import OnEditedMessage from .on_inline_query import OnInlineQuery from .on_message import OnMessage from .on_poll import OnPoll @@ -31,6 +32,7 @@ from .on_user_status import OnUserStatus class Decorators( OnMessage, + OnEditedMessage, OnDeletedMessages, OnCallbackQuery, OnRawUpdate, diff --git a/pyrogram/methods/decorators/on_edited_message.py b/pyrogram/methods/decorators/on_edited_message.py new file mode 100644 index 00000000..02ebdec3 --- /dev/null +++ b/pyrogram/methods/decorators/on_edited_message.py @@ -0,0 +1,61 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Callable + +import pyrogram +from pyrogram.filters import Filter + + +class OnEditedMessage: + def on_edited_message( + self=None, + filters=None, + group: int = 0 + ) -> Callable: + """Decorator for handling edited messages. + + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.EditedMessageHandler`. + + Parameters: + filters (:obj:`~pyrogram.filters`, *optional*): + Pass one or more filters to allow only a subset of messages to be passed + in your function. + + group (``int``, *optional*): + The group identifier, defaults to 0. + """ + + def decorator(func: Callable) -> Callable: + if isinstance(self, pyrogram.Client): + self.add_handler(pyrogram.handlers.EditedMessageHandler(func, filters), group) + elif isinstance(self, Filter) or self is None: + if not hasattr(func, "handlers"): + func.handlers = [] + + func.handlers.append( + ( + pyrogram.handlers.MessageHandler(func, self), + group if filters is None else filters + ) + ) + + return func + + return decorator diff --git a/pyrogram/methods/decorators/on_message.py b/pyrogram/methods/decorators/on_message.py index e9a3dfdd..220c12bb 100644 --- a/pyrogram/methods/decorators/on_message.py +++ b/pyrogram/methods/decorators/on_message.py @@ -28,7 +28,7 @@ class OnMessage: filters=None, group: int = 0 ) -> Callable: - """Decorator for handling messages. + """Decorator for handling new messages. This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.handlers.MessageHandler`.