diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index d23f2cd71..fd99eaf32 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -91,7 +91,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; userEmpty#d3bc4b7a id:long = User; -user#215c4438 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?int color:flags2.8?PeerColor profile_color:flags2.9?PeerColor = User; +user#215c4438 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?int color:flags2.8?PeerColor profile_color:flags2.9?PeerColor = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; @@ -99,9 +99,9 @@ userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true p userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#e26f42f1 = UserStatus; -userStatusLastWeek#7bf09fc = UserStatus; -userStatusLastMonth#77ebc742 = UserStatus; +userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; +userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; +userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; chatEmpty#29562865 id:long = Chat; chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; @@ -235,7 +235,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonIllegalDrugs#a8eb2be = ReportReason; inputReportReasonPersonalDetails#9ec7863d = ReportReason; -userFull#b9b12c6c flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector wallpaper:flags.24?WallPaper stories:flags.25?PeerStories = UserFull; +userFull#b9b12c6c flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector wallpaper:flags.24?WallPaper stories:flags.25?PeerStories = UserFull; contact#145ade0b user_id:long mutual:Bool = Contact; @@ -409,6 +409,7 @@ updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_r updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; +updateSavedReactionTags#39c67432 = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1267,7 +1268,7 @@ statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInvite stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; -globalPrivacySettings#734c4ccb flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true = GlobalPrivacySettings; +globalPrivacySettings#734c4ccb flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true = GlobalPrivacySettings; help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; @@ -1375,7 +1376,7 @@ auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; -messageReactions#4f2b9479 flags:# min:flags.0?true can_see_list:flags.2?true results:Vector recent_reactions:flags.1?Vector = MessageReactions; +messageReactions#4f2b9479 flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector = MessageReactions; messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; @@ -1652,6 +1653,13 @@ messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; +savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; + +messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; +messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; + +outboxReadDate#3bb842ac date:int = OutboxReadDate; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1781,6 +1789,7 @@ account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#b60f5918 id:InputUser = users.UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; +users.getIsPremiumRequiredToContact#a622aa10 id:Vector = Vector; contacts.getContactIDs#7adc669d hash:long = Vector; contacts.getStatuses#c4a353ee = Vector; @@ -1811,7 +1820,7 @@ contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector = messages.Messages; messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#a7b4e929 flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; +messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; @@ -2002,6 +2011,10 @@ messages.deleteSavedHistory#6e98102b flags:# peer:InputPeer max_id:int min_date: messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; +messages.getSavedReactionTags#761ddacf hash:long = messages.SavedReactionTags; +messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; +messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; +messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2244,4 +2257,4 @@ premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = p premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; -// LAYER 170 \ No newline at end of file +// LAYER 172 \ No newline at end of file diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index acd2fd5ae..e87eab49a 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -487,6 +487,11 @@ def get_title_list(s: str) -> list: ForumTopicReopened GeneralTopicHidden GeneralTopicUnhidden + Reaction + ReactionCount + ReactionType + MessageReactionUpdated + MessageReactionCountUpdated """, stories=""" Stories diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index e81343ce1..5e3fd8b71 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -275,6 +275,7 @@ RESULTS_TOO_MUCH The result contains too many items RESULT_ID_DUPLICATE The result contains items with duplicated identifiers RESULT_ID_EMPTY Result ID empty RESULT_ID_INVALID The given result cannot be used to send the selection to the bot +REACTIONS_TOO_MANY Currently, non-premium users, can set up to one reaction per message RESULT_TYPE_INVALID The result type is invalid REVOTE_NOT_ALLOWED You cannot change your vote RSA_DECRYPT_FAILED Internal RSA decryption failed diff --git a/compiler/errors/source/403_FORBIDDEN.tsv b/compiler/errors/source/403_FORBIDDEN.tsv index 99645f632..534a72a91 100644 --- a/compiler/errors/source/403_FORBIDDEN.tsv +++ b/compiler/errors/source/403_FORBIDDEN.tsv @@ -11,6 +11,7 @@ MESSAGE_AUTHOR_REQUIRED You are not the author of this message MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat, most likely because you are not the author of them POLL_VOTE_REQUIRED Cast a vote in the poll before calling this method PREMIUM_ACCOUNT_REQUIRED This action requires a premium account +PRIVACY_PREMIUM_REQUIRED The user has restricted from sending messages OR This action requires a premium account RIGHT_FORBIDDEN You don't have enough rights for this action, or you tried to set one or more admin rights that can't be applied to this kind of chat (channel or supergroup) SENSITIVE_CHANGE_FORBIDDEN Your sensitive content settings can't be changed at this time TAKEOUT_REQUIRED The method must be invoked inside a takeout session diff --git a/compiler/errors/source/420_FLOOD.tsv b/compiler/errors/source/420_FLOOD.tsv index 575cc2f5b..b45fb3f63 100644 --- a/compiler/errors/source/420_FLOOD.tsv +++ b/compiler/errors/source/420_FLOOD.tsv @@ -2,5 +2,7 @@ id message 2FA_CONFIRM_WAIT_X A wait of {value} seconds is required because this account is active and protected by a 2FA password FLOOD_TEST_PHONE_WAIT_X A wait of {value} seconds is required in the test servers FLOOD_WAIT_X A wait of {value} seconds is required -SLOWMODE_WAIT_X A wait of {value} seconds is required to send messages in this chat. +PREMIUM_SUB_ACTIVE_UNTIL_X A wait of {value} seconds is required +SLOWMODE_WAIT_X A wait of {value} seconds is required to send messages in this chat +STORY_SEND_FLOOD_X A wait of {value} seconds is required to continue posting stories TAKEOUT_INIT_DELAY_X You have to confirm the data export request using one of your mobile devices or wait {value} seconds \ No newline at end of file diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index 1dac109c7..90a01cbe0 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 000000000..59692fbad --- /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 f98e37610..aca1a6056 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 e1f325079..cfe99bbec 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/client.py b/pyrogram/client.py index e714c2962..df722317f 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -848,6 +848,9 @@ async def handle_download(self, packet): if isinstance(e, asyncio.CancelledError): raise e + if isinstance(e, pyrogram.errors.FloodWait): + raise e + return None else: if in_memory: @@ -1070,6 +1073,8 @@ async def get_file( await cdn_session.stop() except pyrogram.StopTransmission: raise + except pyrogram.errors.FloodWait: + raise except Exception as e: log.exception(e) finally: diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index ea94b2a88..701e5fcb2 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -25,9 +25,7 @@ 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 @@ 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 @@ async def story_parser(update, users, chats): 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 @@ async def story_parser(update, users, chats): 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 76b79e9bd..15eadf275 100644 --- a/pyrogram/enums/__init__.py +++ b/pyrogram/enums/__init__.py @@ -30,6 +30,7 @@ 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 @@ '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 000000000..829de1ecd --- /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 5a28eeb5a..ab9186680 100644 --- a/pyrogram/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -31,3 +31,5 @@ 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 000000000..74ab37a80 --- /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 000000000..ea86a6d79 --- /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 560a13dec..169b1ec33 100644 --- a/pyrogram/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -30,6 +30,8 @@ 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 000000000..37e95a29f --- /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 000000000..bc27776b9 --- /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 180763f24..3045adc35 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 @@ async def send_reaction( 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 @@ async def send_reaction( 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 @@ async def send_reaction( 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 @@ async def send_reaction( 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 @@ async def send_reaction( ] 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/raw/core/primitives/vector.py b/pyrogram/raw/core/primitives/vector.py index c6c6e8e5d..7676ab6ae 100644 --- a/pyrogram/raw/core/primitives/vector.py +++ b/pyrogram/raw/core/primitives/vector.py @@ -19,6 +19,7 @@ from io import BytesIO from typing import cast, Union, Any +from .bool import BoolFalse, BoolTrue, Bool from .int import Int, Long from ..list import List from ..tl_object import TLObject @@ -32,7 +33,22 @@ class Vector(bytes, TLObject): @staticmethod def read_bare(b: BytesIO, size: int) -> Union[int, Any]: if size == 4: - return Int.read(b) + # cek + e = int.from_bytes( + b.read(4), + "little" + ) + # bak + b.seek(-4, 1) + # cond + if e in [ + BoolFalse.ID, + BoolTrue.ID, + ]: + return Bool.read(b) + # not + else: + return Int.read(b) if size == 8: return Long.read(b) diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index a58518682..890a3fe54 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 .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_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 @@ __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 3e16a4aae..f8676dfe4 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -4360,7 +4360,7 @@ async def click(self, x: Union[int, str] = 0, y: int = None, quote: bool = None, 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 @@ async def react(self, emoji: str = "", big: bool = False) -> bool: 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 000000000..3735e6776 --- /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 000000000..aa4eb387c --- /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 8f057cf55..b2b277893 100644 --- a/pyrogram/types/messages_and_media/message_reactions.py +++ b/pyrogram/types/messages_and_media/message_reactions.py @@ -51,6 +51,8 @@ def _parse( 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 17e08ff57..1295571ef 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 000000000..fa46cb08c --- /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 000000000..a0a9cbf4e --- /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 44b94bdef..e5c538a74 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -69,6 +69,9 @@ class Chat(Object): is_join_to_send (``bool``, *optional*): True, if only chat members allowed to send message in chat. + is_slowmode_enabled (``bool``, *optional*): + True, if slowmode is enabled in chat. + is_antispam (``bool``, *optional*): True, if Aggressive Anti-Spam is enabled in chat. Returned only in :meth:`~pyrogram.Client.get_chat`. @@ -134,6 +137,10 @@ class Chat(Object): Chat members count, for groups, supergroups and channels only. Returned only in :meth:`~pyrogram.Client.get_chat`. + slow_mode_delay (``int``, *optional*): + For supergroups, the minimum allowed delay between consecutive messages sent by each unpriviledged user in seconds. + Returned only in :meth:`~pyrogram.Client.get_chat`. + restrictions (List of :obj:`~pyrogram.types.Restriction`, *optional*): The list of reasons why this chat might be unavailable to some users. This field is available only in case *is_restricted* is True. @@ -192,6 +199,7 @@ def __init__( is_join_request: bool = None, is_join_to_send: bool = None, is_antispam: bool = None, + is_slowmode_enabled: bool = None, title: str = None, username: str = None, first_name: str = None, @@ -209,6 +217,7 @@ def __init__( sticker_set_name: str = None, can_set_sticker_set: bool = None, members_count: int = None, + slow_mode_delay: int = None, restrictions: List["types.Restriction"] = None, permissions: "types.ChatPermissions" = None, distance: int = None, @@ -234,6 +243,7 @@ def __init__( self.is_join_request = is_join_request self.is_join_to_send = is_join_to_send self.is_antispam = is_antispam + self.is_slowmode_enabled = is_slowmode_enabled self.title = title self.username = username self.first_name = first_name @@ -251,6 +261,7 @@ def __init__( self.sticker_set_name = sticker_set_name self.can_set_sticker_set = can_set_sticker_set self.members_count = members_count + self.slow_mode_delay = slow_mode_delay self.restrictions = restrictions self.permissions = permissions self.distance = distance @@ -341,6 +352,7 @@ def _parse_channel_chat(client, channel: raw.types.Channel) -> "Chat": is_forum=getattr(channel, "forum", None), is_join_request=getattr(channel, "join_request", None), is_join_to_send=getattr(channel, "join_to_send", None), + is_slowmode_enabled=getattr(channel, "slowmode_enabled", None), title=channel.title, username=user_name, usernames=usernames, @@ -428,6 +440,7 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. else: parsed_chat = Chat._parse_channel_chat(client, chat_raw) parsed_chat.members_count = full_chat.participants_count + parsed_chat.slow_mode_delay = getattr(full_chat, "slowmode_seconds", None) parsed_chat.description = full_chat.about or None # TODO: Add StickerSet type parsed_chat.can_set_sticker_set = full_chat.can_set_stickers @@ -474,7 +487,10 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. 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 057fb9665..0252029bc 100644 --- a/pyrogram/types/user_and_chats/chat_reactions.py +++ b/pyrogram/types/user_and_chats/chat_reactions.py @@ -62,8 +62,12 @@ def _parse(client, chat_reactions: "raw.base.ChatReactions") -> Optional["ChatRe 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