diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index acd2fd5a..e87eab49 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -487,6 +487,11 @@ def pyrogram_api(): ForumTopicReopened GeneralTopicHidden GeneralTopicUnhidden + Reaction + ReactionCount + ReactionType + MessageReactionUpdated + MessageReactionCountUpdated """, stories=""" Stories diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index 1dac109c..90a01cbe 100644 --- a/docs/source/api/decorators.rst +++ b/docs/source/api/decorators.rst @@ -38,6 +38,8 @@ Index - :meth:`~Client.on_message` - :meth:`~Client.on_edited_message` - :meth:`~Client.on_callback_query` + - :meth:`~Client.on_message_reaction_updated` + - :meth:`~Client.on_message_reaction_count_updated` - :meth:`~Client.on_inline_query` - :meth:`~Client.on_chosen_inline_result` - :meth:`~Client.on_chat_member_updated` @@ -58,6 +60,8 @@ Details .. autodecorator:: pyrogram.Client.on_message() .. autodecorator:: pyrogram.Client.on_edited_message() .. autodecorator:: pyrogram.Client.on_callback_query() +.. autodecorator:: pyrogram.Client.on_message_reaction_updated() +.. autodecorator:: pyrogram.Client.on_message_reaction_count_updated() .. autodecorator:: pyrogram.Client.on_inline_query() .. autodecorator:: pyrogram.Client.on_chosen_inline_result() .. autodecorator:: pyrogram.Client.on_chat_member_updated() diff --git a/docs/source/api/enums/ReactionType.rst b/docs/source/api/enums/ReactionType.rst new file mode 100644 index 00000000..59692fba --- /dev/null +++ b/docs/source/api/enums/ReactionType.rst @@ -0,0 +1,8 @@ +ReactionType +============ + +.. autoclass:: pyrogram.enums.ReactionType() + :members: + +.. raw:: html + :file: ./cleanup.html diff --git a/docs/source/api/enums/index.rst b/docs/source/api/enums/index.rst index f98e3761..aca1a605 100644 --- a/docs/source/api/enums/index.rst +++ b/docs/source/api/enums/index.rst @@ -28,6 +28,7 @@ to apply only a valid value among the expected ones. SentCodeType NextCodeType UserStatus + ReactionType StoriesPrivacyRules StoryPrivacy @@ -49,5 +50,6 @@ to apply only a valid value among the expected ones. SentCodeType NextCodeType UserStatus + ReactionType StoriesPrivacyRules StoryPrivacy diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst index e1f32507..cfe99bbe 100644 --- a/docs/source/api/handlers.rst +++ b/docs/source/api/handlers.rst @@ -39,6 +39,8 @@ Index - :class:`EditedMessageHandler` - :class:`DeletedMessagesHandler` - :class:`CallbackQueryHandler` + - :class:`MessageReactionUpdatedHandler` + - :class:`MessageReactionCountUpdatedHandler` - :class:`InlineQueryHandler` - :class:`ChosenInlineResultHandler` - :class:`ChatMemberUpdatedHandler` @@ -58,6 +60,8 @@ Details .. autoclass:: EditedMessageHandler() .. autoclass:: DeletedMessagesHandler() .. autoclass:: CallbackQueryHandler() +.. autoclass:: MessageReactionUpdatedHandler() +.. autoclass:: MessageReactionCountUpdatedHandler() .. autoclass:: InlineQueryHandler() .. autoclass:: ChosenInlineResultHandler() .. autoclass:: ChatMemberUpdatedHandler() diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index ea94b2a8..701e5fcb 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -25,9 +25,7 @@ from collections import OrderedDict import pyrogram from pyrogram import utils from pyrogram.handlers import ( - CallbackQueryHandler, MessageHandler, EditedMessageHandler, DeletedMessagesHandler, - UserStatusHandler, RawUpdateHandler, InlineQueryHandler, PollHandler, ConversationHandler, - ChosenInlineResultHandler, ChatMemberUpdatedHandler, ChatJoinRequestHandler, StoryHandler + CallbackQueryHandler, MessageHandler, EditedMessageHandler, DeletedMessagesHandler, MessageReactionUpdatedHandler, MessageReactionCountUpdatedHandler, UserStatusHandler, RawUpdateHandler, InlineQueryHandler, PollHandler, ConversationHandler, ChosenInlineResultHandler, ChatMemberUpdatedHandler, ChatJoinRequestHandler, StoryHandler ) from pyrogram.raw.types import ( UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage, @@ -36,7 +34,9 @@ from pyrogram.raw.types import ( UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery, UpdateUserStatus, UpdateBotInlineQuery, UpdateMessagePoll, UpdateBotInlineSend, UpdateChatParticipant, UpdateChannelParticipant, - UpdateBotChatInviteRequester, UpdateStory + UpdateBotChatInviteRequester, UpdateStory, + UpdateBotMessageReaction, + UpdateBotMessageReactions ) log = logging.getLogger(__name__) @@ -54,6 +54,8 @@ class Dispatcher: CHOSEN_INLINE_RESULT_UPDATES = (UpdateBotInlineSend,) CHAT_JOIN_REQUEST_UPDATES = (UpdateBotChatInviteRequester,) NEW_STORY_UPDATES = (UpdateStory,) + MESSAGE_BOT_NA_REACTION_UPDATES = (UpdateBotMessageReaction,) + MESSAGE_BOT_A_REACTION_UPDATES = (UpdateBotMessageReactions,) def __init__(self, client: "pyrogram.Client"): self.client = client @@ -137,6 +139,18 @@ class Dispatcher: await pyrogram.types.Story._parse(self.client, update.story, update.peer), StoryHandler ) + + async def message_bot_na_reaction_parser(update, users, chats): + return ( + pyrogram.types.MessageReactionUpdated._parse(self.client, update, users, chats), + MessageReactionUpdatedHandler + ) + + async def message_bot_a_reaction_parser(update, users, chats): + return ( + pyrogram.types.MessageReactionCountUpdated._parse(self.client, update, users, chats), + MessageReactionCountUpdatedHandler + ) self.update_parsers = { Dispatcher.NEW_MESSAGE_UPDATES: message_parser, @@ -149,7 +163,9 @@ class Dispatcher: Dispatcher.CHOSEN_INLINE_RESULT_UPDATES: chosen_inline_result_parser, Dispatcher.CHAT_MEMBER_UPDATES: chat_member_updated_parser, Dispatcher.CHAT_JOIN_REQUEST_UPDATES: chat_join_request_parser, - Dispatcher.NEW_STORY_UPDATES: story_parser + Dispatcher.NEW_STORY_UPDATES: story_parser, + Dispatcher.MESSAGE_BOT_NA_REACTION_UPDATES: message_bot_na_reaction_parser, + Dispatcher.MESSAGE_BOT_A_REACTION_UPDATES: message_bot_a_reaction_parser } self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple} diff --git a/pyrogram/enums/__init__.py b/pyrogram/enums/__init__.py index 76b79e9b..15eadf27 100644 --- a/pyrogram/enums/__init__.py +++ b/pyrogram/enums/__init__.py @@ -30,6 +30,7 @@ from .next_code_type import NextCodeType from .parse_mode import ParseMode from .poll_type import PollType from .profile_color import ProfileColor +from .reaction_type import ReactionType from .reply_color import ReplyColor from .sent_code_type import SentCodeType from .stories_privacy_rules import StoriesPrivacyRules @@ -51,6 +52,7 @@ __all__ = [ 'ParseMode', 'PollType', 'ProfileColor', + 'ReactionType', 'ReplyColor', 'SentCodeType', "StoriesPrivacyRules", diff --git a/pyrogram/enums/reaction_type.py b/pyrogram/enums/reaction_type.py new file mode 100644 index 00000000..829de1ec --- /dev/null +++ b/pyrogram/enums/reaction_type.py @@ -0,0 +1,29 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +from enum import auto +from .auto_name import AutoName + + +class ReactionType(AutoName): + """Reaction type enumeration used in :obj:`~pyrogram.types.ReactionType`.""" + EMOJI = auto() + """Emoji reaction type.""" + + CUSTOM_EMOJI = auto() + """Custom emoji reaction type.""" diff --git a/pyrogram/handlers/__init__.py b/pyrogram/handlers/__init__.py index 5a28eeb5..ab918668 100644 --- a/pyrogram/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -31,3 +31,5 @@ from .poll_handler import PollHandler from .raw_update_handler import RawUpdateHandler from .user_status_handler import UserStatusHandler from .story_handler import StoryHandler +from .message_reaction_updated_handler import MessageReactionUpdatedHandler +from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler \ No newline at end of file diff --git a/pyrogram/handlers/message_reaction_count_updated_handler.py b/pyrogram/handlers/message_reaction_count_updated_handler.py new file mode 100644 index 00000000..74ab37a8 --- /dev/null +++ b/pyrogram/handlers/message_reaction_count_updated_handler.py @@ -0,0 +1,51 @@ +# 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 MessageReactionCountUpdatedHandler(Handler): + """The MessageReactionCountUpdated handler class. + Used to handle changes in the anonymous reaction of a message. + + 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_reaction_count_updated` decorator. + + Parameters: + callback (``Callable``): + Pass a function that will be called when a new MessageReactionCountUpdated event arrives. It takes + *(client, message_reaction_count_updated)* 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 updates 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 handler. + + message_reaction_count_updated (:obj:`~pyrogram.types.MessageReactionCountUpdated`): + The received message reaction count update. + """ + + def __init__(self, callback: Callable, filters=None): + super().__init__(callback, filters) \ No newline at end of file diff --git a/pyrogram/handlers/message_reaction_updated_handler.py b/pyrogram/handlers/message_reaction_updated_handler.py new file mode 100644 index 00000000..ea86a6d7 --- /dev/null +++ b/pyrogram/handlers/message_reaction_updated_handler.py @@ -0,0 +1,51 @@ +# 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 MessageReactionUpdatedHandler(Handler): + """The MessageReactionUpdated handler class. + Used to handle changes in the reaction of a message. + + 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_reaction_updated` decorator. + + Parameters: + callback (``Callable``): + Pass a function that will be called when a new MessageReactionUpdated event arrives. It takes + *(client, message_reaction_updated)* 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 updates 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 handler. + + message_reaction_updated (:obj:`~pyrogram.types.MessageReactionUpdated`): + The received message reaction update. + """ + + def __init__(self, callback: Callable, filters=None): + super().__init__(callback, filters) \ No newline at end of file diff --git a/pyrogram/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py index 560a13de..169b1ec3 100644 --- a/pyrogram/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -30,6 +30,8 @@ from .on_poll import OnPoll from .on_raw_update import OnRawUpdate from .on_user_status import OnUserStatus from .on_story import OnStory +from .on_message_reaction_updated import OnMessageReactionUpdated +from .on_message_reaction_count_updated import OnMessageReactionCountUpdated class Decorators( @@ -45,6 +47,8 @@ class Decorators( OnChosenInlineResult, OnChatMemberUpdated, OnChatJoinRequest, - OnStory + OnStory, + OnMessageReactionUpdated, + OnMessageReactionCountUpdated ): pass diff --git a/pyrogram/methods/decorators/on_message_reaction_count_updated.py b/pyrogram/methods/decorators/on_message_reaction_count_updated.py new file mode 100644 index 00000000..37e95a29 --- /dev/null +++ b/pyrogram/methods/decorators/on_message_reaction_count_updated.py @@ -0,0 +1,60 @@ +# 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 OnMessageReactionCountUpdated: + def on_message_reaction_count_updated( + self=None, + filters=None, + group: int = 0 + ) -> Callable: + """Decorator for handling anonymous reaction changes on messages. + + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.MessageReactionCountUpdatedHandler`. + + Parameters: + filters (:obj:`~pyrogram.filters`, *optional*): + Pass one or more filters to allow only a subset of updates 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.MessageReactionCountUpdatedHandler(func, filters), group) + elif isinstance(self, Filter) or self is None: + if not hasattr(func, "handlers"): + func.handlers = [] + + func.handlers.append( + ( + pyrogram.handlers.MessageReactionCountUpdatedHandler(func, self), + group if filters is None else filters + ) + ) + + return func + + return decorator \ No newline at end of file diff --git a/pyrogram/methods/decorators/on_message_reaction_updated.py b/pyrogram/methods/decorators/on_message_reaction_updated.py new file mode 100644 index 00000000..bc27776b --- /dev/null +++ b/pyrogram/methods/decorators/on_message_reaction_updated.py @@ -0,0 +1,60 @@ +# 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 OnMessageReactionUpdated: + def on_message_reaction_updated( + self=None, + filters=None, + group: int = 0 + ) -> Callable: + """Decorator for handling reaction changes on messages. + + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.MessageReactionUpdatedHandler`. + + Parameters: + filters (:obj:`~pyrogram.filters`, *optional*): + Pass one or more filters to allow only a subset of updates 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.MessageReactionUpdatedHandler(func, filters), group) + elif isinstance(self, Filter) or self is None: + if not hasattr(func, "handlers"): + func.handlers = [] + + func.handlers.append( + ( + pyrogram.handlers.MessageReactionUpdatedHandler(func, self), + group if filters is None else filters + ) + ) + + return func + + return decorator \ No newline at end of file diff --git a/pyrogram/methods/messages/send_reaction.py b/pyrogram/methods/messages/send_reaction.py index 180763f2..3045adc3 100644 --- a/pyrogram/methods/messages/send_reaction.py +++ b/pyrogram/methods/messages/send_reaction.py @@ -1,26 +1,26 @@ -# Pyrofork - Telegram MTProto API Client Library for Python +# PyroFork - Telegram MTProto API Client Library for Python # Copyright (C) 2017-present Dan # Copyright (C) 2022-present Mayuri-Chan # -# This file is part of Pyrofork. +# This file is part of PyroFork. # -# Pyrofork is free software: you can redistribute it and/or modify +# PyroFork 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. # -# Pyrofork is distributed in the hope that it will be useful, +# PyroFork 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 Pyrofork. If not, see . +# along with PyroFork. If not, see . from typing import Union, List import pyrogram -from pyrogram import raw +from pyrogram import raw, types class SendReaction: @@ -30,9 +30,14 @@ class SendReaction: message_id: int = None, story_id: int = None, emoji: Union[int, str, List[Union[int, str]]] = None, - big: bool = False - ) -> bool: - """Send a reaction to a message. + big: bool = False, + add_to_recent: bool = False + ) -> "types.MessageReactions": + """Use this method to send reactions on a message/stories. + Service messages can't be reacted to. + Automatically forwarded messages from + a channel to its discussion group have the + same available reactions as messages in the channel. .. include:: /_includes/usable-by/users-bots.rst @@ -42,7 +47,7 @@ class SendReaction: You can also use chat public link in form of *t.me/* (str). message_id (``int``, *optional*): - Identifier of the message. + Identifier of the target message. If the message belongs to a media group, the reaction is set to the first non-deleted message in the group instead. story_id (``int``, *optional*): Identifier of the story. @@ -51,14 +56,18 @@ class SendReaction: Reaction emoji. Pass None as emoji (default) to retract the reaction. Pass list of int or str to react multiple emojis. - + big (``bool``, *optional*): - Pass True to show a bigger and longer reaction. + Pass True to set the reaction with a big animation. + For message reactions only. Defaults to False. - for message reaction only. + + add_to_recent (``bool``, *optional*): + Pass True if the reaction should appear in the recently used reactions. + This option is applicable only for users. Returns: - ``bool``: On success, True is returned. + :obj:`~pyrogram.types.MessageReactions`: On success, True is returned. Example: .. code-block:: python @@ -75,7 +84,7 @@ class SendReaction: await app.send_reaction(chat_id, story_id=story_id) """ if isinstance(emoji, list): - emoji = [ + reaction = [ raw.types.ReactionCustomEmoji(document_id=i) if isinstance(i, int) else raw.types.ReactionEmoji(emoticon=i) @@ -83,26 +92,31 @@ class SendReaction: ] if emoji else None else: if isinstance(emoji, int): - emoji = [raw.types.ReactionCustomEmoji(document_id=emoji)] + reaction = [raw.types.ReactionCustomEmoji(document_id=emoji)] else: - emoji = [raw.types.ReactionEmoji(emoticon=emoji)] if emoji else None + reaction = [raw.types.ReactionEmoji(emoticon=emoji)] if emoji else None if message_id is not None: - await self.invoke( + r = await self.invoke( raw.functions.messages.SendReaction( peer=await self.resolve_peer(chat_id), msg_id=message_id, - reaction=emoji, - big=big + reaction=reaction, + big=big, + add_to_recent=add_to_recent ) ) + for i in r.updates: + if isinstance(i, raw.types.UpdateMessageReactions): + return types.MessageReactions._parse(self, i.reactions) elif story_id is not None: await self.invoke( raw.functions.stories.SendReaction( peer=await self.resolve_peer(chat_id), story_id=story_id, - reaction=raw.types.ReactionEmoji(emoticon=emoji) if emoji else None + reaction=raw.types.ReactionEmoji(emoticon=emoji) if emoji else None, + add_to_recent=add_to_recent ) ) + return True else: - raise ValueError("You need to pass one of message_id/story_id!") - return True + raise ValueError("You need to pass one of message_id!") diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index a5851868..890a3fe5 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -1,20 +1,21 @@ -# Pyrogram - Telegram MTProto API Client Library for Python +# PyroFork - Telegram MTProto API Client Library for Python # Copyright (C) 2017-present Dan +# Copyright (C) 2022-present Mayuri-Chan # -# This file is part of Pyrogram. +# This file is part of PyroFork. # -# Pyrogram is free software: you can redistribute it and/or modify +# PyroFork 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, +# PyroFork 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 . +# along with PyroFork. If not, see . from .animation import Animation from .audio import Audio @@ -35,6 +36,8 @@ from .photo import Photo from .poll import Poll from .poll_option import PollOption from .reaction import Reaction +from .reaction_type import ReactionType +from .reaction_count import ReactionCount from .sticker import Sticker from .stickerset import StickerSet from .stories_privacy_rules import StoriesPrivacyRules @@ -49,6 +52,8 @@ from .web_page import WebPage from .web_page_empty import WebPageEmpty from .web_page_preview import WebPagePreview from .message_reactions import MessageReactions +from .message_reaction_updated import MessageReactionUpdated +from .message_reaction_count_updated import MessageReactionCountUpdated from .message_story import MessageStory from .story import Story from .story_deleted import StoryDeleted @@ -60,5 +65,5 @@ from .exported_story_link import ExportedStoryLink __all__ = [ "Animation", "Audio", "Contact", "Document", "Game", "Giveaway", "GiveawayLaunched", "GiveawayResult", "Location", "MediaArea", "MediaAreaChannelPost", "MediaAreaCoordinates", "Message", "MessageEntity", "Photo", "Thumbnail", "StrippedThumbnail", "Poll", "PollOption", "Sticker", "StickerSet", "Venue", "Video", "VideoNote", "Voice", "WebPage", "WebPageEmpty", "WebPagePreview", "Dice", - "Reaction", "WebAppData", "MessageReactions", "MessageStory", "Story", "StoryDeleted", "StorySkipped", "StoryViews", "StoryForwardHeader", "StoriesPrivacyRules", "ExportedStoryLink" + "Reaction", "WebAppData", "MessageReactions", "ReactionCount", "ReactionType", "MessageReactionUpdated", "MessageReactionCountUpdated", "MessageStory", "Story", "StoryDeleted", "StorySkipped", "StoryViews", "StoryForwardHeader", "StoriesPrivacyRules", "ExportedStoryLink" ] diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index b68e6028..0b6f169b 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -4360,7 +4360,7 @@ class Message(Object, Update): else: await self.reply(button, quote=quote) - async def react(self, emoji: str = "", big: bool = False) -> bool: + async def react(self, emoji: str = "", big: bool = False, add_to_recent: bool = True) -> "types.MessageReactions": """Bound method *react* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -4386,9 +4386,13 @@ class Message(Object, Update): big (``bool``, *optional*): Pass True to show a bigger and longer reaction. Defaults to False. + + add_to_recent (``bool``, *optional*): + Pass True if the reaction should appear in the recently used reactions. + This option is applicable only for users. Returns: - ``bool``: On success, True is returned. + :obj: `~pyrogram.types.MessageReactions`: On success, True is returned. Raises: RPCError: In case of a Telegram RPC error. diff --git a/pyrogram/types/messages_and_media/message_reaction_count_updated.py b/pyrogram/types/messages_and_media/message_reaction_count_updated.py new file mode 100644 index 00000000..3735e677 --- /dev/null +++ b/pyrogram/types/messages_and_media/message_reaction_count_updated.py @@ -0,0 +1,89 @@ +# PyroFork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of PyroFork. +# +# PyroFork 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. +# +# PyroFork 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 PyroFork. If not, see . + +from datetime import datetime +from typing import Dict, List + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object +from ..update import Update + + +class MessageReactionCountUpdated(Object, Update): + """Reactions to a message with anonymous reactions were changed. + + These updates are heavy and their changes may be delayed by a few minutes. + + Parameters: + chat (:obj:`~pyrogram.types.Chat`): + The chat containing the message the user reacted to + + message_id (``int``): + Unique identifier of the message inside the chat + + date (:py:obj:`~datetime.datetime`): + Date of change of the reaction + + reactions (:obj:`~pyrogram.types.ReactionCount`): + List of reactions that are present on the message + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + chat: "types.Chat", + message_id: int, + date: datetime, + reactions: List["types.ReactionCount"] + ): + super().__init__(client) + + self.chat = chat + self.message_id = message_id + self.date = date + self.reactions = reactions + + @staticmethod + def _parse( + client: "pyrogram.Client", + update: "raw.types.UpdateBotMessageReactions", + users: Dict[int, "raw.types.User"], + chats: Dict[int, "raw.types.Chat"] + ) -> "MessageReactionUpdated": + chat = None + peer_id = utils.get_peer_id(update.peer) + raw_peer_id = utils.get_raw_peer_id(update.peer) + if peer_id > 0: + chat = types.Chat._parse_user_chat(client, users[raw_peer_id]) + else: + chat = types.Chat._parse_chat_chat(client, chats[raw_peer_id]) + + return MessageReactionCountUpdated( + client=client, + chat=chat, + message_id=update.msg_id, + date=utils.timestamp_to_datetime(update.date), + reactions=[ + types.ReactionCount._parse( + client, + rt + ) for rt in update.reactions + ] + ) \ No newline at end of file diff --git a/pyrogram/types/messages_and_media/message_reaction_updated.py b/pyrogram/types/messages_and_media/message_reaction_updated.py new file mode 100644 index 00000000..aa4eb387 --- /dev/null +++ b/pyrogram/types/messages_and_media/message_reaction_updated.py @@ -0,0 +1,124 @@ +# PyroFork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of PyroFork. +# +# PyroFork 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. +# +# PyroFork 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 PyroFork. If not, see . + +from datetime import datetime +from typing import Dict, List + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object +from ..update import Update + + +class MessageReactionUpdated(Object, Update): + """This object represents a change of a reaction on a message performed by a user. + A reaction to a message was changed by a user. + The update isn't received for reactions set by bots. + + These updates are heavy and their changes may be delayed by a few minutes. + + Parameters: + id (``int``): + Unique identifier of the message inside the chat + + chat (:obj:`~pyrogram.types.Chat`): + The chat containing the message the user reacted to + + from_user (:obj:`~pyrogram.types.User`, *optional*): + The user that changed the reaction, if the user isn't anonymous + + actor_chat (:obj:`~pyrogram.types.Chat`, *optional*): + The chat on behalf of which the reaction was changed, if the user is anonymous + + date (:py:obj:`~datetime.datetime`): + Date of change of the reaction + + old_reaction (:obj:`~pyrogram.types.ReactionType`): + Previous list of reaction types that were set by the user + + new_reaction (:obj:`~pyrogram.types.ReactionType`): + New list of reaction types that have been set by the user + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + id: int, + from_user: "types.User", + actor_chat: "types.Chat", + date: datetime, + chat: "types.Chat", + old_reaction: List["types.ReactionType"], + new_reaction: List["types.ReactionType"] + ): + super().__init__(client) + + self.id = id + self.from_user = from_user + self.actor_chat = actor_chat + self.date = date + self.chat = chat + self.old_reaction = old_reaction + self.new_reaction = new_reaction + + @staticmethod + def _parse( + client: "pyrogram.Client", + update: "raw.types.UpdateBotMessageReaction", + users: Dict[int, "raw.types.User"], + chats: Dict[int, "raw.types.Chat"] + ) -> "MessageReactionUpdated": + chat = None + peer_id = utils.get_peer_id(update.peer) + raw_peer_id = utils.get_raw_peer_id(update.peer) + if peer_id > 0: + chat = types.Chat._parse_user_chat(client, users[raw_peer_id]) + else: + chat = types.Chat._parse_channel_chat(client, chats[raw_peer_id]) + + from_user = None + actor_chat = None + + raw_actor_peer_id = utils.get_raw_peer_id(update.actor) + actor_peer_id = utils.get_peer_id(update.actor) + + if actor_peer_id > 0: + from_user = types.User._parse(client, users[raw_actor_peer_id]) + else: + actor_chat = types.Chat._parse_channel_chat(client, chats[raw_actor_peer_id]) + + return MessageReactionUpdated( + client=client, + id=update.msg_id, + from_user=from_user, + date=utils.timestamp_to_datetime(update.date), + chat=chat, + actor_chat=actor_chat, + old_reaction=[ + types.ReactionType._parse( + rt + ) for rt in update.old_reactions + ], + new_reaction=[ + types.ReactionType._parse( + rt + ) for rt in update.new_reactions + ] + ) \ No newline at end of file diff --git a/pyrogram/types/messages_and_media/message_reactions.py b/pyrogram/types/messages_and_media/message_reactions.py index 8f057cf5..b2b27789 100644 --- a/pyrogram/types/messages_and_media/message_reactions.py +++ b/pyrogram/types/messages_and_media/message_reactions.py @@ -51,6 +51,8 @@ class MessageReactions(Object): return MessageReactions( client=client, - reactions=[types.Reaction._parse_count(client, reaction) - for reaction in message_reactions.results] + reactions=[ + types.Reaction._parse_count(client, reaction) + for reaction in message_reactions.results + ] ) diff --git a/pyrogram/types/messages_and_media/reaction.py b/pyrogram/types/messages_and_media/reaction.py index 17e08ff5..1295571e 100644 --- a/pyrogram/types/messages_and_media/reaction.py +++ b/pyrogram/types/messages_and_media/reaction.py @@ -1,20 +1,21 @@ -# Pyrogram - Telegram MTProto API Client Library for Python +# PyroFork - Telegram MTProto API Client Library for Python # Copyright (C) 2017-present Dan +# Copyright (C) 2022-present Mayuri-Chan # -# This file is part of Pyrogram. +# This file is part of PyroFork. # -# Pyrogram is free software: you can redistribute it and/or modify +# PyroFork 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, +# PyroFork 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 . +# along with PyroFork. If not, see . from typing import Optional diff --git a/pyrogram/types/messages_and_media/reaction_count.py b/pyrogram/types/messages_and_media/reaction_count.py new file mode 100644 index 00000000..fa46cb08 --- /dev/null +++ b/pyrogram/types/messages_and_media/reaction_count.py @@ -0,0 +1,63 @@ +# PyroFork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of PyroFork. +# +# PyroFork 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. +# +# PyroFork 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 PyroFork. If not, see . + +from typing import Optional + +from pyrogram import raw +from .reaction_type import ReactionType +from ..object import Object + +class ReactionCount(Object): + """Represents a reaction added to a message along with the number of times it was added. + + Parameters: + + type (:obj:`~pyrogram.types.ReactionType`): + Reaction type. + + total_count (``int``): + Total reaction count. + + chosen_order (``int``): + Chosen reaction order. + Available for chosen reactions. + """ + + def __init__( + self, + *, + type: ReactionType, + total_count: int, + chosen_order: int + ): + super().__init__() + self.type = type + self.total_count = total_count + self.chosen_order = chosen_order + + @staticmethod + def _parse( + update: "raw.types.ReactionCount", + ) -> Optional["ReactionCount"]: + return ReactionCount( + type=ReactionType._parse( + update.reaction + ), + total_count=update.count, + chosen_order=update.chosen_order + ) diff --git a/pyrogram/types/messages_and_media/reaction_type.py b/pyrogram/types/messages_and_media/reaction_type.py new file mode 100644 index 00000000..a0a9cbf4 --- /dev/null +++ b/pyrogram/types/messages_and_media/reaction_type.py @@ -0,0 +1,74 @@ +# PyroFork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of PyroFork. +# +# PyroFork 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. +# +# PyroFork 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 PyroFork. If not, see . + +from typing import Optional + +from pyrogram import enums, raw +from ..object import Object + +class ReactionType(Object): + """Contains information about a reaction. + + Parameters: + type (``enums.ReactionType``, *optional*): + Reaction type. + + emoji (``str``, *optional*): + Reaction emoji. + + custom_emoji_id (``int``, *optional*): + Custom emoji id. + """ + def __init__( + self, + *, + type: str = "enums.ReactionType", + emoji: str = None, + custom_emoji_id: str = None + ): + super().__init__() + self.type = type + self.emoji = emoji + self.custom_emoji_id = custom_emoji_id + + @staticmethod + def _parse( + update: "raw.types.Reaction", + ) -> Optional["ReactionType"]: + if isinstance(update, raw.types.ReactionEmpty): + return None + elif isinstance(update, raw.types.ReactionEmoji): + return ReactionType( + type=enums.ReactionType.EMOJI, + emoji=update.emoticon + ) + elif isinstance(update, raw.types.ReactionCustomEmoji): + return ReactionType( + type=enums.ReactionType.CUSTOM_EMOJI, + custom_emoji_id=update.document_id + ) + + def write(self): + if self.type == enums.ReactionType.EMOJI: + return raw.types.ReactionEmoji( + emoticon=self.emoji + ) + if self.type == enums.ReactionType.CUSTOM_EMOJI: + return raw.types.ReactionCustomEmoji( + document_id=self.custom_emoji_id + ) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 44b94bde..e6519183 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -474,7 +474,10 @@ class Chat(Object): if isinstance(full_chat.exported_invite, raw.types.ChatInviteExported): parsed_chat.invite_link = full_chat.exported_invite.link - parsed_chat.available_reactions = types.ChatReactions._parse(client, full_chat.available_reactions) + parsed_chat.available_reactions = types.ChatReactions._parse( + client, + full_chat.available_reactions + ) return parsed_chat diff --git a/pyrogram/types/user_and_chats/chat_reactions.py b/pyrogram/types/user_and_chats/chat_reactions.py index 057fb966..0252029b 100644 --- a/pyrogram/types/user_and_chats/chat_reactions.py +++ b/pyrogram/types/user_and_chats/chat_reactions.py @@ -62,8 +62,12 @@ class ChatReactions(Object): if isinstance(chat_reactions, raw.types.ChatReactionsSome): return ChatReactions( client=client, - reactions=[types.Reaction._parse(client, reaction) - for reaction in chat_reactions.reactions] + reactions=[ + types.ReactionType._parse(reaction) + for reaction in chat_reactions.reactions + ] ) + if isinstance(chat_reactions, raw.types.ChatReactionsNone): + return None - return None + return None \ No newline at end of file