From e7654c9fad4eed0d6218572a711b21aa91522a17 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 24 Apr 2024 19:12:57 +0200 Subject: [PATCH 001/154] Add edit_cached_media method --- compiler/docs/compiler.py | 2 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/__init__.py | 2 + .../methods/messages/edit_cached_media.py | 116 ++++++++++++++++++ pyrogram/types/messages_and_media/message.py | 61 +++++++++ 5 files changed, 182 insertions(+) create mode 100644 pyrogram/methods/messages/edit_cached_media.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 5ff86f766c..a0efbb1360 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -279,6 +279,7 @@ def get_title_list(s: str) -> list: copy_message delete_messages download_media + edit_cached_media edit_inline_caption edit_inline_media edit_inline_reply_markup @@ -612,6 +613,7 @@ def get_title_list(s: str) -> list: Message.unpin Message.edit Message.edit_text + Message.edit_cached_media Message.edit_caption Message.edit_media Message.edit_reply_markup diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 00f63f4d43..f8660cf4c2 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 178 | +------------------------+ +- Added :meth:`~pyrogram.Client.edit_cached_media` and :meth:`~pyrogram.types.Message.edit_cached_media`. - Steal `d51eef3 `_ without attribution. - Added ``limit`` to :obj:`~pyrogram.types.ChatReactions`. - Added ``personal_chat_message`` to :obj:`~pyrogram.types.Chat`. diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index 8fc44b7634..15ca14ac06 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -20,6 +20,7 @@ from .copy_message import CopyMessage from .delete_messages import DeleteMessages from .download_media import DownloadMedia +from .edit_cached_media import EditCachedMedia from .edit_inline_caption import EditInlineCaption from .edit_inline_media import EditInlineMedia from .edit_inline_reply_markup import EditInlineReplyMarkup @@ -73,6 +74,7 @@ class Messages( CopyMessage, DeleteMessages, DownloadMedia, + EditCachedMedia, EditInlineCaption, EditInlineMedia, EditInlineReplyMarkup, diff --git a/pyrogram/methods/messages/edit_cached_media.py b/pyrogram/methods/messages/edit_cached_media.py new file mode 100644 index 0000000000..22e4db52a9 --- /dev/null +++ b/pyrogram/methods/messages/edit_cached_media.py @@ -0,0 +1,116 @@ +# 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 . + +import logging +from datetime import datetime +from typing import Union, List, Optional + +import pyrogram +from pyrogram import raw, enums, types, utils + +log = logging.getLogger(__name__) + + +class EditCachedMedia: + async def edit_cached_media( + self: "pyrogram.Client", + chat_id: Union[int, str], + message_id: int, + file_id: str, + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + schedule_date: datetime = None, + has_spoiler: bool = None, + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> Optional["types.Message"]: + """Edit a media stored on the Telegram servers using a file_id. + + This convenience method works with any valid file_id only. + It does the same as calling the relevant method for editing media using a file_id, thus saving you from the + hassle of using the correct :obj:`~pyrogram.types.InputMedia` for the media the file_id is pointing to. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + message_id (``int``): + Message identifier in the chat specified in chat_id. + + file_id (``str``): + Media to send. + Pass a file_id as string to send a media that exists on the Telegram servers. + + caption (``str``, *optional*): + Media caption, 0-1024 characters. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + schedule_date (:py:obj:`~datetime.datetime`, *optional*): + Date when the message will be automatically sent. + + has_spoiler (``bool``, *optional*): + True, if the message media is covered by a spoiler animation. + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): + An InlineKeyboardMarkup object. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the edited media message is returned. + + Example: + .. code-block:: python + + await app.edit_cached_media(chat_id, message_id, file_id) + """ + + rpc = raw.functions.messages.EditMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + media=utils.get_input_media_from_file_id(file_id, has_spoiler=has_spoiler), + reply_markup=await reply_markup.write(self) if reply_markup else None, + schedule_date=utils.datetime_to_timestamp(schedule_date), + **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) + ) + r = await self.invoke(rpc) + + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateEditMessage, + raw.types.UpdateEditChannelMessage, + raw.types.UpdateNewScheduledMessage + ) + ): + return await types.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=0 + ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 6d04aa1147..aa5d17126b 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -3697,6 +3697,67 @@ async def edit_reply_markup(self, reply_markup: "types.InlineKeyboardMarkup" = N reply_markup=reply_markup ) + async def edit_cached_media( + file_id: str, + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + schedule_date: datetime = None, + has_spoiler: bool = None, + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> "Message": + """Edit a media stored on the Telegram servers using a file_id. + + This convenience method works with any valid file_id only. + It does the same as calling the relevant method for editing media using a file_id, thus saving you from the + hassle of using the correct :obj:`~pyrogram.types.InputMedia` for the media the file_id is pointing to. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + file_id (``str``): + Media to send. + Pass a file_id as string to send a media that exists on the Telegram servers. + + caption (``str``, *optional*): + Media caption, 0-1024 characters. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + schedule_date (:py:obj:`~datetime.datetime`, *optional*): + Date when the message will be automatically sent. + + has_spoiler (``bool``, *optional*): + True, if the message media is covered by a spoiler animation. + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): + An InlineKeyboardMarkup object. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the edited media message is returned. + + Example: + .. code-block:: python + + await message.edit_cached_media(file_id) + """ + return await self._client.edit_cached_media( + chat_id=self.chat.id, + message_id=self.id, + file_id=file_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + schedule_date=schedule_date, + has_spoiler=has_spoiler, + reply_markup=reply_markup + ) + async def forward( self, chat_id: Union[int, str], From 536c2fa92e498cdb3b11b1e128aebe031ea13ebe Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 24 Apr 2024 19:28:51 +0200 Subject: [PATCH 002/154] Fix bug with forward fliters Follow-Up: 46a3b2d --- pyrogram/filters.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index 26d611f856..8ff574f8df 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -239,7 +239,7 @@ async def reply_filter(_, __, m: Message) -> bool: # region forwarded_filter async def forwarded_filter(_, __, m: Message) -> bool: - return bool(m.forward_date) + return bool(m.forward_origin) forwarded = create(forwarded_filter) @@ -817,8 +817,11 @@ async def from_scheduled_filter(_, __, m: Message) -> bool: # region linked_channel_filter async def linked_channel_filter(_, __, m: Message) -> bool: - return bool(m.forward_from_chat and not m.from_user) - + return bool( + m.forward_origin and + m.forward_origin.type == "channel" and + m.forward_origin.chat == m.sender_chat + ) linked_channel: Filter = create(linked_channel_filter) """Filter messages that are automatically forwarded from the linked channel to the group chat.""" From d06c6a104eb4b7f714e358632263ca9e62cdee74 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 25 Apr 2024 16:32:06 +0200 Subject: [PATCH 003/154] https://t.me/pyrogramchat/614800 --- pyrogram/methods/messages/edit_inline_media.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/methods/messages/edit_inline_media.py b/pyrogram/methods/messages/edit_inline_media.py index 5d4a3701c0..d549ccfbaf 100644 --- a/pyrogram/methods/messages/edit_inline_media.py +++ b/pyrogram/methods/messages/edit_inline_media.py @@ -216,7 +216,7 @@ async def edit_inline_media( file_reference=uploaded_media.photo.file_reference ), spoiler=getattr(media, "has_spoiler", None) - ) if isinstance(media, types.InputMediaPhoto) else raw.types.InputMediaDocument( + ) if isinstance(uploaded_media, raw.types.MessageMediaPhoto) else raw.types.InputMediaDocument( id=raw.types.InputDocument( id=uploaded_media.document.id, access_hash=uploaded_media.document.access_hash, From 15e8f31e99e5c2f90133013b09087e71c92e94cb Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 25 Apr 2024 17:36:12 +0200 Subject: [PATCH 004/154] documentatation fix --- pyrogram/methods/users/set_profile_photo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyrogram/methods/users/set_profile_photo.py b/pyrogram/methods/users/set_profile_photo.py index 712ee2b6d7..6b0ae13c47 100644 --- a/pyrogram/methods/users/set_profile_photo.py +++ b/pyrogram/methods/users/set_profile_photo.py @@ -40,7 +40,6 @@ async def set_profile_photo( .. note:: This method only works for Users. - Bots profile photos must be set using BotFather. .. include:: /_includes/usable-by/users-bots.rst From a64e70c06e9e1cd347300f1863ce7a1151522bc3 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 25 Apr 2024 18:13:46 +0200 Subject: [PATCH 005/154] Added new functions (#19) set_bot_name get_bot_name set_bot_info_description get_bot_info_description set_bot_info_short_description get_bot_info_short_description --- compiler/docs/compiler.py | 6 ++ docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/bots/__init__.py | 12 ++++ .../methods/bots/get_bot_info_description.py | 62 +++++++++++++++++ .../bots/get_bot_info_short_description.py | 62 +++++++++++++++++ pyrogram/methods/bots/get_bot_name.py | 62 +++++++++++++++++ .../methods/bots/set_bot_info_description.py | 66 +++++++++++++++++++ .../bots/set_bot_info_short_description.py | 66 +++++++++++++++++++ pyrogram/methods/bots/set_bot_name.py | 66 +++++++++++++++++++ 9 files changed, 403 insertions(+) create mode 100644 pyrogram/methods/bots/get_bot_info_description.py create mode 100644 pyrogram/methods/bots/get_bot_info_short_description.py create mode 100644 pyrogram/methods/bots/get_bot_name.py create mode 100644 pyrogram/methods/bots/set_bot_info_description.py create mode 100644 pyrogram/methods/bots/set_bot_info_short_description.py create mode 100644 pyrogram/methods/bots/set_bot_name.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index a0efbb1360..a9729af4f7 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -187,6 +187,12 @@ def get_title_list(s: str) -> list: set_chat_menu_button get_chat_menu_button answer_web_app_query + set_bot_name + get_bot_name + set_bot_info_description + get_bot_info_description + set_bot_info_short_description + get_bot_info_short_description """, chats=""" Chats diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index f8660cf4c2..ee9ee45b25 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 178 | +------------------------+ +- Added :meth:`~pyrogram.Client.get_bot_name`, :meth:`~pyrogram.Client.get_bot_info_description`, :meth:`~pyrogram.Client.get_bot_info_short_description`, :meth:`~pyrogram.Client.set_bot_name`, :meth:`~pyrogram.Client.set_bot_info_description`, :meth:`~pyrogram.Client.set_bot_info_short_description`. - Added :meth:`~pyrogram.Client.edit_cached_media` and :meth:`~pyrogram.types.Message.edit_cached_media`. - Steal `d51eef3 `_ without attribution. - Added ``limit`` to :obj:`~pyrogram.types.ChatReactions`. diff --git a/pyrogram/methods/bots/__init__.py b/pyrogram/methods/bots/__init__.py index 8198ed8fe7..7926677ce7 100644 --- a/pyrogram/methods/bots/__init__.py +++ b/pyrogram/methods/bots/__init__.py @@ -22,6 +22,9 @@ from .delete_bot_commands import DeleteBotCommands from .get_bot_commands import GetBotCommands from .get_bot_default_privileges import GetBotDefaultPrivileges +from .get_bot_info_description import GetBotInfoDescription +from .get_bot_info_short_description import GetBotInfoShortDescription +from .get_bot_name import GetBotName from .get_chat_menu_button import GetChatMenuButton from .get_game_high_scores import GetGameHighScores from .get_inline_bot_results import GetInlineBotResults @@ -30,6 +33,9 @@ from .send_inline_bot_result import SendInlineBotResult from .set_bot_commands import SetBotCommands from .set_bot_default_privileges import SetBotDefaultPrivileges +from .set_bot_info_description import SetBotInfoDescription +from .set_bot_info_short_description import SetBotInfoShortDescription +from .set_bot_name import SetBotName from .set_chat_menu_button import SetChatMenuButton from .set_game_score import SetGameScore @@ -51,5 +57,11 @@ class Bots( GetBotDefaultPrivileges, SetChatMenuButton, GetChatMenuButton, + SetBotInfoDescription, + GetBotInfoDescription, + SetBotInfoShortDescription, + GetBotInfoShortDescription, + SetBotName, + GetBotName, ): pass diff --git a/pyrogram/methods/bots/get_bot_info_description.py b/pyrogram/methods/bots/get_bot_info_description.py new file mode 100644 index 0000000000..739e6d60dc --- /dev/null +++ b/pyrogram/methods/bots/get_bot_info_description.py @@ -0,0 +1,62 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class GetBotInfoDescription: + async def get_bot_info_description( + self: "pyrogram.Client", + language_code: str = "", + for_my_bot: Union[int, str] = None, + ) -> str: + """Use this method to get the current / owned bot description for the given user language. + + .. note:: + + If the current account is an User, can be called only if the ``for_my_bot`` has ``can_be_edited`` property set to True. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + language_code (``str``, *optional*): + A two-letter ISO 639-1 language code or an empty string + + for_my_bot (``int`` | ``str``, *optional*): + Unique identifier (int) or username (str) of the bot for which profile photo has to be updated instead of the current user. + The bot should have ``can_be_edited`` property set to True. + + Returns: + ``str``: On success, returns the text shown in the chat with a bot if the chat is empty in the given language. + + Example: + .. code-block:: python + + bot_description = await app.get_bot_info_description() + """ + + bot_info = await self.invoke( + raw.functions.bots.GetBotInfo( + bot=await self.resolve_peer(for_my_bot) if for_my_bot else None, + lang_code=language_code + ) + ) + return bot_info.description diff --git a/pyrogram/methods/bots/get_bot_info_short_description.py b/pyrogram/methods/bots/get_bot_info_short_description.py new file mode 100644 index 0000000000..c78eb186c5 --- /dev/null +++ b/pyrogram/methods/bots/get_bot_info_short_description.py @@ -0,0 +1,62 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class GetBotInfoShortDescription: + async def get_bot_info_short_description( + self: "pyrogram.Client", + language_code: str = "", + for_my_bot: Union[int, str] = None, + ) -> str: + """Use this method to get the current / owned bot short description for the given user language. + + .. note:: + + If the current account is an User, can be called only if the ``for_my_bot`` has ``can_be_edited`` property set to True. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + language_code (``str``, *optional*): + A two-letter ISO 639-1 language code or an empty string + + for_my_bot (``int`` | ``str``, *optional*): + Unique identifier (int) or username (str) of the bot for which profile photo has to be updated instead of the current user. + The bot should have ``can_be_edited`` property set to True. + + Returns: + ``str``: On success, returns the text shown on a bot's profile page and sent together with the link when users share the bot in the given language. + + Example: + .. code-block:: python + + bot_short_description = await app.get_bot_info_short_description() + """ + + bot_info = await self.invoke( + raw.functions.bots.GetBotInfo( + bot=await self.resolve_peer(for_my_bot) if for_my_bot else None, + lang_code=language_code + ) + ) + return bot_info.about diff --git a/pyrogram/methods/bots/get_bot_name.py b/pyrogram/methods/bots/get_bot_name.py new file mode 100644 index 0000000000..e2775b89fc --- /dev/null +++ b/pyrogram/methods/bots/get_bot_name.py @@ -0,0 +1,62 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class GetBotName: + async def get_bot_name( + self: "pyrogram.Client", + language_code: str = "", + for_my_bot: Union[int, str] = None, + ) -> str: + """Use this method to get the current / owned bot name for the given user language. + + .. note:: + + If the current account is an User, can be called only if the ``for_my_bot`` has ``can_be_edited`` property set to True. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + language_code (``str``, *optional*): + A two-letter ISO 639-1 language code or an empty string + + for_my_bot (``int`` | ``str``, *optional*): + Unique identifier (int) or username (str) of the bot for which profile photo has to be updated instead of the current user. + The bot should have ``can_be_edited`` property set to True. + + Returns: + ``str``: On success, returns the name of a bot in the given language. + + Example: + .. code-block:: python + + bot_name = await app.get_bot_name() + """ + + bot_info = await self.invoke( + raw.functions.bots.GetBotInfo( + bot=await self.resolve_peer(for_my_bot) if for_my_bot else None, + lang_code=language_code + ) + ) + return bot_info.name diff --git a/pyrogram/methods/bots/set_bot_info_description.py b/pyrogram/methods/bots/set_bot_info_description.py new file mode 100644 index 0000000000..6be130aca4 --- /dev/null +++ b/pyrogram/methods/bots/set_bot_info_description.py @@ -0,0 +1,66 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class SetBotInfoDescription: + async def set_bot_info_description( + self: "pyrogram.Client", + description: str, + language_code: str = "", + for_my_bot: Union[int, str] = None, + ) -> bool: + """Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. + + .. note:: + + If the current account is an User, can be called only if the ``for_my_bot`` has ``can_be_edited`` property set to True. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + description (``str``): + New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language. + + language_code (``str``, *optional*): + A two-letter ISO 639-1 language code or an empty string + + for_my_bot (``int`` | ``str``, *optional*): + Unique identifier (int) or username (str) of the bot for which profile photo has to be updated instead of the current user. + The bot should have ``can_be_edited`` property set to True. + + Returns: + ``bool``: True on success. + + Example: + .. code-block:: python + + await app.set_bot_info_description("") + """ + + return await self.invoke( + raw.functions.bots.SetBotInfo( + bot=await self.resolve_peer(for_my_bot) if for_my_bot else None, + lang_code=language_code, + description=description + ) + ) diff --git a/pyrogram/methods/bots/set_bot_info_short_description.py b/pyrogram/methods/bots/set_bot_info_short_description.py new file mode 100644 index 0000000000..5a3903d55a --- /dev/null +++ b/pyrogram/methods/bots/set_bot_info_short_description.py @@ -0,0 +1,66 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class SetBotInfoShortDescription: + async def set_bot_info_short_description( + self: "pyrogram.Client", + short_description: str, + language_code: str = "", + for_my_bot: Union[int, str] = None, + ) -> bool: + """Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. + + .. note:: + + If the current account is an User, can be called only if the ``for_my_bot`` has ``can_be_edited`` property set to True. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + short_description (``str``): + New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language. + + language_code (``str``, *optional*): + A two-letter ISO 639-1 language code or an empty string + + for_my_bot (``int`` | ``str``, *optional*): + Unique identifier (int) or username (str) of the bot for which profile photo has to be updated instead of the current user. + The bot should have ``can_be_edited`` property set to True. + + Returns: + ``bool``: True on success. + + Example: + .. code-block:: python + + await app.set_bot_info_short_description("") + """ + + return await self.invoke( + raw.functions.bots.SetBotInfo( + bot=await self.resolve_peer(for_my_bot) if for_my_bot else None, + lang_code=language_code, + about=short_description + ) + ) diff --git a/pyrogram/methods/bots/set_bot_name.py b/pyrogram/methods/bots/set_bot_name.py new file mode 100644 index 0000000000..34fd2fffeb --- /dev/null +++ b/pyrogram/methods/bots/set_bot_name.py @@ -0,0 +1,66 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class SetBotName: + async def set_bot_name( + self: "pyrogram.Client", + name: str, + language_code: str = "", + for_my_bot: Union[int, str] = None, + ) -> str: + """Use this method to get the current / owned bot name for the given user language. + + .. note:: + + If the current account is an User, can be called only if the ``for_my_bot`` has ``can_be_edited`` property set to True. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + name (``str``): + New bot name; 0-64 characters. Pass an empty string to remove the dedicated name for the given language. + + language_code (``str``, *optional*): + A two-letter ISO 639-1 language code or an empty string + + for_my_bot (``int`` | ``str``, *optional*): + Unique identifier (int) or username (str) of the bot for which profile photo has to be updated instead of the current user. + The bot should have ``can_be_edited`` property set to True. + + Returns: + ``bool``: True on success. + + Example: + .. code-block:: python + + await app.set_bot_name("Pyrogram Assistant") + """ + + return await self.invoke( + raw.functions.bots.SetBotInfo( + bot=await self.resolve_peer(for_my_bot) if for_my_bot else None, + lang_code=language_code, + name=name + ) + ) From 00e99c4bd58de32fd889defc96d99f0413c49429 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma <31959970+KurimuzonAkuma@users.noreply.github.com> Date: Wed, 24 Apr 2024 22:14:10 +0300 Subject: [PATCH 006/154] attempt to fix build --- .github/workflows/python.yml | 4 ++-- pyproject.toml | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index d1a204d816..6ad8fe3c83 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -12,8 +12,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + os: [ubuntu-22.04, macos-12] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v3 diff --git a/pyproject.toml b/pyproject.toml index 4bfaf4c057..496f3d8f5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,10 @@ include = ["pyrogram/py.typed"] exclude = ["tests", "docs", "requirements.lock", "requirements-dev.lock", ".github", ".gitignore"] [tool.hatch.build.targets.sdist] -include = ["pyrogram"] +include = [ + "compiler", + "pyrogram", +] exclude = [ ".github/", "docs/", From 563da9a08e5dbab56315c9a46fe532e51d3236e8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 26 Apr 2024 20:12:40 +0200 Subject: [PATCH 007/154] Add search_chats method --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/chats/__init__.py | 2 + pyrogram/methods/chats/search_chats.py | 81 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 pyrogram/methods/chats/search_chats.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index a9729af4f7..f2886d4e39 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -198,6 +198,7 @@ def get_title_list(s: str) -> list: Chats join_chat leave_chat + search_chats ban_chat_member unban_chat_member restrict_chat_member diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index ee9ee45b25..ca1db3de14 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 178 | +------------------------+ +- Added :meth:`~pyrogram.Client.search_chats`. - Added :meth:`~pyrogram.Client.get_bot_name`, :meth:`~pyrogram.Client.get_bot_info_description`, :meth:`~pyrogram.Client.get_bot_info_short_description`, :meth:`~pyrogram.Client.set_bot_name`, :meth:`~pyrogram.Client.set_bot_info_description`, :meth:`~pyrogram.Client.set_bot_info_short_description`. - Added :meth:`~pyrogram.Client.edit_cached_media` and :meth:`~pyrogram.types.Message.edit_cached_media`. - Steal `d51eef3 `_ without attribution. diff --git a/pyrogram/methods/chats/__init__.py b/pyrogram/methods/chats/__init__.py index 4029f5eeeb..f2d3025d58 100644 --- a/pyrogram/methods/chats/__init__.py +++ b/pyrogram/methods/chats/__init__.py @@ -42,6 +42,7 @@ from .pin_chat_message import PinChatMessage from .promote_chat_member import PromoteChatMember from .restrict_chat_member import RestrictChatMember +from .search_chats import SearchChats from .set_administrator_title import SetAdministratorTitle from .set_chat_description import SetChatDescription from .set_chat_permissions import SetChatPermissions @@ -66,6 +67,7 @@ class Chats( BanChatMember, UnbanChatMember, RestrictChatMember, + SearchChats, PromoteChatMember, GetChatMembers, GetChatMember, diff --git a/pyrogram/methods/chats/search_chats.py b/pyrogram/methods/chats/search_chats.py new file mode 100644 index 0000000000..d5d3e61a9d --- /dev/null +++ b/pyrogram/methods/chats/search_chats.py @@ -0,0 +1,81 @@ +# 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 Union + +import pyrogram +from pyrogram import raw, types, utils + + +class SearchChats: + async def search_chats( + self: "pyrogram.Client", + query: str, + limit: int = 10, + personalize_result: bool = False + ) -> bool: + """Searches for the specified query in the title and username of already known chats via request to the server. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + query (``str``): + Query to search for. + + limit (``int``, *optional*): + The maximum number of chats to be returned. Defaults to 10. + + personalize_result (``bool``, *optional*): + True, if should return personalized results, else would return all found user identifiers. Defaults to False. + + Returns: + List[:obj:`~pyrogram.types.Chat`]: Returns chats in the order seen in the main chat list + + Example: + .. code-block:: python + + chats = await app.search_chats("Pyrogram") + """ + r = await self.invoke( + raw.functions.contacts.Search( + q=query, + limit=limit + ) + ) + users = {i.id: i for i in r.users} + chats = {i.id: i for i in r.chats} + c = [] + attr = "my_results" if personalize_result else "results" + m = getattr(r, attr, []) + for o in m: + id = utils.get_raw_peer_id(o) + if isinstance(o, raw.types.PeerUser): + c.append( + types.Chat._parse_chat( + self, + users[id] + ) + ) + else: + c.append( + types.Chat._parse_chat( + self, + chats[id] + ) + ) + return types.List(c) From 56997dbe8a4a36959b67bd95b9a15734275c2fab Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 26 Apr 2024 21:42:08 +0200 Subject: [PATCH 008/154] Fix unused bugs in get_reply_message_parameters --- pyrogram/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/utils.py b/pyrogram/utils.py index 0f06e4ca6d..ad4243ce2a 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -506,9 +506,9 @@ async def _get_reply_message_parameters( reply_to.quote_text = message reply_to.quote_entities = entities if reply_parameters.chat_id: - reply_to.reply_to_peer_id = await client.resolve_peer(chat_id) + reply_to.reply_to_peer_id = await client.resolve_peer(reply_parameters.chat_id) if reply_parameters.quote_position: - reply_to.quote_offset = quote_position + reply_to.quote_offset = reply_parameters.quote_position return reply_to From 2429389d791d6c0d81c23d3d0a81845c75c6afe0 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 26 Apr 2024 21:54:04 +0200 Subject: [PATCH 009/154] Update API scheme to layer 179. --- compiler/api/source/main_api.tl | 9 ++++++--- docs/source/releases/changes-in-this-fork.rst | 5 +++++ pyrogram/methods/messages/send_poll.py | 2 ++ pyrogram/methods/messages/stop_poll.py | 1 + 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 34d02b86a4..4bbc1b2bb4 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -781,6 +781,8 @@ auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true go auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; auth.sentCodeTypeFirebaseSms#e57b1432 flags:# nonce:flags.0?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; +auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; +auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; @@ -1172,9 +1174,9 @@ help.supportName#8c05f1c9 name:string = help.SupportName; help.userInfoEmpty#f3ae2eed = help.UserInfo; help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; -pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer; +pollAnswer#ff16e2ca text:TextWithEntities option:bytes = PollAnswer; -poll#86e18161 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector close_period:flags.4?int close_date:flags.5?int = Poll; +poll#58747131 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int = Poll; pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters; @@ -1831,6 +1833,7 @@ auth.checkRecoveryPassword#d36bf79 code:string = Bool; auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; auth.requestFirebaseSms#89464b50 flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string ios_push_secret:flags.1?string = Bool; auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; +auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; @@ -2451,4 +2454,4 @@ test.useError = Error; test.useConfigSimple = help.ConfigSimple; test.parseInputAppEvent = InputAppEvent; -// LAYER 178 +// LAYER 179 diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index ca1db3de14..43b293530a 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -8,6 +8,11 @@ it can take advantage of new goodies! `For a more detailed description, please check the commits. `_ ++------------------------+ +| Scheme layer used: 179 | ++------------------------+ + + +------------------------+ | Scheme layer used: 178 | +------------------------+ diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index f4aa5d4680..130d0e2148 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -171,8 +171,10 @@ async def send_poll( media=raw.types.InputMediaPoll( poll=raw.types.Poll( id=self.rnd_id(), + # TODO question=question, answers=[ + # TODO raw.types.PollAnswer(text=text, option=bytes([i])) for i, text in enumerate(options) ], diff --git a/pyrogram/methods/messages/stop_poll.py b/pyrogram/methods/messages/stop_poll.py index 7129f92c3d..0726b1c159 100644 --- a/pyrogram/methods/messages/stop_poll.py +++ b/pyrogram/methods/messages/stop_poll.py @@ -69,6 +69,7 @@ async def stop_poll( poll=raw.types.Poll( id=int(poll.id), closed=True, + # TODO question="", answers=[] ) From 212701a9bde06399fe402442303e1646c35adc5c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 27 Apr 2024 05:02:51 +0200 Subject: [PATCH 010/154] Support sending Poll question and options with entities support Server only seems to allow CUSTOM_EMOJI entities at the moment. --- pyrogram/methods/messages/send_poll.py | 33 ++++++++++++++++++----- pyrogram/methods/messages/stop_poll.py | 1 - pyrogram/types/messages_and_media/poll.py | 5 ++-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index 130d0e2148..5e12f5c4e4 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -166,18 +166,37 @@ async def send_poll( message_thread_id, reply_parameters ) + + # TODO: wait for BOT API update? + question, question_entities = (await utils.parse_text_entities(self, question, None, None)).values() + if not question_entities: + question_entities = [] + + answers = [] + for i, answer_ in enumerate(options): + answer, answer_entities = (await utils.parse_text_entities(self, answer_, None, None)).values() + if not answer_entities: + answer_entities = [] + answers.append( + raw.types.PollAnswer( + text=raw.types.TextWithEntities( + text=answer, + entities=answer_entities + ), + option=bytes([i]) + ) + ) + rpc = raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=raw.types.InputMediaPoll( poll=raw.types.Poll( id=self.rnd_id(), - # TODO - question=question, - answers=[ - # TODO - raw.types.PollAnswer(text=text, option=bytes([i])) - for i, text in enumerate(options) - ], + question=raw.types.TextWithEntities( + text=question, + entities=question_entities + ), + answers=answers, closed=is_closed, public_voters=not is_anonymous, multiple_choice=allows_multiple_answers, diff --git a/pyrogram/methods/messages/stop_poll.py b/pyrogram/methods/messages/stop_poll.py index 0726b1c159..7129f92c3d 100644 --- a/pyrogram/methods/messages/stop_poll.py +++ b/pyrogram/methods/messages/stop_poll.py @@ -69,7 +69,6 @@ async def stop_poll( poll=raw.types.Poll( id=int(poll.id), closed=True, - # TODO question="", answers=[] ) diff --git a/pyrogram/types/messages_and_media/poll.py b/pyrogram/types/messages_and_media/poll.py index 025e36390e..b830ba1846 100644 --- a/pyrogram/types/messages_and_media/poll.py +++ b/pyrogram/types/messages_and_media/poll.py @@ -24,6 +24,7 @@ from pyrogram import types from ..object import Object from ..update import Update +from .message import Str class Poll(Object, Update): @@ -137,7 +138,7 @@ def _parse(client, media_poll: Union["raw.types.MessageMediaPoll", "raw.types.Up options.append( types.PollOption( - text=answer.text, + text=Str(answer.text.text).init(answer.text.entities), voter_count=voter_count, data=answer.option, client=client @@ -146,7 +147,7 @@ def _parse(client, media_poll: Union["raw.types.MessageMediaPoll", "raw.types.Up return Poll( id=str(poll.id), - question=poll.question, + question=Str(poll.question.text).init(poll.question.entities), options=options, total_voter_count=media_poll.results.total_voters, is_closed=poll.closed, From d2f69a6773bf137a0dbfb3546163de33170d0368 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 27 Apr 2024 05:07:44 +0200 Subject: [PATCH 011/154] Bump Version --- docs/source/releases/changes-in-this-fork.rst | 2 ++ pyrogram/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 43b293530a..533e63907e 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,8 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- `ℹ️ Blog Post `_ +- `View new and changed raw API methods `__. +------------------------+ | Scheme layer used: 178 | diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 7831ea6ce3..a741556e7c 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -__version__ = "2.1.25" +__version__ = "2.1.26" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From dc132bb1d7db3b0ea191e3ea0f2fa6edc48ac6a8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 27 Apr 2024 06:11:04 +0200 Subject: [PATCH 012/154] Fix bug in poll unparse --- pyrogram/types/messages_and_media/poll.py | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/messages_and_media/poll.py b/pyrogram/types/messages_and_media/poll.py index b830ba1846..aa04eb65d4 100644 --- a/pyrogram/types/messages_and_media/poll.py +++ b/pyrogram/types/messages_and_media/poll.py @@ -136,18 +136,38 @@ def _parse(client, media_poll: Union["raw.types.MessageMediaPoll", "raw.types.Up if result.correct: correct_option_id = i + entities = [ + types.MessageEntity._parse( + client, + entity, + {} # there isn't a TEXT_MENTION entity available yet + ) + for entity in (answer.text.entities or []) + ] + entities = types.List(filter(lambda x: x is not None, entities)) + options.append( types.PollOption( - text=Str(answer.text.text).init(answer.text.entities), + text=Str(answer.text.text).init(entities), voter_count=voter_count, data=answer.option, client=client ) ) + entities = [ + types.MessageEntity._parse( + client, + entity, + {} # there isn't a TEXT_MENTION entity available yet + ) + for entity in (poll.question.entities or []) + ] + entities = types.List(filter(lambda x: x is not None, entities)) + return Poll( id=str(poll.id), - question=Str(poll.question.text).init(poll.question.entities), + question=Str(poll.question.text).init(entities), options=options, total_voter_count=media_poll.results.total_voters, is_closed=poll.closed, From 06ceb3d2322aea5e84ea2d20ebe23bf91db534bd Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 27 Apr 2024 12:13:44 +0200 Subject: [PATCH 013/154] Add reverse parameter to get_chat_history --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/get_chat_history.py | 23 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 533e63907e..3d6903b79a 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added ``reverse`` parameter to :meth:`~pyrogram.Client.get_chat_history`. (`855e69e `_, `a086b49 `_) - `ℹ️ Blog Post `_ - `View new and changed raw API methods `__. diff --git a/pyrogram/methods/messages/get_chat_history.py b/pyrogram/methods/messages/get_chat_history.py index 25a759b993..6fb8ca0e51 100644 --- a/pyrogram/methods/messages/get_chat_history.py +++ b/pyrogram/methods/messages/get_chat_history.py @@ -33,6 +33,7 @@ async def get_chunk( max_id: int = 0, from_message_id: int = 0, from_date: datetime = utils.zero_datetime(), + reverse: bool = False, is_scheduled: bool = False ): if is_scheduled: @@ -43,19 +44,23 @@ async def get_chunk( ), sleep_threshold=60 ) - return await utils.parse_messages( + messages = await utils.parse_messages( client, r, is_scheduled=True, replies=0 ) + if reverse: + messages.reverse() + return messages else: + from_message_id = from_message_id or (1 if reverse else 0) messages = await client.invoke( raw.functions.messages.GetHistory( peer=await client.resolve_peer(chat_id), offset_id=from_message_id, offset_date=utils.datetime_to_timestamp(from_date), - add_offset=offset, + add_offset=offset * (-1 if reverse else 1) - (limit if reverse else 0), limit=limit, max_id=max_id, min_id=min_id, @@ -63,13 +68,15 @@ async def get_chunk( ), sleep_threshold=60 ) - - return await utils.parse_messages( + messages =await utils.parse_messages( client, messages, is_scheduled=False, replies=0 ) + if reverse: + messages.reverse() + return messages class GetChatHistory: @@ -82,6 +89,7 @@ async def get_chat_history( min_id: int = 0, max_id: int = 0, offset_date: datetime = utils.zero_datetime(), + reverse: bool = False, is_scheduled: bool = False ) -> Optional[AsyncGenerator["types.Message", None]]: """Get messages from a chat history. @@ -118,8 +126,12 @@ async def get_chat_history( offset_date (:py:obj:`~datetime.datetime`, *optional*): Pass a date as offset to retrieve only older messages starting from that date. + reverse (``bool``, *optional*): + Pass True to retrieve the messages in reversed order (from older to most recent). Defaults to False. + is_scheduled (``bool``, *optional*): Whether to get scheduled messages. Defaults to False. + Returns: ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. @@ -143,13 +155,14 @@ async def get_chat_history( min_id=min_id, max_id=max_id, from_date=offset_date, + reverse=reverse, is_scheduled=is_scheduled ) if not messages: return - offset_id = messages[-1].id + offset_id = messages[-1].id + (1 if reverse else 0) for message in messages: yield message From 44d47c704113a3be3799a6e7380e699e7fd1fdb8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 27 Apr 2024 12:27:11 +0200 Subject: [PATCH 014/154] Try to Fix _parse for Expired Media --- pyrogram/types/messages_and_media/message.py | 13 ++++++++++++ pyrogram/types/messages_and_media/video.py | 20 +++++++++---------- .../types/messages_and_media/video_note.py | 16 +++++++-------- pyrogram/types/messages_and_media/voice.py | 14 ++++++------- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index aa5d17126b..a31e024346 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1052,6 +1052,19 @@ async def _parse( else: document = types.Document._parse(client, doc, file_name) media_type = enums.MessageMediaType.DOCUMENT + + elif doc is None: + has_media_spoiler = media.spoiler + if media.video: + video = types.Video._parse(client, doc, None, None, media.ttl_seconds) + media_type = enums.MessageMediaType.VIDEO + elif media.round: + video_note = types.VideoNote._parse(client, doc, None, media.ttl_seconds) + media_type = enums.MessageMediaType.VIDEO_NOTE + elif media.voice: + voice = types.Voice._parse(client, doc, None, media.ttl_seconds) + media_type = enums.MessageMediaType.VOICE + elif isinstance(media, raw.types.MessageMediaWebPage): if isinstance(media.webpage, raw.types.WebPage): web_page = types.WebPage._parse(client, media.webpage) diff --git a/pyrogram/types/messages_and_media/video.py b/pyrogram/types/messages_and_media/video.py index b50f9fca78..7b1149705e 100644 --- a/pyrogram/types/messages_and_media/video.py +++ b/pyrogram/types/messages_and_media/video.py @@ -115,20 +115,20 @@ def _parse( media_id=video.id, access_hash=video.access_hash, file_reference=video.file_reference - ).encode(), + ).encode() if video else None, file_unique_id=FileUniqueId( file_unique_type=FileUniqueType.DOCUMENT, media_id=video.id - ).encode(), - width=video_attributes.w, - height=video_attributes.h, - duration=video_attributes.duration, + ).encode() if video else None, + width=video_attributes.w if video_attributes else None, + height=video_attributes.h if video_attributes else None, + duration=video_attributes.duration if video_attributes else None, file_name=file_name, - mime_type=video.mime_type, - supports_streaming=video_attributes.supports_streaming, - file_size=video.size, - date=utils.timestamp_to_datetime(video.date), + mime_type=video.mime_type if video else None, + supports_streaming=video_attributes.supports_streaming if video_attributes else None, + file_size=video.size if video else None, + date=utils.timestamp_to_datetime(video.date) if video else None, ttl_seconds=ttl_seconds, - thumbs=types.Thumbnail._parse(client, video), + thumbs=types.Thumbnail._parse(client, video) if video else None, client=client ) diff --git a/pyrogram/types/messages_and_media/video_note.py b/pyrogram/types/messages_and_media/video_note.py index 9aa70449fa..e438484bdd 100644 --- a/pyrogram/types/messages_and_media/video_note.py +++ b/pyrogram/types/messages_and_media/video_note.py @@ -99,17 +99,17 @@ def _parse( media_id=video_note.id, access_hash=video_note.access_hash, file_reference=video_note.file_reference - ).encode(), + ).encode() if video_note else None, file_unique_id=FileUniqueId( file_unique_type=FileUniqueType.DOCUMENT, media_id=video_note.id - ).encode(), - length=video_attributes.w, - duration=video_attributes.duration, - file_size=video_note.size, - mime_type=video_note.mime_type, - date=utils.timestamp_to_datetime(video_note.date), + ).encode() if video_note else None, + length=video_attributes.w if video_attributes else None, + duration=video_attributes.duration if video_attributes else None, + file_size=video_note.size if video_note else None, + mime_type=video_note.mime_type if video_note else None, + date=utils.timestamp_to_datetime(video_note.date) if video_note else None, ttl_seconds=ttl_seconds, - thumbs=types.Thumbnail._parse(client, video_note), + thumbs=types.Thumbnail._parse(client, video_note) if video_note else None, client=client ) diff --git a/pyrogram/types/messages_and_media/voice.py b/pyrogram/types/messages_and_media/voice.py index adceafb7f1..65f2c850d3 100644 --- a/pyrogram/types/messages_and_media/voice.py +++ b/pyrogram/types/messages_and_media/voice.py @@ -87,16 +87,16 @@ def _parse(client, voice: "raw.types.Document", attributes: "raw.types.DocumentA media_id=voice.id, access_hash=voice.access_hash, file_reference=voice.file_reference - ).encode(), + ).encode() if voice else None, file_unique_id=FileUniqueId( file_unique_type=FileUniqueType.DOCUMENT, media_id=voice.id - ).encode(), - duration=attributes.duration, - mime_type=voice.mime_type, - file_size=voice.size, - waveform=attributes.waveform, - date=utils.timestamp_to_datetime(voice.date), + ).encode() if voice else None, + duration=attributes.duration if attributes else None, + mime_type=voice.mime_type if voice else None, + file_size=voice.size if voice else None, + waveform=attributes.waveform if attributes else None, + date=utils.timestamp_to_datetime(voice.date) if voice else None, ttl_seconds=ttl_seconds, client=client ) From 89f6dc708cd92494f4fd12cbd90d679e8564c5d2 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 27 Apr 2024 14:34:40 +0200 Subject: [PATCH 015/154] Add get_collectible_item_info (KurimuzonAkuma/pyrogram#45) --- compiler/docs/compiler.py | 3 +- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/business/__init__.py | 2 + .../business/get_collectible_item_info.py | 69 ++++++++++++++++ pyrogram/types/business/__init__.py | 2 + .../types/business/collectible_item_info.py | 79 +++++++++++++++++++ 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/business/get_collectible_item_info.py create mode 100644 pyrogram/types/business/collectible_item_info.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index f2886d4e39..e52d8b652f 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -361,8 +361,9 @@ def get_title_list(s: str) -> list: set_personal_chat """, business=""" - Telegram Business + Telegram Business & Fragment get_business_connection + get_collectible_item_info """, ) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 3d6903b79a..52180284ee 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added :meth:`~pyrogram.Client.get_collectible_item_info`. - Added ``reverse`` parameter to :meth:`~pyrogram.Client.get_chat_history`. (`855e69e `_, `a086b49 `_) - `ℹ️ Blog Post `_ - `View new and changed raw API methods `__. diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index eda3b7f03f..3825b2dfa0 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -17,9 +17,11 @@ # along with Pyrogram. If not, see . from .get_business_connection import GetBusinessConnection +from .get_collectible_item_info import GetCollectibleItemInfo class TelegramBusiness( GetBusinessConnection, + GetCollectibleItemInfo, ): pass diff --git a/pyrogram/methods/business/get_collectible_item_info.py b/pyrogram/methods/business/get_collectible_item_info.py new file mode 100644 index 0000000000..8fb93065a3 --- /dev/null +++ b/pyrogram/methods/business/get_collectible_item_info.py @@ -0,0 +1,69 @@ +# 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 . + +import pyrogram +from pyrogram import raw, types + + +class GetCollectibleItemInfo: + async def get_collectible_item_info( + self: "pyrogram.Client", + username: str = None, + phone_number: str = None + ) -> "types.CollectibleInfo": + """Returns information about a given collectible item that was purchased at https://fragment.com + + .. include:: /_includes/usable-by/users.rst + + You must use exactly one of ``username`` OR ``phone_number``. + + Parameters: + username (``str``, *optional*): + Describes a collectible username that can be purchased at https://fragment.com + + phone_number (``str``, *optional*): + Describes a collectible phone number that can be purchased at https://fragment.com + + Returns: + :obj:`~pyrogram.types.CollectibleInfo`: On success, a collectible info is returned. + + Example: + .. code-block:: python + + username = await app.get_collectible_item_info(username="nerd") + print(username) + """ + + input_collectible = None + + if username: + input_collectible = raw.types.InputCollectibleUsername(username=username) + elif phone_number: + input_collectible = raw.types.InputCollectiblePhone(phone=phone_number) + else: + raise ValueError( + "No argument supplied. Either pass username OR phone_number" + ) + + r = await self.invoke( + raw.functions.fragment.GetCollectibleInfo( + collectible=input_collectible + ) + ) + + return types.CollectibleItemInfo._parse(r) diff --git a/pyrogram/types/business/__init__.py b/pyrogram/types/business/__init__.py index 1ff4c93531..1078ef8908 100644 --- a/pyrogram/types/business/__init__.py +++ b/pyrogram/types/business/__init__.py @@ -21,6 +21,7 @@ from .business_location import BusinessLocation from .business_opening_hours import BusinessOpeningHours from .business_opening_hours_interval import BusinessOpeningHoursInterval +from .collectible_item_info import CollectibleItemInfo __all__ = [ "BusinessConnection", @@ -28,4 +29,5 @@ "BusinessLocation", "BusinessOpeningHours", "BusinessOpeningHoursInterval", + "CollectibleItemInfo", ] diff --git a/pyrogram/types/business/collectible_item_info.py b/pyrogram/types/business/collectible_item_info.py new file mode 100644 index 0000000000..48608f6267 --- /dev/null +++ b/pyrogram/types/business/collectible_item_info.py @@ -0,0 +1,79 @@ +# 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 datetime import datetime + +from pyrogram import raw, utils +from ..object import Object + + +class CollectibleItemInfo(Object): + """Contains information about a collectible item and its last purchase. + + Parameters: + purchase_date (``datetime``): + Point in time (Unix timestamp) when the item was purchased + + currency (``str``): + Currency for the paid amount + + amount (``float``): + The paid amount, in the smallest units of the currency + + cryptocurrency (``str``): + Cryptocurrency used to pay for the item + + cryptocurrency_amount (``float``): + The paid amount, in the smallest units of the cryptocurrency + + url (``str``): + Individual URL for the item on https://fragment.com + + """ + + def __init__( + self, + *, + purchase_date : datetime, + currency : str, + amount: float, + cryptocurrency: str, + cryptocurrency_amount: float, + url: str + ): + super().__init__() + + self.purchase_date = purchase_date + self.currency= currency + self.amount = amount + self.cryptocurrency = cryptocurrency + self.cryptocurrency_amount = cryptocurrency_amount + self.url = url + + @staticmethod + def _parse( + collectible_info: "raw.types.fragment.CollectibleInfo" + ) -> "CollectibleItemInfo": + return CollectibleItemInfo( + purchase_date=utils.timestamp_to_datetime(collectible_info.purchase_date), + currency=collectible_info.currency, + amount=collectible_info.amount, + cryptocurrency=collectible_info.crypto_currency, + cryptocurrency_amount=collectible_info.crypto_amount, + url=collectible_info.url + ) From bf4bb78e3dbb5d61138a255b09ca8833d2056cc8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 28 Apr 2024 04:53:37 +0200 Subject: [PATCH 016/154] Add revoke_messages to ban_chat_member pyrogram/pyrogram#1421 --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/chats/ban_chat_member.py | 10 ++++++++-- pyrogram/types/user_and_chats/chat.py | 10 ++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 52180284ee..dcd2e8d9f2 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added ``revoke_messages`` parameter to :meth:`~pyrogram.Client.ban_chat_member` and :meth:`~pyrogram.types.Chat.ban_member`. - Added :meth:`~pyrogram.Client.get_collectible_item_info`. - Added ``reverse`` parameter to :meth:`~pyrogram.Client.get_chat_history`. (`855e69e `_, `a086b49 `_) - `ℹ️ Blog Post `_ diff --git a/pyrogram/methods/chats/ban_chat_member.py b/pyrogram/methods/chats/ban_chat_member.py index 635c48b5da..37556dc70d 100644 --- a/pyrogram/methods/chats/ban_chat_member.py +++ b/pyrogram/methods/chats/ban_chat_member.py @@ -29,7 +29,8 @@ async def ban_chat_member( self: "pyrogram.Client", chat_id: Union[int, str], user_id: Union[int, str], - until_date: datetime = utils.zero_datetime() + until_date: datetime = utils.zero_datetime(), + revoke_messages: bool = None ) -> Union["types.Message", bool]: """Ban a user from a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the group on their own using @@ -56,6 +57,10 @@ async def ban_chat_member( If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Defaults to epoch (ban forever). + revoke_messages (``bool``, *optional*): + Pass True to delete all messages from the chat for the user that is being removed. If False, the user will be able to see messages in the group that were sent before the user was removed. + Always True for supergroups and channels. + Returns: :obj:`~pyrogram.types.Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in case a message object couldn't be returned, True is returned. @@ -96,7 +101,8 @@ async def ban_chat_member( r = await self.invoke( raw.functions.messages.DeleteChatUser( chat_id=abs(chat_id), - user_id=user_peer + user_id=user_peer, + revoke_history=revoke_messages ) ) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 9437d5b272..42cb268584 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -859,7 +859,8 @@ async def set_ttl(self, ttl_seconds: int) -> "types.Message": async def ban_member( self, user_id: Union[int, str], - until_date: datetime = utils.zero_datetime() + until_date: datetime = utils.zero_datetime(), + revoke_messages: bool = None ) -> Union["types.Message", bool]: """Bound method *ban_member* of :obj:`~pyrogram.types.Chat`. @@ -892,6 +893,10 @@ async def ban_member( If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Defaults to epoch (ban forever). + revoke_messages (``bool``, *optional*): + Pass True to delete all messages from the chat for the user that is being removed. If False, the user will be able to see messages in the group that were sent before the user was removed. + Always True for supergroups and channels. + Returns: :obj:`~pyrogram.types.Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in case a message object couldn't be returned, True is returned. @@ -903,7 +908,8 @@ async def ban_member( return await self._client.ban_chat_member( chat_id=self.id, user_id=user_id, - until_date=until_date + until_date=until_date, + revoke_messages=revoke_messages ) async def unban_member( From cd17bf4d7089255be6b9d57435c7db0578fc05f5 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 28 Apr 2024 10:52:55 +0200 Subject: [PATCH 017/154] Fix for copy_message in case of Poll --- pyrogram/types/messages_and_media/message.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index a31e024346..1c9aa1e0d3 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -3984,7 +3984,7 @@ async def copy( schedule_date=schedule_date, protect_content=self.has_protected_content, reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup + reply_markup=self.reply_markup if reply_markup is object else reply_markup ) elif self.location: return await self._client.send_location( @@ -3998,7 +3998,7 @@ async def copy( schedule_date=schedule_date, protect_content=self.has_protected_content, reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup + reply_markup=self.reply_markup if reply_markup is object else reply_markup ) elif self.venue: return await self._client.send_venue( @@ -4016,13 +4016,15 @@ async def copy( schedule_date=schedule_date, protect_content=self.has_protected_content, reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup + reply_markup=self.reply_markup if reply_markup is object else reply_markup ) elif self.poll: - return await self._client.send_poll( + oldpm = self._client.parse_mode + self._client.set_parse_mode(enums.ParseMode.HTML) + cm = await self._client.send_poll( chat_id, - question=self.poll.question, - options=[opt.text for opt in self.poll.options], + question=self.poll.question.html, + options=[opt.text.html for opt in self.poll.options], is_anonymous=self.poll.is_anonymous, type=self.poll.type, allows_multiple_answers=self.poll.allows_multiple_answers, @@ -4038,8 +4040,10 @@ async def copy( business_connection_id=self.business_connection_id, schedule_date=schedule_date, reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup + reply_markup=self.reply_markup if reply_markup is object else reply_markup ) + self._client.set_parse_mode(oldpm) + return cm elif self.game: return await self._client.send_game( chat_id, @@ -4050,7 +4054,7 @@ async def copy( business_connection_id=self.business_connection_id, reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup + reply_markup=self.reply_markup if reply_markup is object else reply_markup ) else: raise ValueError("Unknown media type") From 14cff9333f194523b30c4dfa4be0c09a44aee17f Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 28 Apr 2024 16:38:28 +0200 Subject: [PATCH 018/154] Fix missing await at one place --- pyrogram/types/messages_and_media/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 1c9aa1e0d3..f7153ff0a1 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1240,7 +1240,7 @@ async def _parse( if business_connection_id: parsed_message.business_connection_id = business_connection_id if raw_reply_to_message: - parsed_message.reply_to_message = types.Message._parse( + parsed_message.reply_to_message = await types.Message._parse( client, raw_reply_to_message, users, From 2ebe36e20b0fd11df9cd97c94ed9c368d6aea78b Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 30 Apr 2024 18:04:03 +0200 Subject: [PATCH 019/154] Fix edge case in Pinned Recent Action KurimuzonAkuma/pyrogram#49 --- pyrogram/types/user_and_chats/chat_event.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pyrogram/types/user_and_chats/chat_event.py b/pyrogram/types/user_and_chats/chat_event.py index 88ff42f343..22f1cdac48 100644 --- a/pyrogram/types/user_and_chats/chat_event.py +++ b/pyrogram/types/user_and_chats/chat_event.py @@ -406,12 +406,13 @@ async def _parse( elif isinstance(action, raw.types.ChannelAdminLogEventActionUpdatePinned): message = action.message - if message.pinned: - pinned_message = await types.Message._parse(client, message, users, chats) - action = enums.ChatEventAction.MESSAGE_PINNED - else: - unpinned_message = await types.Message._parse(client, message, users, chats) - action = enums.ChatEventAction.MESSAGE_UNPINNED + if isinstance(action.message, raw.types.Message): + if message.pinned: + pinned_message = await types.Message._parse(client, message, users, chats) + action = enums.ChatEventAction.MESSAGE_PINNED + else: + unpinned_message = await types.Message._parse(client, message, users, chats) + action = enums.ChatEventAction.MESSAGE_UNPINNED elif isinstance(action, raw.types.ChannelAdminLogEventActionExportedInviteEdit): old_invite_link = types.ChatInviteLink._parse(client, action.prev_invite, users) From be8b2d52f0dcd2ee6e4947750099cfa21e9dcfe0 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 30 Apr 2024 18:56:25 +0200 Subject: [PATCH 020/154] Add full_name to Chat and User --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/types/user_and_chats/chat.py | 15 ++++++++++ pyrogram/types/user_and_chats/user.py | 28 +++++++++++++++---- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index dcd2e8d9f2..93fba6d41b 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added ``full_name`` to :obj:`~pyrogram.types.Chat` and :obj:`~pyrogram.types.User` only for :obj:`~pyrogram.enums.ChatType.PRIVATE`. - Added ``revoke_messages`` parameter to :meth:`~pyrogram.Client.ban_chat_member` and :meth:`~pyrogram.types.Chat.ban_member`. - Added :meth:`~pyrogram.Client.get_collectible_item_info`. - Added ``reverse`` parameter to :meth:`~pyrogram.Client.get_chat_history`. (`855e69e `_, `a086b49 `_) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 42cb268584..8e0d80f7b9 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -200,6 +200,9 @@ class Chat(Object): is_peak_preview (``bool``, *optional*): True, if this is a peak preview. + full_name (``str``, *property*): + Full name of the other party in a private chat, for private chats and bots. + """ def __init__( @@ -649,6 +652,18 @@ def _parse_chat_preview(client, chat_invite: "raw.types.ChatInvite") -> "Chat": client=client ) + @property + def full_name(self) -> str: + return " ".join( + filter( + None, + [ + self.first_name, + self.last_name + ] + ) + ) or None + async def archive(self): """Bound method *archive* of :obj:`~pyrogram.types.Chat`. diff --git a/pyrogram/types/user_and_chats/user.py b/pyrogram/types/user_and_chats/user.py index 3e81086d43..1a386214cc 100644 --- a/pyrogram/types/user_and_chats/user.py +++ b/pyrogram/types/user_and_chats/user.py @@ -141,12 +141,6 @@ class User(Object, Update): The list of reasons why this bot might be unavailable to some users. This field is available only in case *is_restricted* is True. - mention (``str``, *property*): - Generate a text mention for this user. - You can use ``user.mention()`` to mention the user using their first name (styled using html), or - ``user.mention("another name")`` for a custom name. To choose a different style - ("HTML" or "MARKDOWN") use ``user.mention(style=ParseMode.MARKDOWN)``. - is_bot (``bool``, *optional*): True, if this user is a bot. @@ -185,6 +179,16 @@ class User(Object, Update): profile_color (:obj:`~pyrogram.types.ChatColor`, *optional*): Chat profile color. + + mention (``str``, *property*): + Generate a text mention for this user. + You can use ``user.mention()`` to mention the user using their first name (styled using html), or + ``user.mention("another name")`` for a custom name. To choose a different style + ("HTML" or "MARKDOWN") use ``user.mention(style=ParseMode.MARKDOWN)``. + + full_name (``str``, *property*): + Full name of the other party in a private chat, for private chats and bots. + """ def __init__( @@ -281,6 +285,18 @@ def mention(self): self._client.parse_mode ) + @property + def full_name(self) -> str: + return " ".join( + filter( + None, + [ + self.first_name, + self.last_name + ] + ) + ) or None + @staticmethod def _parse(client, user: "raw.base.User") -> Optional["User"]: if user is None: From 57089014e59c61a28627a62d19494e7e9d69ae37 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 30 Apr 2024 19:12:09 +0200 Subject: [PATCH 021/154] Bump Version --- docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 93fba6d41b..91dfc885ee 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -6,7 +6,7 @@ in reverse chronological order. You should read this when upgrading to this fork to know where your code can break, and where it can take advantage of new goodies! -`For a more detailed description, please check the commits. `_ +`For a more detailed description, please check the commits. `_ +------------------------+ | Scheme layer used: 179 | diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index a741556e7c..da924df55b 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -__version__ = "2.1.26" +__version__ = "2.1.27" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 0909fff64d25e4f6ae254f315ff911572fd713c8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 1 May 2024 14:11:24 +0200 Subject: [PATCH 022/154] Update API scheme to layer 179. --- compiler/api/source/main_api.tl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 4bbc1b2bb4..a4374932c2 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -1542,6 +1542,8 @@ emojiListNotModified#481eadfa = EmojiList; emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; +emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; +emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; @@ -1785,7 +1787,7 @@ channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options: channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; -stats.broadcastRevenueStats#d07b4bad top_hours_graph:StatsGraph revenue_graph:StatsGraph current_balance:long available_balance:long overall_revenue:long usd_rate:double = stats.BroadcastRevenueStats; +stats.broadcastRevenueStats#5407e297 top_hours_graph:StatsGraph revenue_graph:StatsGraph balances:BroadcastRevenueBalances usd_rate:double = stats.BroadcastRevenueStats; stats.broadcastRevenueWithdrawalUrl#ec659737 url:string = stats.BroadcastRevenueWithdrawalUrl; @@ -1800,6 +1802,8 @@ reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; +broadcastRevenueBalances#8438f1c6 current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2188,6 +2192,7 @@ messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vecto messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; +messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; 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; From b845b12dd7f5d402dbee2796c8e28c9823f139bd Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 1 May 2024 14:16:30 +0200 Subject: [PATCH 023/154] Bump Version --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index da924df55b..d7fa145b05 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -__version__ = "2.1.27" +__version__ = "2.1.28" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From bf2dcbb3a3b2ce48d3c1c569e4672026197a225b Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 05:52:42 +0200 Subject: [PATCH 024/154] Fix condition for captions in copy_media_group https://t.me/pyrogramchat/615594 --- pyrogram/methods/messages/copy_media_group.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyrogram/methods/messages/copy_media_group.py b/pyrogram/methods/messages/copy_media_group.py index dbc6206443..6c608030f3 100644 --- a/pyrogram/methods/messages/copy_media_group.py +++ b/pyrogram/methods/messages/copy_media_group.py @@ -127,11 +127,13 @@ async def copy_media_group( raw.types.InputSingleMedia( media=media, random_id=self.rnd_id(), + # TODO **await self.parser.parse( - captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else + captions[i] if isinstance(captions, list) and i < len(captions) and isinstance(captions[i], str) else captions if isinstance(captions, str) and i == 0 else message.caption if message.caption and message.caption != "None" and not type( - captions) is str else "") + captions) is str else "" + ) ) ) From 981ebd271c36edc03d7635718c2d3c3ed08fffb1 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 05:56:30 +0200 Subject: [PATCH 025/154] Fix type hint --- pyrogram/types/messages_and_media/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index f7153ff0a1..dc0da20bab 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -35,7 +35,7 @@ class Str(str): def __init__(self, *args): super().__init__() - self.entities = None + self.entities: Optional[List["types.MessageEntity"]] = None def init(self, entities): self.entities = entities From 66b5a34b87b5a14a7d8c053037aa990af64d2d0d Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 06:25:16 +0200 Subject: [PATCH 026/154] fix sleep optimize condition andfor new methods --- pyrogram/session/session.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 2e346f634d..7e619cc1ba 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -59,6 +59,12 @@ class Session: 444: "invalid DC" } + CUR_ALWD_INNR_QRYS = ( + raw.functions.InvokeWithoutUpdates, + raw.functions.InvokeWithTakeout, + raw.functions.InvokeWithBusinessConnection, + ) + def __init__( self, client: "pyrogram.Client", @@ -359,7 +365,7 @@ async def send(self, data: TLObject, wait_response: bool = True, timeout: float raise TimeoutError("Request timed out") if isinstance(result, raw.types.RpcError): - if isinstance(data, (raw.functions.InvokeWithoutUpdates, raw.functions.InvokeWithTakeout)): + if isinstance(data, Session.CUR_ALWD_INNR_QRYS): data = data.query RPCError.raise_it(result, type(data)) @@ -385,7 +391,7 @@ async def invoke( except asyncio.TimeoutError: pass - if isinstance(query, (raw.functions.InvokeWithoutUpdates, raw.functions.InvokeWithTakeout)): + if isinstance(query, Session.CUR_ALWD_INNR_QRYS): inner_query = query.query else: inner_query = query @@ -422,6 +428,6 @@ async def invoke( query_name, str(e) or repr(e) ) - await asyncio.sleep(0.5) + await asyncio.sleep(3) return await self.invoke(query, retries - 1, timeout) From 785ed3d300b96bf3ec0d9086def37e329a1e16b6 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 06:44:32 +0200 Subject: [PATCH 027/154] Attempt 4 at fixing message_thread_id parameter --- pyrogram/types/messages_and_media/message.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index dc0da20bab..e93e9ecf33 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1217,6 +1217,11 @@ async def _parse( parsed_message.message_thread_id = message.reply_to.reply_to_top_id if message.reply_to.forum_topic: parsed_message.is_topic_message = True + if message.reply_to.reply_to_top_id: + parsed_message.message_thread_id = message.reply_to.reply_to_top_id + else: + parsed_message.message_thread_id = message.reply_to.reply_to_msg_id + # TODO if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): parsed_message.reply_to_story = await types.Story._parse(client, chats, None, message.reply_to) From 330a198f1f9315998eba98fbe4b7672dbd49d8ae Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 13:48:38 +0200 Subject: [PATCH 028/154] Fix except error in send_message Ref: https://core.telegram.org/constructor/InputMediaWebpage --- pyrogram/methods/messages/send_message.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index daff719aa9..3cbb19dac6 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -197,7 +197,8 @@ async def send_message( media=raw.types.InputMediaWebPage( url=link_preview_options.url, force_large_media=link_preview_options.prefer_large_media, - force_small_media=link_preview_options.prefer_small_media + force_small_media=link_preview_options.prefer_small_media, + optional=True ), invert_media=link_preview_options.show_above_text, entities=entities, @@ -213,7 +214,7 @@ async def send_message( # await session.stop() else: r = await self.invoke(rpc) - except errors.WebpageNotFound: + except errors.MessageEmpty: if not message: raise ValueError( "Bad Request: text is empty" From 406b0e0dd13f14b2db93ac20c07f61bda7acc2c1 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 17:07:55 +0200 Subject: [PATCH 029/154] Added the field quote of type TextQuote to Message which contains the part of the replied message text or caption that is quoted in the current message. --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 1 + .../types/input_message_content/__init__.py | 2 + .../types/input_message_content/text_quote.py | 89 +++++++++++++++++++ pyrogram/types/messages_and_media/message.py | 17 +++- 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 pyrogram/types/input_message_content/text_quote.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index e52d8b652f..987b3eab61 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -495,6 +495,7 @@ def get_title_list(s: str) -> list: InputMessageContent InputTextMessageContent ReplyParameters + TextQuote """, messages_media=""" Messages & Media diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 91dfc885ee..a073c698c5 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added the class :obj:`~pyrogram.types.TextQuote` and the field ``quote`` of type :obj:`~pyrogram.types.TextQuote` to the class :obj:`~pyrogram.types.Message`, which contains the part of the replied message text or caption that is quoted in the current message. - Added ``full_name`` to :obj:`~pyrogram.types.Chat` and :obj:`~pyrogram.types.User` only for :obj:`~pyrogram.enums.ChatType.PRIVATE`. - Added ``revoke_messages`` parameter to :meth:`~pyrogram.Client.ban_chat_member` and :meth:`~pyrogram.types.Chat.ban_member`. - Added :meth:`~pyrogram.Client.get_collectible_item_info`. diff --git a/pyrogram/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py index 3accd6f9ff..f1696cbe52 100644 --- a/pyrogram/types/input_message_content/__init__.py +++ b/pyrogram/types/input_message_content/__init__.py @@ -20,10 +20,12 @@ from .input_text_message_content import InputTextMessageContent from .reply_parameters import ReplyParameters from .external_reply_info import ExternalReplyInfo +from .text_quote import TextQuote __all__ = [ "ExternalReplyInfo", "InputMessageContent", "InputTextMessageContent", "ReplyParameters", + "TextQuote", ] diff --git a/pyrogram/types/input_message_content/text_quote.py b/pyrogram/types/input_message_content/text_quote.py new file mode 100644 index 0000000000..74f10334fc --- /dev/null +++ b/pyrogram/types/input_message_content/text_quote.py @@ -0,0 +1,89 @@ +# 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 Optional, List, Union + +import pyrogram +from pyrogram import raw, types, utils, enums +from ..object import Object +from ..messages_and_media.message import Str + + +class TextQuote(Object): + """This object contains information about the quoted part of a message that is replied to by the given message. + + Parameters: + text (``str``): + Text of the quoted part of a message that is replied to by the given message + + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + Special entities that appear in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and custom_emoji entities are kept in quotes. + + position (``int``): + Approximate quote position in the original message in UTF-16 code units as specified by the sender + + is_manual (``bool``, *optional*): + True, if the quote was chosen manually by the message sender. Otherwise, the quote was added automatically by the server. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + text: str = None, + entities: List["types.MessageEntity"] = None, + position: int = None, + is_manual: bool = None + ): + super().__init__(client) + + self.text = text + self.entities = entities + self.position = position + self.is_manual = is_manual + + @staticmethod + def _parse( + client, + chats: dict, + users: dict, + reply_to: "raw.types.MessageReplyHeader" + ) -> "TextQuote": + if not getattr(reply_to, "quote", None): + return None + + if isinstance(reply_to, raw.types.MessageReplyHeader): + quote_text = reply_to.quote_text + quote_entities = reply_to.quote_entities + position = reply_to.quote_offset + + entities = [ + types.MessageEntity._parse(client, entity, users) + for entity in quote_entities + ] + entities = types.List( + filter(lambda x: x is not None, entities) + ) + + return TextQuote( + text=Str(quote_text).init(entities) or None, + entities=entities, + position=position, + # TODO + ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index e93e9ecf33..473caf8859 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -109,7 +109,11 @@ class Message(Object, Update): external_reply (:obj:`~pyrogram.types.ExternalReplyInfo`, *optional*): Information about the message that is being replied to, which may come from another chat or forum topic - quote + quote (:obj:`~pyrogram.types.TextQuote`, *optional*): + For replies that quote part of the original message, the quoted part of the message + + reply_to_story (:obj:`~pyrogram.types.Story`, *optional*): + For replies to a story, the original story via_bot (:obj:`~pyrogram.types.User`): The information of the bot that generated the message from an inline query of a user. @@ -401,7 +405,7 @@ def __init__( reply_to_message_id: int = None, reply_to_message: "Message" = None, external_reply: "types.ExternalReplyInfo" = None, - + quote: "types.TextQuote" = None, reply_to_story: "types.Story" = None, via_bot: "types.User" = None, edit_date: datetime = None, @@ -570,6 +574,7 @@ def __init__( self.is_topic_message = is_topic_message self.sender_boost_count = sender_boost_count self.boost_added = boost_added + self.quote = quote self.story = story self.reply_to_story = reply_to_story self.giveaway = giveaway @@ -1221,7 +1226,13 @@ async def _parse( parsed_message.message_thread_id = message.reply_to.reply_to_top_id else: parsed_message.message_thread_id = message.reply_to.reply_to_msg_id - # TODO + if message.reply_to.quote: + parsed_message.quote = types.TextQuote._parse( + client, + chats, + users, + message.reply_to + ) if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): parsed_message.reply_to_story = await types.Story._parse(client, chats, None, message.reply_to) From c58b688fb58071c15d1266cc4b6583910d64175b Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 5 May 2024 17:11:17 +0200 Subject: [PATCH 030/154] Bump Version --- pyrogram/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index d7fa145b05..8a11ef7325 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -16,7 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -__version__ = "2.1.28" +__fork_name__ = "pyrotgfork" +__version__ = "2.1.29" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From ff9e58c68aa72e150779d6f9c78855f0e5d9749d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81=C3=91=C3=91=C3=8DH=C3=8CL=C3=85T=C3=98R=20SP=C3=84R?= =?UTF-8?q?K?= <75305464+annihilatorrrr@users.noreply.github.com> Date: Mon, 6 May 2024 15:37:26 +0530 Subject: [PATCH 031/154] Fixed nonetype has nothing like date. (#21) --- pyrogram/types/messages_and_media/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 473caf8859..cea7530118 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -4693,6 +4693,6 @@ def forward_date(self) -> datetime: "This property is deprecated. " "Please use forward_origin instead" ) - return self.forward_origin.date + return getattr(self.forward_origin, "date", None) # END: the below properties were removed in `BOT API 7.0 `_ From a8dacd1aea2814aedbaaa2028ea6427e63cd4267 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Sun, 5 May 2024 19:42:29 +0300 Subject: [PATCH 032/154] Fix stop_poll method --- pyrogram/methods/messages/stop_poll.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/methods/messages/stop_poll.py b/pyrogram/methods/messages/stop_poll.py index 7129f92c3d..1ce6352641 100644 --- a/pyrogram/methods/messages/stop_poll.py +++ b/pyrogram/methods/messages/stop_poll.py @@ -69,7 +69,7 @@ async def stop_poll( poll=raw.types.Poll( id=int(poll.id), closed=True, - question="", + question=raw.types.TextWithEntities(text="", entities=[]), answers=[] ) ), From 02c726e5345f0f97094f7095ea53a572a4056887 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 6 May 2024 16:46:17 +0200 Subject: [PATCH 033/154] Added the field via_join_request to the class ChatMemberUpdated. --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/types/user_and_chats/chat_member_updated.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index a073c698c5..e3df5f2102 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added the field ``via_join_request`` to the class :obj:`~pyrogram.types.ChatMemberUpdated`. - Added the class :obj:`~pyrogram.types.TextQuote` and the field ``quote`` of type :obj:`~pyrogram.types.TextQuote` to the class :obj:`~pyrogram.types.Message`, which contains the part of the replied message text or caption that is quoted in the current message. - Added ``full_name`` to :obj:`~pyrogram.types.Chat` and :obj:`~pyrogram.types.User` only for :obj:`~pyrogram.enums.ChatType.PRIVATE`. - Added ``revoke_messages`` parameter to :meth:`~pyrogram.Client.ban_chat_member` and :meth:`~pyrogram.types.Chat.ban_member`. diff --git a/pyrogram/types/user_and_chats/chat_member_updated.py b/pyrogram/types/user_and_chats/chat_member_updated.py index c15d0b759b..adc5f42ad7 100644 --- a/pyrogram/types/user_and_chats/chat_member_updated.py +++ b/pyrogram/types/user_and_chats/chat_member_updated.py @@ -47,6 +47,9 @@ class ChatMemberUpdated(Object, Update): invite_link (:obj:`~pyrogram.types.ChatInviteLink`, *optional*): Chat invite link, which was used by the user to join the chat; for joining by invite link events only. + via_join_request (``bool``, *optional*): + True, if the user joined the chat after sending a direct join request and being approved by an administrator + via_chat_folder_invite_link (``bool``, *optional*): True, if the user joined the chat via a chat folder invite link """ @@ -61,6 +64,7 @@ def __init__( old_chat_member: "types.ChatMember", new_chat_member: "types.ChatMember", invite_link: "types.ChatInviteLink" = None, + via_join_request: bool = None, via_chat_folder_invite_link: bool = None ): super().__init__(client) @@ -71,6 +75,7 @@ def __init__( self.old_chat_member = old_chat_member self.new_chat_member = new_chat_member self.invite_link = invite_link + self.via_join_request = via_join_request self.via_chat_folder_invite_link = via_chat_folder_invite_link @staticmethod @@ -115,6 +120,7 @@ def _parse( old_chat_member = None new_chat_member = None invite_link = None + via_join_request = None if update.prev_participant: old_chat_member = types.ChatMember._parse(client, update.prev_participant, users, chats) @@ -124,6 +130,8 @@ def _parse( if update.invite: invite_link = types.ChatInviteLink._parse(client, update.invite, users) + if isinstance(update.invite, raw.types.ChatInvitePublicJoinRequests): + via_join_request = True return ChatMemberUpdated( chat=types.Chat._parse_chat(client, chats[chat_id]), @@ -133,5 +141,6 @@ def _parse( new_chat_member=new_chat_member, invite_link=invite_link, client=client, + via_join_request=via_join_request, via_chat_folder_invite_link=getattr(update, "via_chatlist", False) ) From 6a46d7c70c262bb3523b7d5a02f75fa513d79ac5 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 6 May 2024 16:51:05 +0200 Subject: [PATCH 034/154] Added the max_reaction_count to the Chat --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/types/user_and_chats/chat.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index e3df5f2102..8856730b46 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added the field ``max_reaction_count`` to the class :obj:`~pyrogram.types.Chat`. - Added the field ``via_join_request`` to the class :obj:`~pyrogram.types.ChatMemberUpdated`. - Added the class :obj:`~pyrogram.types.TextQuote` and the field ``quote`` of type :obj:`~pyrogram.types.TextQuote` to the class :obj:`~pyrogram.types.Message`, which contains the part of the replied message text or caption that is quoted in the current message. - Added ``full_name`` to :obj:`~pyrogram.types.Chat` and :obj:`~pyrogram.types.User` only for :obj:`~pyrogram.enums.ChatType.PRIVATE`. diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 8e0d80f7b9..4f60a38615 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -52,6 +52,9 @@ class Chat(Object): is_forum (``bool``, *optional*): True, if the supergroup chat is a forum + max_reaction_count (``int``): + The maximum number of reactions that can be set on a message in the chat + photo (:obj:`~pyrogram.types.ChatPhoto`, *optional*): Chat photo. Suitable for downloads only. @@ -260,6 +263,7 @@ def __init__( unrestrict_boost_count: int = None, is_forum: bool = None, is_peak_preview: bool = None, + max_reaction_count: int = None, _raw: Union[ "raw.types.ChatInvite", "raw.types.Channel", @@ -610,6 +614,7 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. full_chat.available_reactions, reactions_limit=getattr(full_chat, "reactions_limit", None) ) + parsed_chat.max_reaction_count = getattr(full_chat, "reactions_limit", 11) parsed_chat.personal_chat = personal_chat parsed_chat.personal_chat_message = personal_chat_message From 09247fd184705ca140d552af58f4008cb869ff39 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 6 May 2024 17:16:32 +0200 Subject: [PATCH 035/154] Custom Emoji in Polls --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 4 ++ pyrogram/methods/messages/send_poll.py | 22 +++++--- .../types/input_message_content/__init__.py | 2 + .../input_poll_option.py | 55 +++++++++++++++++++ pyrogram/types/messages_and_media/poll.py | 8 +++ .../types/messages_and_media/poll_option.py | 9 +++ 7 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 pyrogram/types/input_message_content/input_poll_option.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 987b3eab61..4b253d4bc6 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -493,6 +493,7 @@ def get_title_list(s: str) -> list: InputMessageContent ExternalReplyInfo InputMessageContent + InputPollOption InputTextMessageContent ReplyParameters TextQuote diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 8856730b46..4da5118b37 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,10 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added the field ``question_entities`` to the class :obj:`~pyrogram.types.Poll`. +- Added the field ``text_entities`` to the class :obj:`~pyrogram.types.PollOption`. +- Added the parameters ``question_parse_mode`` and ``question_entities`` to the method :meth:`~pyrogram.Client.send_poll`. +- Added the class :obj:`~pyrogram.types.InputPollOption` and changed the type of the parameter ``options`` in the method :meth:`~pyrogram.Client.send_poll` to Array of :obj:`~pyrogram.types.InputPollOption`. - Added the field ``max_reaction_count`` to the class :obj:`~pyrogram.types.Chat`. - Added the field ``via_join_request`` to the class :obj:`~pyrogram.types.ChatMemberUpdated`. - Added the class :obj:`~pyrogram.types.TextQuote` and the field ``quote`` of type :obj:`~pyrogram.types.TextQuote` to the class :obj:`~pyrogram.types.Message`, which contains the part of the replied message text or caption that is quoted in the current message. diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index 5e12f5c4e4..7ca2bf164e 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -31,7 +31,9 @@ async def send_poll( self: "pyrogram.Client", chat_id: Union[int, str], question: str, - options: List[str], + options: List["types.InputPollOption"], + question_parse_mode: "enums.ParseMode" = None, + question_entities: List["types.MessageEntity"] = None, is_anonymous: bool = True, type: "enums.PollType" = enums.PollType.REGULAR, allows_multiple_answers: bool = None, @@ -69,8 +71,15 @@ async def send_poll( question (``str``): Poll question, 1-255 characters. - options (List of ``str``): - List of answer options, 2-10 strings 1-100 characters each. + options (List of :obj:`~pyrogram.types.InputPollOption`): + List of answer options, 2-10 answer options. + + question_parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + question_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the poll question, which can be specified instead of *question_parse_mode*. is_anonymous (``bool``, *optional*): True, if the poll needs to be anonymous. @@ -97,7 +106,7 @@ async def send_poll( explanation_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the poll explanation, which can be specified instead of - *parse_mode*. + *explanation_parse_mode*. open_period (``int``, *optional*): Amount of time in seconds the poll will be active after creation, 5-600. @@ -167,14 +176,13 @@ async def send_poll( reply_parameters ) - # TODO: wait for BOT API update? - question, question_entities = (await utils.parse_text_entities(self, question, None, None)).values() + question, question_entities = (await utils.parse_text_entities(self, question, question_parse_mode, question_entities)).values() if not question_entities: question_entities = [] answers = [] for i, answer_ in enumerate(options): - answer, answer_entities = (await utils.parse_text_entities(self, answer_, None, None)).values() + answer, answer_entities = (await utils.parse_text_entities(self, answer_.text, answer_.text_parse_mode, answer_.text_entities)).values() if not answer_entities: answer_entities = [] answers.append( diff --git a/pyrogram/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py index f1696cbe52..1a48488f44 100644 --- a/pyrogram/types/input_message_content/__init__.py +++ b/pyrogram/types/input_message_content/__init__.py @@ -21,10 +21,12 @@ from .reply_parameters import ReplyParameters from .external_reply_info import ExternalReplyInfo from .text_quote import TextQuote +from .input_poll_option import InputPollOption __all__ = [ "ExternalReplyInfo", "InputMessageContent", + "InputPollOption", "InputTextMessageContent", "ReplyParameters", "TextQuote", diff --git a/pyrogram/types/input_message_content/input_poll_option.py b/pyrogram/types/input_message_content/input_poll_option.py new file mode 100644 index 0000000000..53f6138d40 --- /dev/null +++ b/pyrogram/types/input_message_content/input_poll_option.py @@ -0,0 +1,55 @@ +# 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 Union, List + +import pyrogram +from pyrogram import raw, utils, types, enums + +from ..object import Object + + +class InputPollOption(Object): + """This object contains information about one answer option in a poll to send. + + Parameters: + text (``str``): + Option text, 1-100 characters + + text_parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + Currently, only custom emoji entities are allowed. + + text_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + List of special entities that appear in the poll option text, which can be specified instead of *text_parse_mode*. + + """ + + def __init__( + self, + *, + text: str, + text_parse_mode: "enums.ParseMode" = None, + text_entities: List["types.MessageEntity"] = None, + ): + super().__init__() + + self.text = text + self.text_parse_mode = text_parse_mode + self.text_entities = text_entities diff --git a/pyrogram/types/messages_and_media/poll.py b/pyrogram/types/messages_and_media/poll.py index aa04eb65d4..8d4d0d5e67 100644 --- a/pyrogram/types/messages_and_media/poll.py +++ b/pyrogram/types/messages_and_media/poll.py @@ -37,6 +37,9 @@ class Poll(Object, Update): question (``str``): Poll question, 1-255 characters. + question_entities (List of :obj:`~pyrogram.types.MessageEntity`): + Special entities that appear in the question. Currently, only custom emoji entities are allowed in poll questions. + options (List of :obj:`~pyrogram.types.PollOption`): List of poll options. @@ -84,6 +87,7 @@ def __init__( id: str, question: str, options: List["types.PollOption"], + question_entities: List["types.MessageEntity"] = None, total_voter_count: int, is_closed: bool, is_anonymous: bool = None, @@ -101,6 +105,7 @@ def __init__( self.id = id self.question = question self.options = options + self.question_entities = question_entities self.total_voter_count = total_voter_count self.is_closed = is_closed self.is_anonymous = is_anonymous @@ -149,6 +154,7 @@ def _parse(client, media_poll: Union["raw.types.MessageMediaPoll", "raw.types.Up options.append( types.PollOption( text=Str(answer.text.text).init(entities), + text_entities=entities, voter_count=voter_count, data=answer.option, client=client @@ -169,6 +175,7 @@ def _parse(client, media_poll: Union["raw.types.MessageMediaPoll", "raw.types.Up id=str(poll.id), question=Str(poll.question.text).init(entities), options=options, + question_entities=entities, total_voter_count=media_poll.results.total_voters, is_closed=poll.closed, is_anonymous=not poll.public_voters, @@ -206,6 +213,7 @@ def _parse_update(client, update: "raw.types.UpdateMessagePoll"): options.append( types.PollOption( text="", + text_entities=[], voter_count=result.voters, data=result.option, client=client diff --git a/pyrogram/types/messages_and_media/poll_option.py b/pyrogram/types/messages_and_media/poll_option.py index a40926b077..0f5464b56f 100644 --- a/pyrogram/types/messages_and_media/poll_option.py +++ b/pyrogram/types/messages_and_media/poll_option.py @@ -16,7 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from typing import List + import pyrogram +from pyrogram import types + from ..object import Object @@ -26,6 +30,9 @@ class PollOption(Object): Parameters: text (``str``): Option text, 1-100 characters. + + text_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + Special entities that appear in the option text. Currently, only custom emoji entities are allowed in poll option texts. voter_count (``int``): Number of users that voted for this option. @@ -40,11 +47,13 @@ def __init__( *, client: "pyrogram.Client" = None, text: str, + text_entities: List["types.MessageEntity"], voter_count: int, data: bytes ): super().__init__(client) self.text = text + self.text_entities = text_entities self.voter_count = voter_count self.data = data From 6df06ff3ff10ea71ca2c89058b3c393b826aede7 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 6 May 2024 17:18:40 +0200 Subject: [PATCH 036/154] Update API scheme to Layer 179 from TDLib --- compiler/api/source/main_api.tl | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index a4374932c2..daab3b34ca 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -436,6 +436,7 @@ updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Messag updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; +updateBroadcastRevenueTransactions#5c65d358 balances:BroadcastRevenueBalances = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; From 2646b98dd12b6ca6e62e33b2a10fca36c9c32fd4 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 6 May 2024 17:22:20 +0200 Subject: [PATCH 037/154] Bump Version --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 8a11ef7325..8a391db256 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.29" +__version__ = "2.1.30" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 6f628d7cc9cec0875e7a682cbcd88786d5c05390 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Tue, 7 May 2024 20:55:57 +0530 Subject: [PATCH 038/154] ReBrand --- docs/source/topics/speedups.rst | 2 +- pyproject.toml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/topics/speedups.rst b/docs/source/topics/speedups.rst index a22187d260..9ace67e66a 100644 --- a/docs/source/topics/speedups.rst +++ b/docs/source/topics/speedups.rst @@ -18,7 +18,7 @@ Installation .. code-block:: bash - $ pip3 install -U tgcrypto + $ pip3 install -U PyTgCrypto Usage ^^^^^ diff --git a/pyproject.toml b/pyproject.toml index 496f3d8f5d..7f61cb154a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ path = "pyrogram/__init__.py" [project.urls] Homepage = "https://telegramplayground.github.io/pyrogram/releases/" Tracker = "https://github.com/TelegramPlayGround/Pyrogram/issues" -Community = "https://t.me/PyroTGFork" Source = "https://github.com/TelegramPlayGround/Pyrogram" Documentation = "https://telegramplayground.github.io/pyrogram/" @@ -99,6 +98,6 @@ docs = [ ] fast = [ - "TgCrypto==1.2.5", + "PyTgCrypto==1.2.6", "uvloop>0.18.0,<=0.19.0" ] From 37327b4a82ae655431a2f732b9d09fbb2d4f9685 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 9 May 2024 06:54:25 +0200 Subject: [PATCH 039/154] Fix parameter names in copy_message Follow-Up: b3942d92 --- pyrogram/methods/messages/copy_message.py | 17 ++++- pyrogram/types/messages_and_media/message.py | 75 ++++++++++++-------- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/pyrogram/methods/messages/copy_message.py b/pyrogram/methods/messages/copy_message.py index d726acbc86..08bc7ebc69 100644 --- a/pyrogram/methods/messages/copy_message.py +++ b/pyrogram/methods/messages/copy_message.py @@ -44,6 +44,9 @@ async def copy_message( "types.ForceReply" ] = None, schedule_date: datetime = None, + business_connection_id: str = None, + protect_content: bool = None, + message_thread_id: int = None, reply_to_message_id: int = None ) -> "types.Message": """Copy messages of any kind. @@ -93,6 +96,15 @@ async def copy_message( schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message will be sent + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving + + message_thread_id (``int``, *optional*): + Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + Returns: :obj:`~pyrogram.types.Message`: On success, the copied message is returned. @@ -130,5 +142,8 @@ async def copy_message( disable_notification=disable_notification, reply_parameters=reply_parameters, reply_markup=reply_markup, - schedule_date=schedule_date + schedule_date=schedule_date, + business_connection_id=business_connection_id, + protect_content=protect_content, + message_thread_id=message_thread_id ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index cea7530118..97f19b1229 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -3871,8 +3871,11 @@ async def copy( "types.ReplyKeyboardRemove", "types.ForceReply" ] = object, - reply_to_message_id: int = None, - schedule_date: datetime = None + schedule_date: datetime = None, + business_connection_id: str = None, + protect_content: bool = None, + message_thread_id: int = None, + reply_to_message_id: int = None ) -> Union["types.Message", List["types.Message"]]: """Bound method *copy* of :obj:`~pyrogram.types.Message`. @@ -3925,6 +3928,15 @@ async def copy( schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message will be sent + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving + + message_thread_id (``int``, *optional*): + Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + Returns: :obj:`~pyrogram.types.Message`: On success, the copied message is returned. @@ -3942,14 +3954,14 @@ async def copy( elif self.text: return await self._client.send_message( chat_id=chat_id, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, text=self.text, parse_mode=enums.ParseMode.DISABLED, entities=self.entities, link_preview_options=self.link_preview_options, disable_notification=disable_notification, - protect_content=self.has_protected_content, + protect_content=protect_content or self.has_protected_content, reply_parameters=reply_parameters, reply_markup=self.reply_markup if reply_markup is object else reply_markup, reply_to_message_id=reply_to_message_id, @@ -3961,10 +3973,10 @@ async def copy( chat_id=chat_id, disable_notification=disable_notification, reply_parameters=reply_parameters, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, schedule_date=schedule_date, - protect_content=self.has_protected_content, + protect_content=protect_content or self.has_protected_content, has_spoiler=self.has_media_spoiler, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup @@ -3995,10 +4007,10 @@ async def copy( vcard=self.contact.vcard, disable_notification=disable_notification, reply_parameters=reply_parameters, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, schedule_date=schedule_date, - protect_content=self.has_protected_content, + protect_content=protect_content or self.has_protected_content, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) @@ -4009,10 +4021,10 @@ async def copy( longitude=self.location.longitude, disable_notification=disable_notification, reply_parameters=reply_parameters, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, schedule_date=schedule_date, - protect_content=self.has_protected_content, + protect_content=protect_content or self.has_protected_content, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) @@ -4027,20 +4039,25 @@ async def copy( foursquare_type=self.venue.foursquare_type, disable_notification=disable_notification, reply_parameters=reply_parameters, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, schedule_date=schedule_date, - protect_content=self.has_protected_content, + protect_content=protect_content or self.has_protected_content, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) elif self.poll: - oldpm = self._client.parse_mode - self._client.set_parse_mode(enums.ParseMode.HTML) - cm = await self._client.send_poll( + # TODO + return await self._client.send_poll( chat_id, - question=self.poll.question.html, - options=[opt.text.html for opt in self.poll.options], + question=self.poll.question, + question_entities=self.poll.question_entities, + options=[ + types.InputPollOption( + text=opt.text, + text_entities=opt.text_entities + ) for opt in self.poll.options + ], is_anonymous=self.poll.is_anonymous, type=self.poll.type, allows_multiple_answers=self.poll.allows_multiple_answers, @@ -4050,24 +4067,22 @@ async def copy( open_period=self.poll.open_period, close_date=self.poll.close_date, disable_notification=disable_notification, - protect_content=self.has_protected_content, + protect_content=protect_content or self.has_protected_content, reply_parameters=reply_parameters, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, schedule_date=schedule_date, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) - self._client.set_parse_mode(oldpm) - return cm elif self.game: return await self._client.send_game( chat_id, game_short_name=self.game.short_name, disable_notification=disable_notification, - protect_content=self.has_protected_content, - message_thread_id=self.message_thread_id, - business_connection_id=self.business_connection_id, + protect_content=protect_content or self.has_protected_content, + message_thread_id=message_thread_id or self.message_thread_id, + business_connection_id=business_connection_id or self.business_connection_id, reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup From 6a08fef51561903413cf272eac9ffb4aa9225f67 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 9 May 2024 07:07:18 +0200 Subject: [PATCH 040/154] Rename parameter names according to TDLib --- docs/source/releases/changes-in-this-fork.rst | 4 ++-- pyrogram/methods/messages/search_global.py | 6 +++--- pyrogram/methods/messages/search_global_count.py | 6 +++--- pyrogram/types/user_and_chats/chat_reactions.py | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 4da5118b37..bab50fd8a8 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -34,9 +34,9 @@ it can take advantage of new goodies! - Added :meth:`~pyrogram.Client.get_bot_name`, :meth:`~pyrogram.Client.get_bot_info_description`, :meth:`~pyrogram.Client.get_bot_info_short_description`, :meth:`~pyrogram.Client.set_bot_name`, :meth:`~pyrogram.Client.set_bot_info_description`, :meth:`~pyrogram.Client.set_bot_info_short_description`. - Added :meth:`~pyrogram.Client.edit_cached_media` and :meth:`~pyrogram.types.Message.edit_cached_media`. - Steal `d51eef3 `_ without attribution. -- Added ``limit`` to :obj:`~pyrogram.types.ChatReactions`. +- Added ``max_reaction_count`` to :obj:`~pyrogram.types.ChatReactions`. - Added ``personal_chat_message`` to :obj:`~pyrogram.types.Chat`. -- Added ``is_channel`` parameter to :meth:`~pyrogram.Client.search_global` and :meth:`~pyrogram.Client.search_global_count`. +- Added ``only_in_channels`` parameter to :meth:`~pyrogram.Client.search_global` and :meth:`~pyrogram.Client.search_global_count`. +------------------------+ | Scheme layer used: 177 | diff --git a/pyrogram/methods/messages/search_global.py b/pyrogram/methods/messages/search_global.py index e57c3c741d..c171c7ced0 100644 --- a/pyrogram/methods/messages/search_global.py +++ b/pyrogram/methods/messages/search_global.py @@ -31,7 +31,7 @@ async def search_global( filter: "enums.MessagesFilter" = enums.MessagesFilter.EMPTY, limit: int = 0, chat_list: int = 0, - is_channel: bool = False, + only_in_channels: bool = False, ) -> Optional[AsyncGenerator["types.Message", None]]: """Search messages globally from all of your chats. @@ -60,7 +60,7 @@ async def search_global( chat_list (``int``, *optional*): Chat list in which to search messages; Only Main (0) and Archive (1) chat lists are supported. Defaults to (0) Main chat list. - is_channel (``bool``, *optional*): + only_in_channels (``bool``, *optional*): True, if should search only in joined channels. Defaults to False. All available chats are searched. @@ -103,7 +103,7 @@ async def search_global( offset_id=offset_id, limit=limit, folder_id=chat_list, - broadcasts_only=is_channel + broadcasts_only=only_in_channels ), sleep_threshold=60 ), diff --git a/pyrogram/methods/messages/search_global_count.py b/pyrogram/methods/messages/search_global_count.py index ee4a0fa561..c0683c8648 100644 --- a/pyrogram/methods/messages/search_global_count.py +++ b/pyrogram/methods/messages/search_global_count.py @@ -26,7 +26,7 @@ async def search_global_count( query: str = "", filter: "enums.MessagesFilter" = enums.MessagesFilter.EMPTY, chat_list: int = 0, - is_channel: bool = False, + only_in_channels: bool = False, ) -> int: """Get the count of messages resulting from a global search. @@ -45,7 +45,7 @@ async def search_global_count( chat_list (``int``, *optional*): Chat list in which to search messages; Only Main (0) and Archive (1) chat lists are supported. Defaults to (0) Main chat list. - is_channel (``bool``, *optional*): + only_in_channels (``bool``, *optional*): True, if should search only in joined channels. Defaults to False. All available chats are searched. @@ -63,7 +63,7 @@ async def search_global_count( offset_id=0, limit=1, folder_id=chat_list, - broadcasts_only=is_channel + broadcasts_only=only_in_channels ) ) diff --git a/pyrogram/types/user_and_chats/chat_reactions.py b/pyrogram/types/user_and_chats/chat_reactions.py index ed292bf557..189ab45b1b 100644 --- a/pyrogram/types/user_and_chats/chat_reactions.py +++ b/pyrogram/types/user_and_chats/chat_reactions.py @@ -35,7 +35,7 @@ class ChatReactions(Object): reactions (List of :obj:`~pyrogram.types.Reaction`, *optional*): Reactions available. - limit (``int``, *optional*): + max_reaction_count (``int``, *optional*): Limit of the number of different unique reactions that can be added to a message, including already published ones. Can have values between 1 and 11. Defaults to 11, if not specified. Only applicable for :obj:`~pyrogram.enums.ChatType.CHANNEL`. """ @@ -46,14 +46,14 @@ def __init__( all_are_enabled: Optional[bool] = None, allow_custom_emoji: Optional[bool] = None, reactions: Optional[List["types.Reaction"]] = None, - limit: int = 11, + max_reaction_count: int = 11, ): super().__init__(client) self.all_are_enabled = all_are_enabled self.allow_custom_emoji = allow_custom_emoji self.reactions = reactions - self.limit = limit + self.max_reaction_count = max_reaction_count @staticmethod def _parse(client, chat_reactions: "raw.base.ChatReactions", reactions_limit: int = 11) -> Optional["ChatReactions"]: @@ -62,7 +62,7 @@ def _parse(client, chat_reactions: "raw.base.ChatReactions", reactions_limit: in client=client, all_are_enabled=True, allow_custom_emoji=chat_reactions.allow_custom, - limit=reactions_limit + max_reaction_count=reactions_limit ) if isinstance(chat_reactions, raw.types.ChatReactionsSome): @@ -72,7 +72,7 @@ def _parse(client, chat_reactions: "raw.base.ChatReactions", reactions_limit: in types.ReactionType._parse(client, reaction) for reaction in chat_reactions.reactions ], - limit=reactions_limit + max_reaction_count=reactions_limit ) if isinstance(chat_reactions, raw.types.ChatReactionsNone): From 79a143fde92f198ae8cc3fd63080bcf5a66580be Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 10 May 2024 16:36:17 +0200 Subject: [PATCH 041/154] Fix bug in Chat parsing for BotReaction update --- .../types/messages_and_media/message_reaction_count_updated.py | 2 +- pyrogram/types/messages_and_media/message_reaction_updated.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/messages_and_media/message_reaction_count_updated.py b/pyrogram/types/messages_and_media/message_reaction_count_updated.py index 050a08d146..b410ffe8e6 100644 --- a/pyrogram/types/messages_and_media/message_reaction_count_updated.py +++ b/pyrogram/types/messages_and_media/message_reaction_count_updated.py @@ -73,7 +73,7 @@ def _parse( 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]) + chat = types.Chat._parse_chat(client, chats[raw_peer_id]) return MessageReactionCountUpdated( client=client, diff --git a/pyrogram/types/messages_and_media/message_reaction_updated.py b/pyrogram/types/messages_and_media/message_reaction_updated.py index b1cdb05e77..dd8cacef92 100644 --- a/pyrogram/types/messages_and_media/message_reaction_updated.py +++ b/pyrogram/types/messages_and_media/message_reaction_updated.py @@ -91,7 +91,7 @@ def _parse( 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]) + chat = types.Chat._parse_chat(client, chats[raw_peer_id]) user = None actor_chat = None From 69aaccf8fb760702bd547e30174919fbed617522 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 10 May 2024 16:59:27 +0200 Subject: [PATCH 042/154] Add view_messages and bound methods to Message --- compiler/docs/compiler.py | 3 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/__init__.py | 2 + pyrogram/methods/messages/view_messages.py | 65 +++++++++++++++++++ pyrogram/types/messages_and_media/message.py | 65 ++++++++++++++++++- 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/messages/view_messages.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 4b253d4bc6..837ea7e37f 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -330,6 +330,7 @@ def get_title_list(s: str) -> list: set_reaction stop_poll stream_media + view_messages vote_poll """, password=""" @@ -648,6 +649,8 @@ def get_title_list(s: str) -> list: Message.reply_voice Message.get_media_group Message.react + Message.read + Message.view """, chat=""" Chat diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index bab50fd8a8..d45146c600 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added :meth:`~pyrogram.Client.view_messages` and the bound methods :meth:`~pyrogram.types.Message.read` and :meth:`~pyrogram.types.Message.view`. - Added the field ``question_entities`` to the class :obj:`~pyrogram.types.Poll`. - Added the field ``text_entities`` to the class :obj:`~pyrogram.types.PollOption`. - Added the parameters ``question_parse_mode`` and ``question_entities`` to the method :meth:`~pyrogram.Client.send_poll`. diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index 15ca14ac06..850a9b89d1 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -66,6 +66,7 @@ from .send_voice import SendVoice from .stop_poll import StopPoll from .stream_media import StreamMedia +from .view_messages import ViewMessages from .vote_poll import VotePoll @@ -118,6 +119,7 @@ class Messages( SetReaction, StopPoll, StreamMedia, + ViewMessages, VotePoll, ): pass diff --git a/pyrogram/methods/messages/view_messages.py b/pyrogram/methods/messages/view_messages.py new file mode 100644 index 0000000000..bf76ada083 --- /dev/null +++ b/pyrogram/methods/messages/view_messages.py @@ -0,0 +1,65 @@ +# 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 Union, List + +import pyrogram +from pyrogram import raw + + +class ViewMessages: + async def view_messages( + self: "pyrogram.Client", + chat_id: Union[int, str], + message_ids: Union[int, List[int]], + force_read: bool = True + ) -> bool: + """Informs the server that messages are being viewed by the current user. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + message_ids (``int`` | List of ``int``): + Identifier or list of message identifiers of the target message. + + force_read (``bool``, *optional*): + Pass True to mark as read the specified messages and also increment the view counter. + + Returns: + ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Increment message views + await app.view_messages(chat_id, 1) + """ + ids = [message_ids] if not isinstance(message_ids, list) else message_ids + + r = await self.invoke( + raw.functions.messages.GetMessagesViews( + peer=await self.resolve_peer(chat_id), + id=ids, + increment=force_read + ) + ) + + return bool(r) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 97f19b1229..5adb8df18d 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -4047,7 +4047,6 @@ async def copy( reply_markup=self.reply_markup if reply_markup is object else reply_markup ) elif self.poll: - # TODO return await self._client.send_poll( chat_id, question=self.poll.question, @@ -4711,3 +4710,67 @@ def forward_date(self) -> datetime: return getattr(self.forward_origin, "date", None) # END: the below properties were removed in `BOT API 7.0 `_ + + async def read(self) -> bool: + """Bound method *read* of :obj:`~pyrogram.types.Message`. + + Use as a shortcut for: + + .. code-block:: python + + await client.read_chat_history( + chat_id=message.chat.id, + max_id=message_id + ) + + Example: + + .. code-block:: python + + await message.read() + + Returns: + True on success. + + Raises: + RPCError: In case of a Telegram RPC error. + + """ + return await self._client.read_chat_history( + chat_id=self.chat.id, + max_id=self.id + ) + + async def view(self, force_read: bool = True) -> bool: + """Bound method *view* of :obj:`~pyrogram.types.Message`. + + Use as a shortcut for: + + .. code-block:: python + + await client.view_messages( + chat_id=message.chat.id, + message_ids=message_id + ) + + Example: + .. code-block:: python + + await message.view() + + Parameters: + force_read (``bool``, *optional*): + Pass True to mark as read the specified messages and also increment the view counter. + + Returns: + True on success. + + Raises: + RPCError: In case of a Telegram RPC error. + + """ + return await self._client.view_messages( + chat_id=self.chat.id, + message_ids=self.id, + force_read=force_read + ) From 1a10b1a3247728227d213f10d221e8199b3f982c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 11 May 2024 15:23:51 +0200 Subject: [PATCH 043/154] Improve documentation for profile_photo methods Update API scheme with tDesktop --- compiler/api/source/main_api.tl | 26 +++++++++++++++++++ .../methods/users/delete_profile_photos.py | 12 +++++---- pyrogram/methods/users/get_chat_photos.py | 6 ++++- .../methods/users/get_chat_photos_count.py | 4 +++ pyrogram/methods/users/set_profile_photo.py | 4 --- 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index daab3b34ca..0f9f153a58 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -1,5 +1,31 @@ // https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/SourceFiles/mtproto/scheme/api.tl +/////////////////////////////// +/////////////////// Layer cons +/////////////////////////////// + +//invokeAfterMsg#cb9f372d msg_id:long query:!X = X; +//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; +//invokeWithLayer1#53835315 query:!X = X; +//invokeWithLayer2#289dd1f6 query:!X = X; +//invokeWithLayer3#b7475268 query:!X = X; +//invokeWithLayer4#dea0d430 query:!X = X; +//invokeWithLayer5#417a57ae query:!X = X; +//invokeWithLayer6#3a64d54d query:!X = X; +//invokeWithLayer7#a5be56d3 query:!X = X; +//invokeWithLayer8#e9abd9fd query:!X = X; +//invokeWithLayer9#76715a63 query:!X = X; +//invokeWithLayer10#39620c41 query:!X = X; +//invokeWithLayer11#a6b88fdf query:!X = X; +//invokeWithLayer12#dda60d3c query:!X = X; +//invokeWithLayer13#427c8ea2 query:!X = X; +//invokeWithLayer14#2b9b08fa query:!X = X; +//invokeWithLayer15#b4418b64 query:!X = X; +//invokeWithLayer16#cf5f0987 query:!X = X; +//invokeWithLayer17#50858a19 query:!X = X; +//invokeWithLayer18#1c900537 query:!X = X; +//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer + /////////////////////////////// ///////// Main application API /////////////////////////////// diff --git a/pyrogram/methods/users/delete_profile_photos.py b/pyrogram/methods/users/delete_profile_photos.py index 61e3e718d6..a854ee6362 100644 --- a/pyrogram/methods/users/delete_profile_photos.py +++ b/pyrogram/methods/users/delete_profile_photos.py @@ -32,7 +32,7 @@ async def delete_profile_photos( ) -> bool: """Delete your own profile photos. - .. include:: /_includes/usable-by/users.rst + .. include:: /_includes/usable-by/users-bots.rst Parameters: photo_ids (``str`` | List of ``str``, *optional*): @@ -80,8 +80,10 @@ async def delete_profile_photos( photo_ids = photo_ids if isinstance(photo_ids, list) else [photo_ids] input_photos = [utils.get_input_media_from_file_id(i, FileType.PHOTO).id for i in photo_ids] - return bool(await self.invoke( - raw.functions.photos.DeletePhotos( - id=input_photos + return bool( + await self.invoke( + raw.functions.photos.DeletePhotos( + id=input_photos + ) ) - )) + ) diff --git a/pyrogram/methods/users/get_chat_photos.py b/pyrogram/methods/users/get_chat_photos.py index 2b4262d5a5..fd63ec1236 100644 --- a/pyrogram/methods/users/get_chat_photos.py +++ b/pyrogram/methods/users/get_chat_photos.py @@ -29,8 +29,12 @@ async def get_chat_photos( limit: int = 0, ) -> Optional[AsyncGenerator["types.Photo", None]]: """Get a chat or a user profile photos sequentially. + + .. note:: - .. include:: /_includes/usable-by/users.rst + This method works for bot Clients only in :obj:`~pyrogram.enums.ChatType.PRIVATE` and :obj:`~pyrogram.enums.ChatType.GROUP` + + .. include:: /_includes/usable-by/users-bots.rst Parameters: chat_id (``int`` | ``str``): diff --git a/pyrogram/methods/users/get_chat_photos_count.py b/pyrogram/methods/users/get_chat_photos_count.py index d4cf1594f1..023ad2cb74 100644 --- a/pyrogram/methods/users/get_chat_photos_count.py +++ b/pyrogram/methods/users/get_chat_photos_count.py @@ -29,6 +29,10 @@ async def get_chat_photos_count( ) -> int: """Get the total count of photos for a chat. + .. note:: + + This method works for bot Clients only in :obj:`~pyrogram.enums.ChatType.PRIVATE` and :obj:`~pyrogram.enums.ChatType.GROUP` + .. include:: /_includes/usable-by/users-bots.rst Parameters: diff --git a/pyrogram/methods/users/set_profile_photo.py b/pyrogram/methods/users/set_profile_photo.py index 6b0ae13c47..59f5e88187 100644 --- a/pyrogram/methods/users/set_profile_photo.py +++ b/pyrogram/methods/users/set_profile_photo.py @@ -37,10 +37,6 @@ async def set_profile_photo( The ``photo`` and ``video`` arguments are mutually exclusive. Pass either one as named argument (see examples below). - .. note:: - - This method only works for Users. - .. include:: /_includes/usable-by/users-bots.rst Parameters: From 279a684edc0de96345c2695daaa649aa7ed27e15 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 11 May 2024 19:31:42 +0200 Subject: [PATCH 044/154] maybe Fix bug in parsing inline_message_id without reply_markup --- pyrogram/types/bots_and_keyboards/sent_web_app_message.py | 4 +++- pyrogram/types/inline_mode/chosen_inline_result.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/bots_and_keyboards/sent_web_app_message.py b/pyrogram/types/bots_and_keyboards/sent_web_app_message.py index 8b1df19737..ca1506a306 100644 --- a/pyrogram/types/bots_and_keyboards/sent_web_app_message.py +++ b/pyrogram/types/bots_and_keyboards/sent_web_app_message.py @@ -39,4 +39,6 @@ def __init__( @staticmethod def _parse(obj: "raw.types.WebViewMessageSent"): - return SentWebAppMessage(inline_message_id=utils.pack_inline_message_id(obj.msg_id)) + return SentWebAppMessage( + inline_message_id=utils.pack_inline_message_id(obj.msg_id) + ) if obj.msg_id else None diff --git a/pyrogram/types/inline_mode/chosen_inline_result.py b/pyrogram/types/inline_mode/chosen_inline_result.py index 8e09402dbd..367039e3e7 100644 --- a/pyrogram/types/inline_mode/chosen_inline_result.py +++ b/pyrogram/types/inline_mode/chosen_inline_result.py @@ -72,7 +72,7 @@ def __init__( def _parse(client, chosen_inline_result: raw.types.UpdateBotInlineSend, users) -> "ChosenInlineResult": inline_message_id = utils.pack_inline_message_id( chosen_inline_result.msg_id - ) + ) if chosen_inline_result.msg_id else None return ChosenInlineResult( result_id=str(chosen_inline_result.id), From 173d254f3b6d25076eacf301bb03425808296185 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 12 May 2024 14:21:30 +0200 Subject: [PATCH 045/154] Add load_group_call_participants method --- compiler/docs/compiler.py | 5 + compiler/docs/template/methods.rst | 13 ++ docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/__init__.py | 2 + pyrogram/methods/phone/__init__.py | 26 +++ .../phone/load_group_call_participants.py | 103 ++++++++++++ pyrogram/types/user_and_chats/__init__.py | 2 + .../user_and_chats/group_call_participant.py | 153 ++++++++++++++++++ 8 files changed, 305 insertions(+) create mode 100644 pyrogram/methods/phone/__init__.py create mode 100644 pyrogram/methods/phone/load_group_call_participants.py create mode 100644 pyrogram/types/user_and_chats/group_call_participant.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 837ea7e37f..af57bf70c6 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -339,6 +339,10 @@ def get_title_list(s: str) -> list: change_cloud_password remove_cloud_password """, + phone=""" + Phone + load_group_call_participants + """, stickers=""" Stickers get_stickers @@ -572,6 +576,7 @@ def get_title_list(s: str) -> list: ChatShared Dialog EmojiStatus + GroupCallParticipant InviteLinkImporter Restriction User diff --git a/compiler/docs/template/methods.rst b/compiler/docs/template/methods.rst index 6f88bd4837..05ccf463b0 100644 --- a/compiler/docs/template/methods.rst +++ b/compiler/docs/template/methods.rst @@ -164,6 +164,19 @@ Password {password} +Phone +-------- + +.. autosummary:: + :nosignatures: + + {phone} + +.. toctree:: + :hidden: + + {phone} + Bots ---- diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index d45146c600..f520fdd779 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added :meth:`~pyrogram.Client.load_group_call_participants` and the type :obj:`~pyrogram.types.GroupCallParticipant`. - Added :meth:`~pyrogram.Client.view_messages` and the bound methods :meth:`~pyrogram.types.Message.read` and :meth:`~pyrogram.types.Message.view`. - Added the field ``question_entities`` to the class :obj:`~pyrogram.types.Poll`. - Added the field ``text_entities`` to the class :obj:`~pyrogram.types.PollOption`. diff --git a/pyrogram/methods/__init__.py b/pyrogram/methods/__init__.py index b1b8514344..c7a392df94 100644 --- a/pyrogram/methods/__init__.py +++ b/pyrogram/methods/__init__.py @@ -26,6 +26,7 @@ from .invite_links import InviteLinks from .messages import Messages from .password import Password +from .phone import Phone from .stickers import Stickers from .users import Users from .utilities import Utilities @@ -43,6 +44,7 @@ class Methods( InviteLinks, Messages, Password, + Phone, Stickers, TelegramBusiness, Users, diff --git a/pyrogram/methods/phone/__init__.py b/pyrogram/methods/phone/__init__.py new file mode 100644 index 0000000000..3787ed06dd --- /dev/null +++ b/pyrogram/methods/phone/__init__.py @@ -0,0 +1,26 @@ + +# 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 .load_group_call_participants import LoadGroupCallParticipants + + +class Phone( + LoadGroupCallParticipants +): + pass diff --git a/pyrogram/methods/phone/load_group_call_participants.py b/pyrogram/methods/phone/load_group_call_participants.py new file mode 100644 index 0000000000..0d402bfc27 --- /dev/null +++ b/pyrogram/methods/phone/load_group_call_participants.py @@ -0,0 +1,103 @@ +# 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 Union, AsyncGenerator + +import pyrogram +from pyrogram import types, raw + + +class LoadGroupCallParticipants: + async def load_group_call_participants( + self: "pyrogram.Client", + chat_id: Union[int, str], + limit: int = 0 + ) -> AsyncGenerator["types.GroupCallParticipant", None]: + """Loads participants list in a group call of a chat. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. A chat can be either a basic group or a supergroup. + + limit (``int``, *optional*): + Limits the number of participants to be retrieved. By default, no limit is applied and all participants are returned. + + Returns: + ``Generator``: On success, a generator yielding :obj:`~pyrogram.types.GroupCallParticipant` object is returned. + + Example: + .. code-block:: python + + # Get participants + async for participant in app.load_group_call_participants(chat_id): + print(participant) + + """ + peer = await self.resolve_peer(chat_id) + + if isinstance(peer, raw.types.InputPeerChannel): + r = await self.invoke(raw.functions.channels.GetFullChannel(channel=peer)) + elif isinstance(peer, raw.types.InputPeerChat): + r = await self.invoke(raw.functions.messages.GetFullChat(chat_id=peer.chat_id)) + else: + raise ValueError("Target chat should be group, supergroup or channel.") + + full_chat = r.full_chat + + if not getattr(full_chat, "call", None): + raise ValueError("There is no active call in this chat.") + + current = 0 + offset = "" + total = abs(limit) or (1 << 31) - 1 + limit = min(20, total) + + while True: + r = await self.invoke( + raw.functions.phone.GetGroupParticipants( + call=full_chat.call, + ids=[], + sources=[], + offset=offset, + limit=limit + ), + sleep_threshold=60 + ) + + users = {u.id: u for u in r.users} + chats = {c.id: c for c in r.chats} + participants = [ + types.GroupCallParticipant._parse( + self, participant, users, chats + ) for participant in r.participants + ] + + if not participants: + return + + offset = r.next_offset + + for participant in participants: + yield participant + + current += 1 + + if current >= total: + return diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py index 1be75cf732..403aa0aceb 100644 --- a/pyrogram/types/user_and_chats/__init__.py +++ b/pyrogram/types/user_and_chats/__init__.py @@ -34,6 +34,7 @@ from .chat_shared import ChatShared from .dialog import Dialog from .emoji_status import EmojiStatus +from .group_call_participant import GroupCallParticipant from .invite_link_importer import InviteLinkImporter from .restriction import Restriction from .user import User @@ -63,6 +64,7 @@ "ChatShared", "Dialog", "EmojiStatus", + "GroupCallParticipant", "InviteLinkImporter", "Restriction", "User", diff --git a/pyrogram/types/user_and_chats/group_call_participant.py b/pyrogram/types/user_and_chats/group_call_participant.py new file mode 100644 index 0000000000..e43786cbe8 --- /dev/null +++ b/pyrogram/types/user_and_chats/group_call_participant.py @@ -0,0 +1,153 @@ +# 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 datetime import datetime +from typing import Dict + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object + + +class GroupCallParticipant(Object): + """Represents a group call participant + + Parameters: + participant (:obj:`~pyrogram.types.Chat`, *optional*): + Identifier of the group call participant + + date (:py:obj:`~datetime.datetime`, *optional*): + Date when this participant join this group call. + + active_date (:py:obj:`~datetime.datetime`, *optional*): + Date when this participant last active in this group call. + + volume_level (``int``, *optional*): + Participant's volume level, if not set the volume is set to 100%. + + can_unmute_self (``bool``, *optional*): + True, if the participant is muted for all users, but can unmute themselves + + is_muted_for_all_users (``bool``, *optional*): + True, if the participant is muted for all users + + is_current_user (``bool``, *optional*): + True, if the participant is the current user + + is_left (``bool``, *optional*): + Whether the participant has left. + + is_just_joined (``bool``, *optional*): + Whether the participant has just joined. + + is_muted_by_you (``bool``, *optional*): + Whether this participant was muted by the current user. + + is_volume_by_admin (``bool``, *optional*): + Whether our volume can only changed by an admin. + + is_video_joined (``bool``, *optional*): + Whether this participant is currently broadcasting video. + + is_hand_raised (``bool``, *optional*): + True, if the participant hand is raised + + is_video_enabled (``bool``, *optional*): + Whether this participant is currently broadcasting video. + + is_screen_sharing_enabled (``bool``, *optional*): + Whether this participant is currently shared screen. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + participant: "types.Chat" = None, + date: datetime = None, + active_date: datetime = None, + volume_level: int = None, + can_unmute_self: bool = None, + is_muted_for_all_users: bool = None, + is_current_user: bool = None, + is_left: bool = None, + is_just_joined: bool = None, + is_muted_by_you: bool = None, + is_volume_by_admin: bool = None, + is_video_joined: bool = None, + is_hand_raised: bool = None, + is_video_enabled: bool = None, + is_screen_sharing_enabled: bool = None, + _raw: "raw.types.GroupCallParticipant" = None + ): + super().__init__(client) + + self.participant = participant + self.date = date + self.active_date = active_date + self.volume_level = volume_level + self.can_unmute_self = can_unmute_self + self.is_muted_for_all_users = is_muted_for_all_users + self.is_current_user = is_current_user + self.is_left = is_left + self.is_just_joined = is_just_joined + self.is_muted_by_you = is_muted_by_you + self.is_volume_by_admin = is_volume_by_admin + self.is_video_joined = is_video_joined + self.is_hand_raised = is_hand_raised + self.is_video_enabled = is_video_enabled + self.is_screen_sharing_enabled = is_screen_sharing_enabled + self._raw = _raw + + @staticmethod + def _parse( + client: "pyrogram.Client", + participant: "raw.types.GroupCallParticipant", + users: Dict[int, "raw.base.User"], + chats: Dict[int, "raw.base.Chat"] + ) -> "GroupCallParticipant": + peer = participant.peer + peer_id = utils.get_raw_peer_id(peer) + + parsed_chat = types.Chat._parse_chat( + client, + users[peer_id] if isinstance(peer, raw.types.PeerUser) else chats[peer_id], + ) + + parsed_chat.bio = getattr(participant, "about", None) + + return GroupCallParticipant( + participant=parsed_chat, + date=utils.timestamp_to_datetime(participant.date), + active_date=utils.timestamp_to_datetime(participant.active_date), + volume_level=getattr(participant, "volume", None), + can_unmute_self=participant.can_self_unmute, + is_muted_for_all_users=participant.muted, + is_current_user=participant.is_self, + is_left=participant.left, + is_just_joined=participant.just_joined, + is_muted_by_you=participant.muted_by_you, + is_volume_by_admin=participant.volume_by_admin, + is_video_joined=participant.video_joined, + is_hand_raised=bool(getattr(participant, "raise_hand_rating", None)), + is_video_enabled=bool(getattr(participant, "video", None)), + is_screen_sharing_enabled=bool(getattr(participant, "presentation", None)), + _raw=participant, + client=client + ) From 2e00a09d867d7b3270cada123cc17315fb3d1cdf Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 12 May 2024 14:57:00 +0200 Subject: [PATCH 046/154] Add get_chat_sponsored_messages --- compiler/docs/compiler.py | 2 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/__init__.py | 2 + .../messages/get_chat_sponsored_messages.py | 61 +++++++++ pyrogram/types/messages_and_media/__init__.py | 2 + .../messages_and_media/sponsored_message.py | 124 ++++++++++++++++++ 6 files changed, 192 insertions(+) create mode 100644 pyrogram/methods/messages/get_chat_sponsored_messages.py create mode 100644 pyrogram/types/messages_and_media/sponsored_message.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index af57bf70c6..e6d0f1a324 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -332,6 +332,7 @@ def get_title_list(s: str) -> list: stream_media view_messages vote_poll + get_chat_sponsored_messages """, password=""" Password @@ -539,6 +540,7 @@ def get_title_list(s: str) -> list: StrippedThumbnail Poll PollOption + SponsoredMessage Sticker Story Venue diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index f520fdd779..b8c4c1efcb 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,7 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added :meth:`~pyrogram.Client.get_chat_sponsored_messages` and the type :obj:`~pyrogram.types.SponsoredMessage`. - Added :meth:`~pyrogram.Client.load_group_call_participants` and the type :obj:`~pyrogram.types.GroupCallParticipant`. - Added :meth:`~pyrogram.Client.view_messages` and the bound methods :meth:`~pyrogram.types.Message.read` and :meth:`~pyrogram.types.Message.view`. - Added the field ``question_entities`` to the class :obj:`~pyrogram.types.Poll`. diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index 850a9b89d1..2fe5aabbdc 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -68,6 +68,7 @@ from .stream_media import StreamMedia from .view_messages import ViewMessages from .vote_poll import VotePoll +from .get_chat_sponsored_messages import GetChatSponsoredMessages class Messages( @@ -121,5 +122,6 @@ class Messages( StreamMedia, ViewMessages, VotePoll, + GetChatSponsoredMessages, ): pass diff --git a/pyrogram/methods/messages/get_chat_sponsored_messages.py b/pyrogram/methods/messages/get_chat_sponsored_messages.py new file mode 100644 index 0000000000..08eea342d7 --- /dev/null +++ b/pyrogram/methods/messages/get_chat_sponsored_messages.py @@ -0,0 +1,61 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Optional, Union, List + +import pyrogram +from pyrogram import raw, types + + +class GetChatSponsoredMessages: + async def get_chat_sponsored_messages( + self: "pyrogram.Client", + chat_id: Union[int, str], + ) -> Optional[List["types.SponsoredMessage"]]: + """Returns sponsored messages to be shown in a chat; for channel chats only. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + Returns: + List of :obj:`~pyrogram.types.SponsoredMessage`: a list of sponsored messages is returned. + + Example: + .. code-block:: python + + # Get a sponsored messages + sm = await app.get_chat_sponsored_messages(chat_id) + print(sm) + + """ + r = await self.invoke( + raw.functions.channels.GetSponsoredMessages( + channel=await self.resolve_peer(chat_id) + ) + ) + + if isinstance(r, raw.types.messages.SponsoredMessagesEmpty): + return None + + return types.List([ + types.SponsoredMessage._parse(self, sm) + for sm in r.messages + ]) diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index b1f3882b3a..fe812cc81a 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -35,6 +35,7 @@ ReactionTypeCustomEmoji, ReactionCount ) +from .sponsored_message import SponsoredMessage from .sticker import Sticker from .stripped_thumbnail import StrippedThumbnail from .thumbnail import Thumbnail @@ -84,6 +85,7 @@ "StrippedThumbnail", "Poll", "PollOption", + "SponsoredMessage", "Sticker", "Story", "Venue", diff --git a/pyrogram/types/messages_and_media/sponsored_message.py b/pyrogram/types/messages_and_media/sponsored_message.py new file mode 100644 index 0000000000..002d18b1bc --- /dev/null +++ b/pyrogram/types/messages_and_media/sponsored_message.py @@ -0,0 +1,124 @@ +# 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 List + +import pyrogram +from pyrogram import raw, types + +from ..object import Object +from .message import Str + +class SponsoredMessage(Object): + """Describes a sponsored message. + + Parameters: + random_id (``bytes``): + Message identifier; unique for the chat to which the sponsored message belongs among both ordinary and sponsored messages. + + url (``str``): + ad url + + title (``str``): + Title of the sponsored message. + + content (``str``): + sponsored message. + + button_text (``str``): + Text for the message action button. + + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + special entities that appear in the text. + + photo (:obj:`~pyrogram.types.Photo`, *optional*): + sponsored message photo + + is_recommended (``bool``, *optional*): + True, if the message needs to be labeled as "recommended" instead of "sponsored". + + can_be_reported (``bool``, *optional*): + True, if the message can be reported to Telegram moderators through :meth:`~pyrogram.Client.report_chat_sponsored_message`. + + color (:obj:`~pyrogram.types.ChatColor`, *optional*): + Identifier of the accent color for title, button text and message background. + + sponsor_info (``str``, *optional*): + Information about the sponsor of the message. + + additional_info (``str``, *optional*): + If non-empty, additional information about the sponsored message to be shown along with the message. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + random_id: bytes, + url: str, + title: str, + content: str, + button_text: str, + entities: List["types.MessageEntity"] = None, + photo: "types.Photo" = None, + is_recommended: bool = None, + can_be_reported: bool = None, + color: "types.ChatColor" = None, + sponsor_info: str = None, + additional_info: str = None + ): + super().__init__(client) + + self.random_id = random_id + self.url = url + self.title = title + self.content = content + self.button_text = button_text + self.entities = entities + self.photo = photo + self.is_recommended = is_recommended + self.can_be_reported = can_be_reported + self.color = color + self.sponsor_info = sponsor_info + self.additional_info = additional_info + + @staticmethod + def _parse(client, sponsored_message: "raw.types.SponsoredMessage"): + entities = [ + types.MessageEntity._parse(client, entity, users) + for entity in getattr(sponsored_message, "entities", []) + ] + entities = types.List( + filter(lambda x: x is not None, entities) + ) + return SponsoredMessage( + random_id=sponsored_message.random_id, + url=sponsored_message.url, + title=sponsored_message.title, + content=Str(sponsored_message.message).init(entities), + button_text=sponsored_message.button_text, + photo=types.Photo._parse(client, sponsored_message.photo) if sponsored_message.photo else None, + is_recommended=sponsored_message.recommended, + can_be_reported=sponsored_message.can_report, + entities=entities, + color=types.ChatColor._parse(sponsored_message.color) if sponsored_message.color else None, + sponsor_info=getattr(sponsored_message, "sponsor_info", None), + additional_info=getattr(sponsored_message, "additional_info", None), + client=client + ) From 8307cd216b15d27446ea33d997fc3ef63014bf16 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 12 May 2024 15:00:19 +0200 Subject: [PATCH 047/154] Update Pyrogram to v2.1.31 --- docs/source/releases/changes-in-this-fork.rst | 4 ++-- pyrogram/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index b8c4c1efcb..528681a67a 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,8 +12,8 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ -- Added :meth:`~pyrogram.Client.get_chat_sponsored_messages` and the type :obj:`~pyrogram.types.SponsoredMessage`. -- Added :meth:`~pyrogram.Client.load_group_call_participants` and the type :obj:`~pyrogram.types.GroupCallParticipant`. +- Added :meth:`~pyrogram.Client.get_chat_sponsored_messages` and the type :obj:`~pyrogram.types.SponsoredMessage`, by stealing unauthored changes from `KurimuzonAkuma/pyrogram#55 `_. +- Added :meth:`~pyrogram.Client.load_group_call_participants` and the type :obj:`~pyrogram.types.GroupCallParticipant`, by stealing unauthored changes from `6df467f `_. - Added :meth:`~pyrogram.Client.view_messages` and the bound methods :meth:`~pyrogram.types.Message.read` and :meth:`~pyrogram.types.Message.view`. - Added the field ``question_entities`` to the class :obj:`~pyrogram.types.Poll`. - Added the field ``text_entities`` to the class :obj:`~pyrogram.types.PollOption`. diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 8a391db256..8abc521d0d 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.30" +__version__ = "2.1.31" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 192cccb48ee19a021ca909b331207e120d797e7e Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 14 May 2024 19:33:56 +0200 Subject: [PATCH 048/154] Support for Chat Video Type Add has_animation, is_personal, minithumbnail to ChatPhoto Change return type of get_chat_photos Inspiration from KurimuzonAkuma/pyrogram#60 but MVB_#1333 --- docs/source/releases/changes-in-this-fork.rst | 2 + pyrogram/methods/users/get_chat_photos.py | 71 ++++++++++++------- .../types/messages_and_media/animation.py | 45 +++++++++++- pyrogram/types/messages_and_media/video.py | 2 +- pyrogram/types/user_and_chats/chat_photo.py | 26 ++++++- 5 files changed, 114 insertions(+), 32 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 528681a67a..f9dbf3c8c3 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -12,6 +12,8 @@ it can take advantage of new goodies! | Scheme layer used: 179 | +------------------------+ +- Added ``has_animation``, ``is_personal``, ``minithumbnail`` parameters to :obj:`~pyrogram.types.ChatPhoto`. +- Changed return type of :meth:`~pyrogram.Client.get_chat_photos` to return :obj:`~pyrogram.types.Photo` or :obj:`~pyrogram.types.Animation`. - Added :meth:`~pyrogram.Client.get_chat_sponsored_messages` and the type :obj:`~pyrogram.types.SponsoredMessage`, by stealing unauthored changes from `KurimuzonAkuma/pyrogram#55 `_. - Added :meth:`~pyrogram.Client.load_group_call_participants` and the type :obj:`~pyrogram.types.GroupCallParticipant`, by stealing unauthored changes from `6df467f `_. - Added :meth:`~pyrogram.Client.view_messages` and the bound methods :meth:`~pyrogram.types.Message.read` and :meth:`~pyrogram.types.Message.view`. diff --git a/pyrogram/methods/users/get_chat_photos.py b/pyrogram/methods/users/get_chat_photos.py index fd63ec1236..a44162dd85 100644 --- a/pyrogram/methods/users/get_chat_photos.py +++ b/pyrogram/methods/users/get_chat_photos.py @@ -27,12 +27,13 @@ async def get_chat_photos( self: "pyrogram.Client", chat_id: Union[int, str], limit: int = 0, - ) -> Optional[AsyncGenerator["types.Photo", None]]: + ) -> Optional[ + Union[ + AsyncGenerator["types.Photo", None], + AsyncGenerator["types.Animation", None] + ] + ]: """Get a chat or a user profile photos sequentially. - - .. note:: - - This method works for bot Clients only in :obj:`~pyrogram.enums.ChatType.PRIVATE` and :obj:`~pyrogram.enums.ChatType.GROUP` .. include:: /_includes/usable-by/users-bots.rst @@ -47,7 +48,7 @@ async def get_chat_photos( By default, no limit is applied and all profile photos are returned. Returns: - ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` | :obj:`~pyrogram.types.Video` objects. Example: .. code-block:: python @@ -65,36 +66,44 @@ async def get_chat_photos( ) current = types.Photo._parse(self, r.full_chat.chat_photo) or [] - - r = await utils.parse_messages( + current = [current] + current_animation = types.Animation._parse_chat_animation( self, - await self.invoke( - raw.functions.messages.Search( - peer=peer_id, - q="", - filter=raw.types.InputMessagesFilterChatPhotos(), - min_date=0, - max_date=0, - offset_id=0, - add_offset=0, - limit=limit, - max_id=0, - min_id=0, - hash=0 + r.full_chat.chat_photo + ) + if current_animation: + current = current + [current_animation] + extra = [] + if not self.me.is_bot: + r = await utils.parse_messages( + self, + await self.invoke( + raw.functions.messages.Search( + peer=peer_id, + q="", + filter=raw.types.InputMessagesFilterChatPhotos(), + min_date=0, + max_date=0, + offset_id=0, + add_offset=0, + limit=limit, + max_id=0, + min_id=0, + hash=0 + ) ) ) - ) - extra = [message.new_chat_photo for message in r] + extra = [message.new_chat_photo for message in r] if extra: if current: - photos = ([current] + extra) if current.file_id != extra[0].file_id else extra + photos = (current + extra) if current[0].file_id != extra[0].file_id else extra else: photos = extra else: if current: - photos = [current] + photos = current else: photos = [] @@ -123,7 +132,17 @@ async def get_chat_photos( ) ) - photos = [types.Photo._parse(self, photo) for photo in r.photos] + photos = [] + for photo in r.photos: + photos.append( + types.Photo._parse(self, photo) + ) + current_animation = types.Animation._parse_chat_animation( + self, + photo + ) + if current_animation: + photos.append(current_animation) if not photos: return diff --git a/pyrogram/types/messages_and_media/animation.py b/pyrogram/types/messages_and_media/animation.py index 1e7bf4cf39..a6c5d0b06f 100644 --- a/pyrogram/types/messages_and_media/animation.py +++ b/pyrogram/types/messages_and_media/animation.py @@ -43,7 +43,7 @@ class Animation(Object): height (``int``): Animation height as defined by sender. - duration (``int``): + duration (``int``, *optional*): Duration of the animation in seconds as defined by sender. file_name (``str``, *optional*): @@ -70,7 +70,7 @@ def __init__( file_unique_id: str, width: int, height: int, - duration: int, + duration: int = None, file_name: str = None, mime_type: str = None, file_size: int = None, @@ -119,3 +119,44 @@ def _parse( thumbs=types.Thumbnail._parse(client, animation), client=client ) + + @staticmethod + def _parse_chat_animation( + client, + video: "raw.types.Photo" + ) -> "Animation": + if isinstance(video, raw.types.Photo): + if not video.video_sizes: + return + video_sizes: List[raw.types.VideoSize] = [] + for p in video.video_sizes: + if isinstance(p, raw.types.VideoSize): + video_sizes.append(p) + # TODO: VideoSizeEmojiMarkup + video_sizes.sort(key=lambda p: p.size) + video_size = video_sizes[-1] + return Animation( + file_id=FileId( + file_type=FileType.PHOTO, + dc_id=video.dc_id, + media_id=video.id, + access_hash=video.access_hash, + file_reference=video.file_reference, + thumbnail_source=ThumbnailSource.THUMBNAIL, + thumbnail_file_type=FileType.PHOTO, + thumbnail_size=video_size.type, + volume_id=0, + local_id=0 + ).encode() if video else None, + file_unique_id=FileUniqueId( + file_unique_type=FileUniqueType.DOCUMENT, + media_id=video.id + ).encode() if video else None, + width=video_size.w, + height=video_size.h, + file_size=video_size.size, + date=utils.timestamp_to_datetime(video.date) if video else None, + file_name=f"chat_video_{video.date}_{client.rnd_id()}.mp4", + mime_type="video/mp4", + client=client + ) diff --git a/pyrogram/types/messages_and_media/video.py b/pyrogram/types/messages_and_media/video.py index 7b1149705e..11ed1559e5 100644 --- a/pyrogram/types/messages_and_media/video.py +++ b/pyrogram/types/messages_and_media/video.py @@ -22,7 +22,7 @@ import pyrogram from pyrogram import raw, utils from pyrogram import types -from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object diff --git a/pyrogram/types/user_and_chats/chat_photo.py b/pyrogram/types/user_and_chats/chat_photo.py index b3aba61dd0..4234b9767b 100644 --- a/pyrogram/types/user_and_chats/chat_photo.py +++ b/pyrogram/types/user_and_chats/chat_photo.py @@ -19,7 +19,7 @@ from typing import Union import pyrogram -from pyrogram import raw +from pyrogram import raw, types from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object @@ -43,6 +43,16 @@ class ChatPhoto(Object): big_photo_unique_id (``str``): Unique file identifier of big (640x640) chat photo, which is supposed to be the same over time and for different accounts. Can't be used to download or reuse the file. + + has_animation (``bool``): + True, if the photo has animated variant + + is_personal (``bool``): + True, if the photo is visible only for the current user + + minithumbnail (:obj:`~pyrogram.types.StrippedThumbnail`, *optional*): + User profile photo minithumbnail; may be None. + """ def __init__( @@ -52,8 +62,10 @@ def __init__( small_file_id: str, small_photo_unique_id: str, big_file_id: str, - big_photo_unique_id: str - + big_photo_unique_id: str, + has_animation: bool, + is_personal: bool, + minithumbnail: "types.StrippedThumbnail" = None ): super().__init__(client) @@ -61,6 +73,9 @@ def __init__( self.small_photo_unique_id = small_photo_unique_id self.big_file_id = big_file_id self.big_photo_unique_id = big_photo_unique_id + self.has_animation = has_animation + self.is_personal = is_personal + self.minithumbnail = minithumbnail @staticmethod def _parse( @@ -103,5 +118,10 @@ def _parse( file_unique_type=FileUniqueType.DOCUMENT, media_id=chat_photo.photo_id ).encode(), + has_animation=chat_photo.has_video, + is_personal=getattr(chat_photo, "personal", False), + minithumbnail=types.StrippedThumbnail( + data=chat_photo.stripped_thumb + ) if chat_photo.stripped_thumb else None, client=client ) From d22f687212c9e328f65538bb1064459d6e2b3384 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 14 May 2024 21:36:56 +0200 Subject: [PATCH 049/154] Handle FLOOD_PREMIUM_WAIT Squashed commit of the following: commit 546b603 commit 0ac858d commit c8a9725 Ref: https://t.me/swiftgram/72 --- pyrogram/client.py | 6 ++---- pyrogram/methods/users/get_chat_photos.py | 2 +- pyrogram/session/session.py | 6 ++++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyrogram/client.py b/pyrogram/client.py index 9e9fb8e8f0..56376de506 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -984,8 +984,7 @@ async def get_file( location=location, offset=offset_bytes, limit=chunk_size - ), - sleep_threshold=30 + ) ) if isinstance(r, raw.types.upload.File): @@ -1020,8 +1019,7 @@ async def get_file( location=location, offset=offset_bytes, limit=chunk_size - ), - sleep_threshold=30 + ) ) elif isinstance(r, raw.types.upload.FileCdnRedirect): diff --git a/pyrogram/methods/users/get_chat_photos.py b/pyrogram/methods/users/get_chat_photos.py index a44162dd85..883a2c5939 100644 --- a/pyrogram/methods/users/get_chat_photos.py +++ b/pyrogram/methods/users/get_chat_photos.py @@ -48,7 +48,7 @@ async def get_chat_photos( By default, no limit is applied and all profile photos are returned. Returns: - ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` | :obj:`~pyrogram.types.Video` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` | :obj:`~pyrogram.types.Animation` objects. Example: .. code-block:: python diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 7e619cc1ba..857d3eef89 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -28,7 +28,9 @@ from pyrogram.connection import Connection from pyrogram.crypto import mtproto from pyrogram.errors import ( - RPCError, InternalServerError, AuthKeyDuplicated, FloodWait, ServiceUnavailable, BadMsgNotification, + RPCError, InternalServerError, AuthKeyDuplicated, + FloodWait, FloodPremiumWait, + ServiceUnavailable, BadMsgNotification, SecurityCheckMismatch ) from pyrogram.raw.all import layer @@ -401,7 +403,7 @@ async def invoke( while True: try: return await self.send(query, timeout=timeout) - except FloodWait as e: + except (FloodWait, FloodPremiumWait) as e: amount = e.value if amount > sleep_threshold >= 0: From f738262bb1c4eda6efa0deb4aabb68f6eaac964a Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 18 May 2024 15:39:58 +0200 Subject: [PATCH 050/154] Fix link_preview_options bug with edit_message_text (#24) --- pyrogram/methods/messages/edit_message_text.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pyrogram/methods/messages/edit_message_text.py b/pyrogram/methods/messages/edit_message_text.py index 375e846aac..56de57c652 100644 --- a/pyrogram/methods/messages/edit_message_text.py +++ b/pyrogram/methods/messages/edit_message_text.py @@ -63,7 +63,7 @@ async def edit_message_text( List of special entities that appear in message text, which can be specified instead of *parse_mode*. link_preview_options (:obj:`~pyrogram.types.LinkPreviewOptions`, *optional*): - Link preview generation options for the message + Link preview generation options for the message. Ignored if the specified URL does not have a valid preview. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. @@ -101,12 +101,25 @@ async def edit_message_text( ) link_preview_options = types.LinkPreviewOptions(is_disabled=disable_web_page_preview) + media = None + if ( + link_preview_options and + link_preview_options.url + ): + media = raw.types.InputMediaWebPage( + url=link_preview_options.url, + force_large_media=link_preview_options.prefer_large_media, + force_small_media=link_preview_options.prefer_small_media, + optional=True + ) + r = await self.invoke( raw.functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, no_webpage=link_preview_options.is_disabled if link_preview_options else None, invert_media=link_preview_options.show_above_text if link_preview_options else None, + media=media, reply_markup=await reply_markup.write(self) if reply_markup else None, schedule_date=utils.datetime_to_timestamp(schedule_date), **await utils.parse_text_entities(self, text, parse_mode, entities) From a8ec0701c59dd7d0e5c9f792df8b2bbde752ef48 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 22 May 2024 13:39:05 +0200 Subject: [PATCH 051/154] Fix bug in parsing TextQuote and ExternalReplyInfo --- .../input_message_content/external_reply_info.py | 7 +++++++ pyrogram/types/input_message_content/text_quote.py | 7 ++----- pyrogram/types/messages_and_media/message.py | 13 ++++++------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index fd5932f0b8..68d008f31c 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -169,7 +169,14 @@ async def _parse( users, chats, ) + chat = None + if isinstance(reply_to.reply_to_peer_id, raw.types.PeerChannel): + raw_peer_id = utils.get_raw_peer_id(reply_to.reply_to_peer_id) + chat = types.Chat._parse_chat( + client, + chats[raw_peer_id], + ) animation = None audio = None diff --git a/pyrogram/types/input_message_content/text_quote.py b/pyrogram/types/input_message_content/text_quote.py index 74f10334fc..fa344df0c3 100644 --- a/pyrogram/types/input_message_content/text_quote.py +++ b/pyrogram/types/input_message_content/text_quote.py @@ -65,13 +65,10 @@ def _parse( users: dict, reply_to: "raw.types.MessageReplyHeader" ) -> "TextQuote": - if not getattr(reply_to, "quote", None): - return None - if isinstance(reply_to, raw.types.MessageReplyHeader): quote_text = reply_to.quote_text quote_entities = reply_to.quote_entities - position = reply_to.quote_offset + position = reply_to.quote_offset or 0 entities = [ types.MessageEntity._parse(client, entity, users) @@ -85,5 +82,5 @@ def _parse( text=Str(quote_text).init(entities) or None, entities=entities, position=position, - # TODO + is_manual=bool(reply_to.quote) or None ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 5adb8df18d..5458a5543a 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1226,13 +1226,12 @@ async def _parse( parsed_message.message_thread_id = message.reply_to.reply_to_top_id else: parsed_message.message_thread_id = message.reply_to.reply_to_msg_id - if message.reply_to.quote: - parsed_message.quote = types.TextQuote._parse( - client, - chats, - users, - message.reply_to - ) + parsed_message.quote = types.TextQuote._parse( + client, + chats, + users, + message.reply_to + ) if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): parsed_message.reply_to_story = await types.Story._parse(client, chats, None, message.reply_to) From 04b6c65a9189709db0300c471035511de4e51871 Mon Sep 17 00:00:00 2001 From: Gautam Kumar Date: Fri, 24 May 2024 14:11:21 +0530 Subject: [PATCH 052/154] update MIN_CHANNEL_ID (#28) update MIN_CHANNEL_ID Reference: https://t.me/pyrogramchat/593087 --- pyrogram/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrogram/utils.py b/pyrogram/utils.py index ad4243ce2a..4672d1f7c1 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -236,7 +236,8 @@ def unpack_inline_message_id(inline_message_id: str) -> "raw.base.InputBotInline ) -MIN_CHANNEL_ID = -1002147483647 +MIN_CHANNEL_ID_OLD = -1002147483647 +MIN_CHANNEL_ID = -1009999999999 MAX_CHANNEL_ID = -1000000000000 MIN_CHAT_ID_OLD = -2147483647 MIN_CHAT_ID = -999999999999 From 20c1a1eb54a4349856b73446cce40b538d3fa148 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 24 May 2024 11:09:43 +0200 Subject: [PATCH 053/154] Update Pyrogram to v2.1.32.1 --- docs/source/releases/changes-in-this-fork.rst | 4 ++++ pyrogram/__init__.py | 2 +- pyrogram/utils.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index f9dbf3c8c3..ed84a879fa 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -8,10 +8,14 @@ it can take advantage of new goodies! `For a more detailed description, please check the commits. `_ +If you found any issue or have any suggestions, feel free to make `an issue `_ on github. + +------------------------+ | Scheme layer used: 179 | +------------------------+ +- Support for the updated Channel ID format. `#28 `_ +- Improvements to :meth:`~pyrogram.Client.save_file` and :meth:`~pyrogram.Client.get_file` to handle the new `FLOOD_PREMIUM_WAIT `_ errors. - Added ``has_animation``, ``is_personal``, ``minithumbnail`` parameters to :obj:`~pyrogram.types.ChatPhoto`. - Changed return type of :meth:`~pyrogram.Client.get_chat_photos` to return :obj:`~pyrogram.types.Photo` or :obj:`~pyrogram.types.Animation`. - Added :meth:`~pyrogram.Client.get_chat_sponsored_messages` and the type :obj:`~pyrogram.types.SponsoredMessage`, by stealing unauthored changes from `KurimuzonAkuma/pyrogram#55 `_. diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 8abc521d0d..8182d4019d 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.31" +__version__ = "2.1.32.1" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " diff --git a/pyrogram/utils.py b/pyrogram/utils.py index 4672d1f7c1..9d48a17225 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -237,7 +237,7 @@ def unpack_inline_message_id(inline_message_id: str) -> "raw.base.InputBotInline MIN_CHANNEL_ID_OLD = -1002147483647 -MIN_CHANNEL_ID = -1009999999999 +MIN_CHANNEL_ID = -1007852516352 MAX_CHANNEL_ID = -1000000000000 MIN_CHAT_ID_OLD = -2147483647 MIN_CHAT_ID = -999999999999 From 7492d7e05098719322cde9ddab2096a1fc2d5ec3 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 24 May 2024 18:31:34 +0200 Subject: [PATCH 054/154] Add link_preview_options to Client --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/client.py | 6 ++++++ pyrogram/methods/messages/edit_inline_text.py | 2 ++ pyrogram/methods/messages/edit_message_text.py | 2 ++ pyrogram/methods/messages/send_message.py | 2 ++ .../input_message_content/input_text_message_content.py | 2 ++ 6 files changed, 15 insertions(+) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index ed84a879fa..7289b9faee 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ - Improvements to :meth:`~pyrogram.Client.save_file` and :meth:`~pyrogram.Client.get_file` to handle the new `FLOOD_PREMIUM_WAIT `_ errors. - Added ``has_animation``, ``is_personal``, ``minithumbnail`` parameters to :obj:`~pyrogram.types.ChatPhoto`. diff --git a/pyrogram/client.py b/pyrogram/client.py index 56376de506..39c4b31366 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -211,6 +211,10 @@ class Client(Methods): client_platform (:obj:`~pyrogram.enums.ClientPlatform`, *optional*): The platform where this client is running. Defaults to 'other' + + link_preview_options (:obj:`~pyrogram.types.LinkPreviewOptions`, *optional*): + Set the global link preview options for the client. By default, no link preview option is set. + """ APP_VERSION = f"Pyrogram {__version__}" @@ -272,6 +276,7 @@ def __init__( storage_engine: Storage = None, no_joined_notifications: bool = False, client_platform: enums.ClientPlatform = enums.ClientPlatform.OTHER, + link_preview_options: "types.LinkPreviewOptions" = None, _un_docu_gnihts: List = [] ): super().__init__() @@ -309,6 +314,7 @@ def __init__( self.no_joined_notifications = no_joined_notifications self.client_platform = client_platform self._un_docu_gnihts = _un_docu_gnihts + self.link_preview_options = link_preview_options self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler") diff --git a/pyrogram/methods/messages/edit_inline_text.py b/pyrogram/methods/messages/edit_inline_text.py index 86e8ac4578..411901225b 100644 --- a/pyrogram/methods/messages/edit_inline_text.py +++ b/pyrogram/methods/messages/edit_inline_text.py @@ -95,6 +95,8 @@ async def edit_inline_text( ) link_preview_options = types.LinkPreviewOptions(is_disabled=disable_web_page_preview) + link_preview_options = link_preview_options or self.link_preview_options + unpacked = utils.unpack_inline_message_id(inline_message_id) dc_id = unpacked.dc_id diff --git a/pyrogram/methods/messages/edit_message_text.py b/pyrogram/methods/messages/edit_message_text.py index 56de57c652..8942ba2147 100644 --- a/pyrogram/methods/messages/edit_message_text.py +++ b/pyrogram/methods/messages/edit_message_text.py @@ -101,6 +101,8 @@ async def edit_message_text( ) link_preview_options = types.LinkPreviewOptions(is_disabled=disable_web_page_preview) + link_preview_options = link_preview_options or self.link_preview_options + media = None if ( link_preview_options and diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index 3cbb19dac6..8aacdc8e4f 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -150,6 +150,8 @@ async def send_message( ) link_preview_options = types.LinkPreviewOptions(is_disabled=disable_web_page_preview) + link_preview_options = link_preview_options or self.link_preview_options + if reply_to_message_id and reply_parameters: raise ValueError( "Parameters `reply_to_message_id` and `reply_parameters` are mutually " diff --git a/pyrogram/types/input_message_content/input_text_message_content.py b/pyrogram/types/input_message_content/input_text_message_content.py index ea0a97db2b..fa70df41cd 100644 --- a/pyrogram/types/input_message_content/input_text_message_content.py +++ b/pyrogram/types/input_message_content/input_text_message_content.py @@ -65,6 +65,8 @@ def __init__( ) link_preview_options = types.LinkPreviewOptions(is_disabled=disable_web_page_preview) + link_preview_options = link_preview_options or self.link_preview_options + super().__init__() self.message_text = message_text From db9b1a1015e1ad85b1facecef32a6580955f75c0 Mon Sep 17 00:00:00 2001 From: Hitalo M Date: Sun, 26 May 2024 00:04:53 -0300 Subject: [PATCH 055/154] refactor(mime_types): added new file extensions The mime_types.py file was updated to include new file extensions for various media types. This ensures that the application can handle these file types correctly. --- pyrogram/mime_types.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pyrogram/mime_types.py b/pyrogram/mime_types.py index 2f6c86aa8b..a853bd715b 100644 --- a/pyrogram/mime_types.py +++ b/pyrogram/mime_types.py @@ -18,6 +18,7 @@ # From https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types. # Extended with extra mime types specific to Telegram. + mime_types = """ # This file maps Internet media types to unique file extension(s). # Although created for httpd, this file is used by many software systems @@ -163,7 +164,7 @@ application/java-archive jar application/java-serialized-object ser application/java-vm class -application/javascript js +# application/javascript # application/jose # application/jose+json # application/jrd+json @@ -606,6 +607,7 @@ # application/vnd.geo+json # application/vnd.geocube+xml application/vnd.geogebra.file ggb +application/vnd.geogebra.slides ggs application/vnd.geogebra.tool ggt application/vnd.geometry-explorer gex gre application/vnd.geonext gxt @@ -1233,6 +1235,7 @@ application/vnd.zzazz.deck+xml zaz application/voicexml+xml vxml # application/vq-rtcpxr +application/wasm wasm # application/watcherinfo+xml # application/whoispp-query # application/whoispp-response @@ -1457,10 +1460,10 @@ # audio/mp4a-latm # audio/mpa # audio/mpa-robust -audio/mpeg mp3 mpga mp2 mp2a m2a m3a +audio/mpeg mpga mp2 mp2a mp3 m2a m3a # audio/mpeg4-generic # audio/musepack -audio/ogg ogg oga spx +audio/ogg oga ogg spx opus # audio/opus # audio/parityfec # audio/pcma @@ -1568,7 +1571,7 @@ image/ief ief # image/jls # image/jp2 -image/jpeg jpg jpeg jpe +image/jpeg jpeg jpg jpe # image/jpm # image/jpx image/ktx ktx @@ -1664,7 +1667,7 @@ # model/vnd.gs.gdl model/vnd.gtw gtw # model/vnd.moml+xml -model/vnd.mts mts +# model/vnd.mts # model/vnd.opengex # model/vnd.parasolid.transmit.binary # model/vnd.parasolid.transmit.text @@ -1707,7 +1710,7 @@ # text/fwdred # text/grammar-ref-list text/html html htm -# text/javascript +text/javascript js mjs # text/jcr-cnd # text/markdown # text/mizar @@ -1803,7 +1806,7 @@ video/mj2 mj2 mjp2 # video/mp1s # video/mp2p -# video/mp2t +video/mp2t ts m2t m2ts mts video/mp4 mp4 mp4v mpg4 # video/mp4v-es video/mpeg mpeg mpg mpe m1v m2v From e003dec1f5be2c8ee5c30f120f6f69d5b40c7dfc Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 26 May 2024 14:37:49 +0200 Subject: [PATCH 056/154] Add invoice to Message and ExternalReplyInfo --- compiler/docs/compiler.py | 2 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/enums/message_media_type.py | 3 + pyrogram/types/business/__init__.py | 2 + pyrogram/types/business/invoice.py | 73 +++++++++++++++++++ .../external_reply_info.py | 11 ++- pyrogram/types/messages_and_media/message.py | 11 ++- 7 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 pyrogram/types/business/invoice.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index e6d0f1a324..3e28e9e8ca 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -557,6 +557,8 @@ def get_title_list(s: str) -> list: BusinessLocation BusinessOpeningHours BusinessOpeningHoursInterval + CollectibleItemInfo + Invoice """, users_chats=""" Users & Chats diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 7289b9faee..99b814478c 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ - Improvements to :meth:`~pyrogram.Client.save_file` and :meth:`~pyrogram.Client.get_file` to handle the new `FLOOD_PREMIUM_WAIT `_ errors. diff --git a/pyrogram/enums/message_media_type.py b/pyrogram/enums/message_media_type.py index 3c8afacb95..5085af574a 100644 --- a/pyrogram/enums/message_media_type.py +++ b/pyrogram/enums/message_media_type.py @@ -77,3 +77,6 @@ class MessageMediaType(AutoName): GIVEAWAY_WINNERS = auto() "Giveaway Winners" + + INVOICE = auto() + "Invoice" diff --git a/pyrogram/types/business/__init__.py b/pyrogram/types/business/__init__.py index 1078ef8908..8e4dd1eb0c 100644 --- a/pyrogram/types/business/__init__.py +++ b/pyrogram/types/business/__init__.py @@ -22,6 +22,7 @@ from .business_opening_hours import BusinessOpeningHours from .business_opening_hours_interval import BusinessOpeningHoursInterval from .collectible_item_info import CollectibleItemInfo +from .invoice import Invoice __all__ = [ "BusinessConnection", @@ -30,4 +31,5 @@ "BusinessOpeningHours", "BusinessOpeningHoursInterval", "CollectibleItemInfo", + "Invoice", ] diff --git a/pyrogram/types/business/invoice.py b/pyrogram/types/business/invoice.py new file mode 100644 index 0000000000..baf7ddc4d1 --- /dev/null +++ b/pyrogram/types/business/invoice.py @@ -0,0 +1,73 @@ +# 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 . + +import pyrogram +from pyrogram import raw, types +from ..object import Object + + +class Invoice(Object): + """This object contains basic information about an invoice. + + Parameters: + title (``str``): + Product name. + + description (``str``): + Product description. + + start_parameter (``str``): + Unique bot deep-linking parameter that can be used to generate this invoice. + + currency (``str``): + Three-letter ISO 4217 `currency `_ code. + + total_amount (``int``): + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + title: str, + description: str, + start_parameter: str, + currency: str, + total_amount: int + ): + super().__init__(client) + + self.title = title + self.description = description + self.start_parameter = start_parameter + self.currency = currency + self.total_amount = total_amount + + @staticmethod + def _parse(client, invoice: "raw.types.MessageMediaInvoice") -> "Invoice": + return Invoice( + title=invoice.title, + description=invoice.description, + start_parameter=invoice.start_param, + currency=invoice.currency, + total_amount=invoice.total_amount, + # TODO + client=client + ) diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index 68d008f31c..c001d7172e 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -85,7 +85,8 @@ class ExternalReplyInfo(Object): giveaway_winners (:obj:`~pyrogram.types.GiveawayWinners`, *optional*): A giveaway with public winners was completed - invoice + invoice (:obj:`~pyrogram.types.Invoice`, *optional*): + Message is an invoice for a `payment `_, information about the invoice. `More about payments » `_ location (:obj:`~pyrogram.types.Location`, *optional*): Message is a shared location, information about the location. @@ -120,7 +121,7 @@ def __init__( game: "types.Game" = None, giveaway: "types.Giveaway" = None, giveaway_winners: "types.GiveawayWinners" = None, - + invoice: "types.Invoice" = None, location: "types.Location" = None, poll: "types.Poll" = None, venue: "types.Venue" = None, @@ -146,6 +147,7 @@ def __init__( self.game = game self.giveaway = giveaway self.giveaway_winners = giveaway_winners + self.invoice = invoice self.location = location self.poll = poll self.venue = venue @@ -195,6 +197,7 @@ async def _parse( game = None giveaway = None giveaway_winners = None + invoice = None location = None poll = None venue = None @@ -296,6 +299,9 @@ async def _parse( elif isinstance(media, raw.types.MessageMediaGiveawayResults): giveaway_winners = types.GiveawayWinners._parse(client, chats, users, media) media_type = enums.MessageMediaType.GIVEAWAY_WINNERS + elif isinstance(media, raw.types.MessageMediaInvoice): + invoice = types.Invoice._parse(client, media) + media_type = enums.MessageMediaType.INVOICE return ExternalReplyInfo( origin=origin, @@ -317,6 +323,7 @@ async def _parse( game=game, giveaway=giveaway, giveaway_winners=giveaway_winners, + invoice=invoice, location=location, poll=poll, venue=venue diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 5458a5543a..ce5caf765e 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -254,6 +254,9 @@ class Message(Object, Update): Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply. + invoice (:obj:`~pyrogram.types.Invoice`, *optional*): + Message is an invoice for a `payment `_, information about the invoice. `More about payments » `_ + users_shared (:obj:`~pyrogram.types.UsersShared`, *optional*): Service message: users were shared with the bot @@ -446,7 +449,7 @@ def __init__( migrate_to_chat_id: int = None, migrate_from_chat_id: int = None, pinned_message: "Message" = None, - + invoice: "types.Invoice" = None, users_shared: "types.UsersShared" = None, chat_shared: "types.ChatShared" = None, @@ -553,6 +556,7 @@ def __init__( self.migrate_to_chat_id = migrate_to_chat_id self.migrate_from_chat_id = migrate_from_chat_id self.pinned_message = pinned_message + self.invoice = invoice self.game_high_score = game_high_score self.views = views self.forwards = forwards @@ -990,6 +994,7 @@ async def _parse( dice = None giveaway = None giveaway_winners = None + invoice = None media = message.media media_type = None @@ -1104,6 +1109,9 @@ async def _parse( elif isinstance(media, raw.types.MessageMediaGiveawayResults): giveaway_winners = types.GiveawayWinners._parse(client, chats, users, media) media_type = enums.MessageMediaType.GIVEAWAY_WINNERS + elif isinstance(media, raw.types.MessageMediaInvoice): + invoice = types.Invoice._parse(client, media) + media_type = enums.MessageMediaType.INVOICE else: media = None @@ -1191,6 +1199,7 @@ async def _parse( dice=dice, giveaway=giveaway, giveaway_winners=giveaway_winners, + invoice=invoice, views=message.views, forwards=message.forwards, via_bot=types.User._parse(client, users.get(message.via_bot_id, None)), From 48e14a6d0b2468dde11a89d994c454e73847f7a0 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 28 May 2024 14:45:42 +0200 Subject: [PATCH 057/154] Update API scheme on Layer 181 --- compiler/api/source/main_api.tl | 59 +++++++++++++++---- docs/source/releases/changes-in-this-fork.rst | 8 ++- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 0f9f153a58..4f9f9fcc5a 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -87,7 +87,7 @@ inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string pro inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#8eb5a6d5 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; +inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; inputMediaDice#e66fbf7b emoticon:string = InputMedia; @@ -163,7 +163,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#2357bf25 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int = Message; +message#94345242 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck = Message; messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message; messageMediaEmpty#3ded6320 = MessageMedia; @@ -462,7 +462,8 @@ updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Messag updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateBroadcastRevenueTransactions#5c65d358 balances:BroadcastRevenueBalances = Update; +updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueBalances = Update; +updateStarsBalance#fb85198 balance:long = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -719,7 +720,7 @@ messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity; +messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; @@ -807,7 +808,7 @@ auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeTyp auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#e57b1432 flags:# nonce:flags.0?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; +auth.sentCodeTypeFirebaseSms#13c90f17 flags:# nonce:flags.0?bytes play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; @@ -950,6 +951,7 @@ inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; +payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; @@ -957,6 +959,7 @@ payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; +payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; @@ -1496,6 +1499,7 @@ attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; inputInvoiceSlug#c326caef slug:string = InputInvoice; inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; +inputInvoiceStars#1da33ad8 option:StarsTopupOption = InputInvoice; payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; @@ -1507,6 +1511,7 @@ inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgra inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; +inputStorePaymentStars#4f0ee8df flags:# stars:long currency:string amount:long = InputStorePaymentPurpose; premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption; @@ -1831,6 +1836,26 @@ reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNo broadcastRevenueBalances#8438f1c6 current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; +availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; + +messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; +messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; + +factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; + +starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; +starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; +starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; +starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; +starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; +starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; + +starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; + +starsTransaction#cc7079b2 flags:# refund:flags.3?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument = StarsTransaction; + +payments.starsStatus#8cf4ee60 flags:# balance:long history:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1841,6 +1866,8 @@ invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; +invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; +invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; @@ -1854,7 +1881,7 @@ auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_au auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; +auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; @@ -1862,7 +1889,7 @@ auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; auth.acceptLoginToken#e894ad4d token:bytes = Authorization; auth.checkRecoveryPassword#d36bf79 code:string = Bool; auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#89464b50 flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string ios_push_secret:flags.1?string = Bool; +auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; @@ -2020,8 +2047,8 @@ messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?t messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#dff8042c flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates; -messages.sendMedia#7bd66041 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates; +messages.sendMessage#983f9745 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long = Updates; +messages.sendMedia#7852834e flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long = Updates; messages.forwardMessages#d5039208 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; @@ -2100,7 +2127,7 @@ messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#c964709 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates; +messages.sendMultiMedia#37b74355 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; @@ -2220,6 +2247,10 @@ messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Upda messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; +messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; +messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; +messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; +messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; 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; @@ -2330,6 +2361,7 @@ channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; channels.reportSponsoredMessage#af8ff6b9 channel:InputChannel random_id:bytes option:bytes = channels.SponsoredMessageReportResult; channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; +channels.searchPosts#d19f987b hashtag:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -2364,6 +2396,11 @@ payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; payments.applyGiftCode#f6e26854 slug:string = Updates; payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; +payments.getStarsTopupOptions#c00ec7d3 = Vector; +payments.getStarsStatus#104fcfa7 peer:InputPeer = payments.StarsStatus; +payments.getStarsTransactions#673ac2f9 flags:# inbound:flags.0?true outbound:flags.1?true peer:InputPeer offset:string = payments.StarsStatus; +payments.sendStarsForm#2bb731d flags:# form_id:long invoice:InputInvoice = payments.PaymentResult; +payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; @@ -2486,4 +2523,4 @@ test.useError = Error; test.useConfigSimple = help.ConfigSimple; test.parseInputAppEvent = InputAppEvent; -// LAYER 179 +// LAYER 181 diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 99b814478c..386b6c7ea1 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -10,6 +10,13 @@ it can take advantage of new goodies! If you found any issue or have any suggestions, feel free to make `an issue `_ on github. ++------------------------+ +| Scheme layer used: 181 | ++------------------------+ + + +- `View new and changed raw API methods `__. + +------------------------+ | Scheme layer used: 179 | +------------------------+ @@ -34,7 +41,6 @@ If you found any issue or have any suggestions, feel free to make `an issue `_, `a086b49 `_) -- `ℹ️ Blog Post `_ - `View new and changed raw API methods `__. +------------------------+ From 4842ef08ee06718804917442283da2c087976cbb Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 28 May 2024 20:27:06 +0200 Subject: [PATCH 058/154] Fix bug https://t.me/c/1220993104/1/1378886 --- pyrogram/types/messages_and_media/animation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/types/messages_and_media/animation.py b/pyrogram/types/messages_and_media/animation.py index a6c5d0b06f..289a8ba912 100644 --- a/pyrogram/types/messages_and_media/animation.py +++ b/pyrogram/types/messages_and_media/animation.py @@ -22,7 +22,7 @@ import pyrogram from pyrogram import raw, utils from pyrogram import types -from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object From e9167ec8df2ef4d92e432f1f416c9ea33e4a2797 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 28 May 2024 21:49:32 +0200 Subject: [PATCH 059/154] Fix bug in TextQuote parsing Regression was introduced in a8ec070 --- pyrogram/types/messages_and_media/message.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index ce5caf765e..95009d1643 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1235,12 +1235,13 @@ async def _parse( parsed_message.message_thread_id = message.reply_to.reply_to_top_id else: parsed_message.message_thread_id = message.reply_to.reply_to_msg_id - parsed_message.quote = types.TextQuote._parse( - client, - chats, - users, - message.reply_to - ) + if getattr(message.reply_to, "quote", False): + parsed_message.quote = types.TextQuote._parse( + client, + chats, + users, + message.reply_to + ) if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): parsed_message.reply_to_story = await types.Story._parse(client, chats, None, message.reply_to) From 7fb94d9b8f372c57e8cbe87f7dbf77b4dae8ce80 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 28 May 2024 21:49:39 +0200 Subject: [PATCH 060/154] Added EXPANDABLE_BLOCKQUOTE in MessageEntityType --- docs/source/releases/changes-in-this-fork.rst | 4 +++- pyrogram/enums/message_entity_type.py | 12 +++++++++--- pyrogram/parser/html.py | 10 +++++++++- pyrogram/parser/markdown.py | 19 ++++++++++++++++--- .../input_message_content.py | 7 +++++-- .../messages_and_media/message_entity.py | 12 ++++++++++-- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 386b6c7ea1..2606351a1b 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,9 @@ If you found any issue or have any suggestions, feel free to make `an issue `__. +------------------------+ diff --git a/pyrogram/enums/message_entity_type.py b/pyrogram/enums/message_entity_type.py index 4db75f93f7..13398a4908 100644 --- a/pyrogram/enums/message_entity_type.py +++ b/pyrogram/enums/message_entity_type.py @@ -16,7 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from enum import auto + from pyrogram import raw + from .auto_name import AutoName @@ -59,15 +62,18 @@ class MessageEntityType(AutoName): SPOILER = raw.types.MessageEntitySpoiler "Spoiler text" + BLOCKQUOTE = auto() + "Block quotation" + + EXPANDABLE_BLOCKQUOTE = auto() + "collapsed-by-default block quotation" + CODE = raw.types.MessageEntityCode "Monowidth string" PRE = raw.types.MessageEntityPre "Monowidth block (see ``language``)" - BLOCKQUOTE = raw.types.MessageEntityBlockquote - "Blockquote text" - TEXT_LINK = raw.types.MessageEntityTextUrl "For clickable text URLs" diff --git a/pyrogram/parser/html.py b/pyrogram/parser/html.py index 46722a8c40..594feba04b 100644 --- a/pyrogram/parser/html.py +++ b/pyrogram/parser/html.py @@ -57,6 +57,7 @@ def handle_starttag(self, tag, attrs): entity = raw.types.MessageEntityStrike elif tag == "blockquote": entity = raw.types.MessageEntityBlockquote + extra["collapsed"] = bool("expandable" in attrs.keys()) elif tag == "code": entity = raw.types.MessageEntityCode elif tag == "pre": @@ -177,9 +178,16 @@ def parse_one(entity): language = getattr(entity, "language", "") or "" start_tag = f'<{name} language="{language}">' if language else f"<{name}>" end_tag = f"" + elif entity_type == MessageEntityType.BLOCKQUOTE: + name = entity_type.name.lower() + start_tag = f"<{name}>" + end_tag = f"" + elif entity_type == MessageEntityType.EXPANDABLE_BLOCKQUOTE: + name = "blockquote" + start_tag = f"<{name} expandable>" + end_tag = f"" elif entity_type in ( MessageEntityType.CODE, - MessageEntityType.BLOCKQUOTE, MessageEntityType.SPOILER, ): name = entity_type.name.lower() diff --git a/pyrogram/parser/markdown.py b/pyrogram/parser/markdown.py index 5c9772d625..fdcf80f8f7 100644 --- a/pyrogram/parser/markdown.py +++ b/pyrogram/parser/markdown.py @@ -34,6 +34,7 @@ CODE_DELIM = "`" PRE_DELIM = "```" BLOCKQUOTE_DELIM = ">" +BLOCKQUOTE_EXPANDABLE_DELIM = "**>" MARKDOWN_RE = re.compile(r"({d})|(!?)\[(.+?)\]\((.+?)\)".format( d="|".join( @@ -67,22 +68,34 @@ def _parse_blockquotes(self, text: str): lines = text.split('\n') result = [] in_blockquote = False + is_expandable_blockquote = False current_blockquote = [] for line in lines: if line.startswith(BLOCKQUOTE_DELIM): in_blockquote = True current_blockquote.append(line[1:].strip()) + elif line.startswith(BLOCKQUOTE_EXPANDABLE_DELIM): + in_blockquote = True + is_expandable_blockquote = True + current_blockquote.append(line[3:].strip()) else: if in_blockquote: in_blockquote = False - result.append(OPENING_TAG.format("blockquote") + '\n'.join(current_blockquote) + CLOSING_TAG.format("blockquote")) + result.append( + (f"
" if is_expandable_blockquote else OPENING_TAG.format("blockquote")) + + '\n'.join(current_blockquote) + + CLOSING_TAG.format("blockquote") + ) current_blockquote = [] result.append(line) if in_blockquote: - result.append(OPENING_TAG.format("blockquote") + '\n'.join(current_blockquote) + CLOSING_TAG.format("blockquote")) - + result.append( + (f"
" if is_expandable_blockquote else OPENING_TAG.format("blockquote")) + + '\n'.join(current_blockquote) + + CLOSING_TAG.format("blockquote") + ) return '\n'.join(result) async def parse(self, text: str, strict: bool = False): diff --git a/pyrogram/types/input_message_content/input_message_content.py b/pyrogram/types/input_message_content/input_message_content.py index 2b46393259..6ffe6cae24 100644 --- a/pyrogram/types/input_message_content/input_message_content.py +++ b/pyrogram/types/input_message_content/input_message_content.py @@ -20,9 +20,12 @@ from ..object import Object -"""- :obj:`~pyrogram.types.InputLocationMessageContent` +""" + - :obj:`~pyrogram.types.InputLocationMessageContent` - :obj:`~pyrogram.types.InputVenueMessageContent` - - :obj:`~pyrogram.types.InputContactMessageContent`""" + - :obj:`~pyrogram.types.InputContactMessageContent` + - :obj:`~pyrogram.types.InputInvoiceMessageContent` +""" class InputMessageContent(Object): diff --git a/pyrogram/types/messages_and_media/message_entity.py b/pyrogram/types/messages_and_media/message_entity.py index d2bf654dcd..a051fcbfbc 100644 --- a/pyrogram/types/messages_and_media/message_entity.py +++ b/pyrogram/types/messages_and_media/message_entity.py @@ -19,8 +19,7 @@ from typing import Optional import pyrogram -from pyrogram import raw, enums -from pyrogram import types +from pyrogram import raw, enums, types from ..object import Object @@ -82,6 +81,12 @@ def _parse(client, entity: "raw.base.MessageEntity", users: dict) -> Optional["M if isinstance(entity, raw.types.InputMessageEntityMentionName): entity_type = enums.MessageEntityType.TEXT_MENTION user_id = entity.user_id.user_id + elif isinstance(entity, raw.types.MessageEntityBlockquote): + if entity.collapsed: + entity_type = enums.MessageEntityType.EXPANDABLE_BLOCKQUOTE + else: + entity_type = enums.MessageEntityType.BLOCKQUOTE + user_id = None else: entity_type = enums.MessageEntityType(entity.__class__) user_id = getattr(entity, "user_id", None) @@ -116,6 +121,9 @@ async def write(self): if self.custom_emoji_id is not None: args["document_id"] = self.custom_emoji_id + if self.type == enums.MessageEntityType.EXPANDABLE_BLOCKQUOTE: + args["collapsed"] = True + entity = self.type.value if entity is raw.types.MessageEntityMentionName: From 3eddb9a5eb10a7f71c5c072de77630a1d7cdc516 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 28 May 2024 21:54:07 +0200 Subject: [PATCH 061/154] Added the field effect_id to the Message. --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/types/messages_and_media/message.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 2606351a1b..5a04389043 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue Date: Tue, 28 May 2024 22:04:26 +0200 Subject: [PATCH 062/154] Added the field show_caption_above_media to the Message. --- docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/types/messages_and_media/message.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 5a04389043..1a8311e91f 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue Date: Wed, 29 May 2024 09:34:57 +0200 Subject: [PATCH 063/154] Add show_caption_above_media --- docs/source/releases/changes-in-this-fork.rst | 3 ++- pyrogram/methods/messages/copy_media_group.py | 5 ++++- pyrogram/methods/messages/send_media_group.py | 6 +++++- .../types/inline_mode/inline_query_result_animation.py | 8 +++++++- .../inline_mode/inline_query_result_cached_animation.py | 8 +++++++- .../types/inline_mode/inline_query_result_cached_photo.py | 8 +++++++- .../types/inline_mode/inline_query_result_cached_video.py | 8 +++++++- pyrogram/types/inline_mode/inline_query_result_photo.py | 8 +++++++- pyrogram/types/inline_mode/inline_query_result_video.py | 8 +++++++- pyrogram/types/input_media/input_media_animation.py | 5 +++++ pyrogram/types/input_media/input_media_photo.py | 5 +++++ pyrogram/types/input_media/input_media_video.py | 5 +++++ 12 files changed, 68 insertions(+), 9 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 1a8311e91f..6a074a56aa 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,8 @@ If you found any issue or have any suggestions, feel free to make `an issue Date: Wed, 29 May 2024 09:57:13 +0200 Subject: [PATCH 064/154] Add message_effect_id to send* methods --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/bots/send_game.py | 5 +++++ pyrogram/methods/messages/send_animation.py | 5 +++++ pyrogram/methods/messages/send_audio.py | 5 +++++ pyrogram/methods/messages/send_contact.py | 7 ++++++- pyrogram/methods/messages/send_dice.py | 5 +++++ pyrogram/methods/messages/send_document.py | 5 +++++ pyrogram/methods/messages/send_location.py | 7 ++++++- pyrogram/methods/messages/send_media_group.py | 5 +++++ pyrogram/methods/messages/send_message.py | 9 ++++++++- pyrogram/methods/messages/send_photo.py | 5 +++++ pyrogram/methods/messages/send_poll.py | 7 ++++++- pyrogram/methods/messages/send_sticker.py | 5 +++++ pyrogram/methods/messages/send_venue.py | 7 ++++++- pyrogram/methods/messages/send_video.py | 5 +++++ pyrogram/methods/messages/send_video_note.py | 5 +++++ pyrogram/methods/messages/send_voice.py | 5 +++++ pyrogram/types/messages_and_media/message.py | 5 +++++ 18 files changed, 93 insertions(+), 5 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 6a074a56aa..15e4621696 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue List["types.Message"]: """Send a group of photos or videos as an album. @@ -81,6 +82,9 @@ async def send_media_group( protect_content (``bool``, *optional*): Protects the contents of the sent message from forwarding and saving. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + Returns: List of :obj:`~pyrogram.types.Message`: On success, a list of the sent messages is returned. @@ -447,6 +451,7 @@ async def send_media_group( reply_to=reply_to, schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, + effect=message_effect_id, invert_media=any(show_caption_above_media) ) session = None diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index 8aacdc8e4f..c09bb81fec 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -39,6 +39,7 @@ async def send_message( protect_content: bool = None, message_thread_id: int = None, business_connection_id: str = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -86,6 +87,9 @@ async def send_message( business_connection_id (``str``, *optional*): Unique identifier of the business connection on behalf of which the message will be sent. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -204,7 +208,8 @@ async def send_message( ), invert_media=link_preview_options.show_above_text, entities=entities, - noforwards=protect_content + noforwards=protect_content, + effect=message_effect_id ) if business_connection_id: r = await session.invoke( @@ -250,6 +255,7 @@ async def send_message( message=message, entities=entities, # TODO + effect=message_effect_id ) if business_connection_id: r = await session.invoke( @@ -280,6 +286,7 @@ async def send_message( message=message, entities=entities, # TODO + effect=message_effect_id ) if business_connection_id: r = await session.invoke( diff --git a/pyrogram/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py index 796b3a9030..9df621a030 100644 --- a/pyrogram/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -48,6 +48,7 @@ async def send_photo( schedule_date: datetime = None, protect_content: bool = None, view_once: bool = None, + message_effect_id: int = None, reply_markup: Union[ "types.InlineKeyboardMarkup", "types.ReplyKeyboardMarkup", @@ -115,6 +116,9 @@ async def send_photo( view_once (``bool``, *optional*): Pass True if the photo should be viewable only once. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -221,6 +225,7 @@ async def send_photo( schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index 7ca2bf164e..07f7bde6b4 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -50,6 +50,7 @@ async def send_poll( message_thread_id: int = None, business_connection_id: str = None, schedule_date: datetime = None, + message_effect_id: int = None, reply_markup: Union[ "types.InlineKeyboardMarkup", "types.ReplyKeyboardMarkup", @@ -140,6 +141,9 @@ async def send_poll( schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -222,7 +226,8 @@ async def send_poll( random_id=self.rnd_id(), schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, - reply_markup=await reply_markup.write(self) if reply_markup else None + reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id ) if business_connection_id: r = await self.invoke( diff --git a/pyrogram/methods/messages/send_sticker.py b/pyrogram/methods/messages/send_sticker.py index 820f77b73c..c79a763887 100644 --- a/pyrogram/methods/messages/send_sticker.py +++ b/pyrogram/methods/messages/send_sticker.py @@ -44,6 +44,7 @@ async def send_sticker( protect_content: bool = None, message_thread_id: int = None, business_connection_id: str = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -99,6 +100,9 @@ async def send_sticker( business_connection_id (``str``, *optional*): Unique identifier of the business connection on behalf of which the message will be sent. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -208,6 +212,7 @@ async def send_sticker( schedule_date=utils.datetime_to_timestamp(schedule_date), + effect=message_effect_id, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/methods/messages/send_venue.py b/pyrogram/methods/messages/send_venue.py index 0b20894455..a1d95c8aa0 100644 --- a/pyrogram/methods/messages/send_venue.py +++ b/pyrogram/methods/messages/send_venue.py @@ -42,6 +42,7 @@ async def send_venue( business_connection_id: str = None, schedule_date: datetime = None, protect_content: bool = None, + message_effect_id: int = None, reply_markup: Union[ "types.InlineKeyboardMarkup", "types.ReplyKeyboardMarkup", @@ -98,6 +99,9 @@ async def send_venue( protect_content (``bool``, *optional*): Protects the contents of the sent message from forwarding and saving. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -151,7 +155,8 @@ async def send_venue( random_id=self.rnd_id(), schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, - reply_markup=await reply_markup.write(self) if reply_markup else None + reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id ) if business_connection_id: r = await self.invoke( diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index cbc81820b3..70eb9f3875 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -49,6 +49,7 @@ async def send_video( protect_content: bool = None, message_thread_id: int = None, business_connection_id: str = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -126,6 +127,9 @@ async def send_video( business_connection_id (``str``, *optional*): Unique identifier of the business connection on behalf of which the message will be sent. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -280,6 +284,7 @@ async def progress(current, total): schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/methods/messages/send_video_note.py b/pyrogram/methods/messages/send_video_note.py index 9675a2b1f8..8ffde7a7a8 100644 --- a/pyrogram/methods/messages/send_video_note.py +++ b/pyrogram/methods/messages/send_video_note.py @@ -42,6 +42,7 @@ async def send_video_note( protect_content: bool = None, message_thread_id: int = None, business_connection_id: str = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -101,6 +102,9 @@ async def send_video_note( business_connection_id (``str``, *optional*): Unique identifier of the business connection on behalf of which the message will be sent. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -245,6 +249,7 @@ async def send_video_note( schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/methods/messages/send_voice.py b/pyrogram/methods/messages/send_voice.py index ee8dd32947..71e85e1ca1 100644 --- a/pyrogram/methods/messages/send_voice.py +++ b/pyrogram/methods/messages/send_voice.py @@ -44,6 +44,7 @@ async def send_voice( protect_content: bool = None, message_thread_id: int = None, business_connection_id: str = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -102,6 +103,9 @@ async def send_voice( business_connection_id (``str``, *optional*): Unique identifier of the business connection on behalf of which the message will be sent. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -240,6 +244,7 @@ async def send_voice( schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index d088c53a53..7bf099a58f 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1342,6 +1342,7 @@ async def reply_text( link_preview_options: "types.LinkPreviewOptions" = None, disable_notification: bool = None, protect_content: bool = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -1400,6 +1401,9 @@ async def reply_text( protect_content (``bool``, *optional*): Protects the contents of the sent message from forwarding and saving. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -1434,6 +1438,7 @@ async def reply_text( protect_content=protect_content, message_thread_id=self.message_thread_id, business_connection_id=self.business_connection_id, + message_effect_id=message_effect_id, reply_parameters=reply_parameters, reply_markup=reply_markup, schedule_date=schedule_date, From 3f9b18ba6ce8fcce4ee7c538d967d2b6cd99632c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 29 May 2024 09:58:06 +0200 Subject: [PATCH 065/154] Update Pyrogram to v2.1.32.2 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 8182d4019d..27d825a300 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.1" +__version__ = "2.1.32.2" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 36e7f76248c863323f5436ac98bd08b67f613f80 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 1 Jun 2024 08:42:53 +0200 Subject: [PATCH 066/154] Add ``message_effect_id`` to remaining bound Methods Update API scheme from TDesktop --- docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/types/messages_and_media/message.py | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 15e4621696..b24575c9ef 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue Date: Sat, 1 Jun 2024 09:11:47 +0200 Subject: [PATCH 067/154] Added show_caption_above_media to send_cached_media, send_animation, send_photo, send_video, copy_message, and edit_message_caption, edit_cached_media --- docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/methods/messages/copy_message.py | 5 ++++ .../methods/messages/edit_cached_media.py | 5 ++++ .../methods/messages/edit_message_caption.py | 11 +++++++ .../methods/messages/edit_message_media.py | 1 + pyrogram/methods/messages/send_animation.py | 5 ++++ .../methods/messages/send_cached_media.py | 10 +++++++ pyrogram/methods/messages/send_photo.py | 5 ++++ pyrogram/methods/messages/send_video.py | 5 ++++ pyrogram/types/messages_and_media/message.py | 30 +++++++++++++++++++ 10 files changed, 78 insertions(+), 1 deletion(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index b24575c9ef..38f5b3b3c9 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -16,7 +16,7 @@ If you found any issue or have any suggestions, feel free to make `an issue "types.Message": @@ -57,6 +58,9 @@ async def edit_message_caption( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages. + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. @@ -71,6 +75,12 @@ async def edit_message_caption( await app.edit_message_caption(chat_id, message_id, "new media caption") """ + link_preview_options = None + if show_caption_above_media: + link_preview_options = types.LinkPreviewOptions( + show_above_text=show_caption_above_media + ) + return await self.edit_message_text( chat_id=chat_id, message_id=message_id, @@ -78,5 +88,6 @@ async def edit_message_caption( parse_mode=parse_mode, entities=caption_entities, reply_markup=reply_markup, + link_preview_options=link_preview_options, schedule_date=schedule_date ) diff --git a/pyrogram/methods/messages/edit_message_media.py b/pyrogram/methods/messages/edit_message_media.py index bad30ffabb..f4fcdde50c 100644 --- a/pyrogram/methods/messages/edit_message_media.py +++ b/pyrogram/methods/messages/edit_message_media.py @@ -287,6 +287,7 @@ async def edit_message_media( reply_markup=await reply_markup.write(self) if reply_markup else None, message=message, entities=entities, + # TODO schedule_date=utils.datetime_to_timestamp(schedule_date) ) ) diff --git a/pyrogram/methods/messages/send_animation.py b/pyrogram/methods/messages/send_animation.py index 7d57dad2f4..8d6a3acd57 100644 --- a/pyrogram/methods/messages/send_animation.py +++ b/pyrogram/methods/messages/send_animation.py @@ -39,6 +39,7 @@ async def send_animation( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, unsave: bool = False, has_spoiler: bool = None, duration: int = 0, @@ -91,6 +92,9 @@ async def send_animation( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + unsave (``bool``, *optional*): By default, the server will save into your own collection any new animation you send. Pass True to automatically unsave the sent animation. Defaults to False. @@ -283,6 +287,7 @@ async def progress(current, total): noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, effect=message_effect_id, + invert_media=show_caption_above_media, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/methods/messages/send_cached_media.py b/pyrogram/methods/messages/send_cached_media.py index 56abf672d4..4f15cb7a6e 100644 --- a/pyrogram/methods/messages/send_cached_media.py +++ b/pyrogram/methods/messages/send_cached_media.py @@ -34,7 +34,9 @@ async def send_cached_media( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, disable_notification: bool = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, message_thread_id: int = None, business_connection_id: str = None, @@ -77,10 +79,16 @@ async def send_cached_media( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages. + disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -139,6 +147,8 @@ async def send_cached_media( schedule_date=utils.datetime_to_timestamp(schedule_date), noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, + invert_media=show_caption_above_media, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) diff --git a/pyrogram/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py index 9df621a030..7bc42668cc 100644 --- a/pyrogram/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -39,6 +39,7 @@ async def send_photo( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, has_spoiler: bool = None, ttl_seconds: int = None, disable_notification: bool = None, @@ -86,6 +87,9 @@ async def send_photo( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + has_spoiler (``bool``, *optional*): Pass True if the photo needs to be covered with a spoiler animation. @@ -226,6 +230,7 @@ async def send_photo( noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, effect=message_effect_id, + invert_media=show_caption_above_media, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index 70eb9f3875..1ead3b898b 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -39,6 +39,7 @@ async def send_video( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, duration: int = 0, width: int = 0, height: int = 0, @@ -92,6 +93,9 @@ async def send_video( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + duration (``int``, *optional*): Duration of sent video in seconds. @@ -285,6 +289,7 @@ async def progress(current, total): noforwards=protect_content, reply_markup=await reply_markup.write(self) if reply_markup else None, effect=message_effect_id, + invert_media=show_caption_above_media, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) session = None diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 4b29747f04..534b7e2417 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1455,6 +1455,7 @@ async def reply_animation( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, unsave: bool = False, has_spoiler: bool = None, duration: int = 0, @@ -1516,6 +1517,9 @@ async def reply_animation( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + unsave (``bool``, *optional*): By default, the server will save into your own collection any new animation you send. Pass True to automatically unsave the sent animation. Defaults to False. @@ -1611,6 +1615,7 @@ async def reply_animation( caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + show_caption_above_media=show_caption_above_media, unsave=unsave, has_spoiler=has_spoiler, duration=duration, @@ -1805,7 +1810,9 @@ async def reply_cached_media( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, disable_notification: bool = None, + message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, schedule_date: datetime = None, reply_markup: Union[ @@ -1852,10 +1859,16 @@ async def reply_cached_media( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages. + disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to @@ -1886,7 +1899,9 @@ async def reply_cached_media( caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + show_caption_above_media=show_caption_above_media, disable_notification=disable_notification, + message_effect_id=message_effect_id, reply_parameters=reply_parameters, message_thread_id=self.message_thread_id, business_connection_id=self.business_connection_id, @@ -2562,6 +2577,7 @@ async def reply_photo( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, has_spoiler: bool = None, ttl_seconds: int = None, disable_notification: bool = None, @@ -2618,6 +2634,9 @@ async def reply_photo( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + has_spoiler (``bool``, *optional*): Pass True if the photo needs to be covered with a spoiler animation. @@ -2693,6 +2712,7 @@ async def reply_photo( caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + show_caption_above_media=show_caption_above_media, has_spoiler=has_spoiler, ttl_seconds=ttl_seconds, disable_notification=disable_notification, @@ -3121,6 +3141,7 @@ async def reply_video( caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, duration: int = 0, width: int = 0, height: int = 0, @@ -3183,6 +3204,9 @@ async def reply_video( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + duration (``int``, *optional*): Duration of sent video in seconds. @@ -3281,6 +3305,7 @@ async def reply_video( caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + show_caption_above_media=show_caption_above_media, duration=duration, width=width, height=height, @@ -3969,6 +3994,7 @@ async def copy( caption: str = None, parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, disable_notification: bool = None, reply_parameters: "types.ReplyParameters" = None, reply_markup: Union[ @@ -4018,6 +4044,9 @@ async def copy( caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the new caption, which can be specified instead of *parse_mode*. + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. Ignored if a new caption isn't specified. + disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. @@ -4080,6 +4109,7 @@ async def copy( chat_id=chat_id, disable_notification=disable_notification, message_effect_id=self.effect_id, + show_caption_above_media=show_caption_above_media, reply_parameters=reply_parameters, message_thread_id=message_thread_id or self.message_thread_id, business_connection_id=business_connection_id or self.business_connection_id, From 450391b3b480a93e16115e18f0127a04eb0f2c00 Mon Sep 17 00:00:00 2001 From: Hitalo M Date: Sat, 1 Jun 2024 09:15:03 +0200 Subject: [PATCH 068/154] refactor(session): replace recursion with loop and add backoff This refactor replaces recursion with a loop in the session invoke logic. Additionally, a backoff mechanism has been introduced to prevent frequent restarts from crashing the bot. --- pyrogram/session/session.py | 42 ++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 857d3eef89..a6ee2119d3 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -20,6 +20,7 @@ import bisect import logging import os +from datetime import datetime, timedelta from hashlib import sha1 from io import BytesIO @@ -54,6 +55,7 @@ class Session: ACKS_THRESHOLD = 10 PING_INTERVAL = 5 STORED_MSG_IDS_MAX_SIZE = 1000 * 2 + RECONNECT_THRESHOLD = timedelta(seconds=10) TRANSPORT_ERRORS = { 404: "auth key not found", @@ -107,6 +109,8 @@ def __init__( self.loop = asyncio.get_event_loop() + self.last_reconnect_attempt = None + async def start(self): while True: self.connection = Connection( @@ -193,6 +197,16 @@ async def stop(self): log.info("Session stopped") async def restart(self): + now = datetime.now() + if ( + self.last_reconnect_attempt + and now - self.last_reconnect_attempt < self.RECONNECT_THRESHOLD + ): + log.info("Reconnecting too frequently, sleeping for a while") + await asyncio.sleep(5) + + self.last_reconnect_attempt = now + await self.stop() await self.start() @@ -400,7 +414,7 @@ async def invoke( query_name = ".".join(inner_query.QUALNAME.split(".")[1:]) - while True: + while retries > 0: try: return await self.send(query, timeout=timeout) except (FloodWait, FloodPremiumWait) as e: @@ -414,22 +428,26 @@ async def invoke( await asyncio.sleep(amount) except (OSError, InternalServerError, ServiceUnavailable) as e: - if retries == 0 \ - or ( - isinstance(e, InternalServerError) - and getattr(e, "code", 0) == 500 - and (e.ID or e.NAME) in [ - "HISTORY_GET_FAILED" - ] - ): + retries -= 1 + if ( + retries == 0 or + ( + isinstance(e, InternalServerError) + and getattr(e, "code", 0) == 500 + and (e.ID or e.NAME) in [ + "HISTORY_GET_FAILED" + ] + ) + ): raise e from None (log.warning if retries < 2 else log.info)( '[%s] Retrying "%s" due to: %s', - Session.MAX_RETRIES - retries + 1, - query_name, str(e) or repr(e) + Session.MAX_RETRIES - retries, + query_name, + str(e) or repr(e) ) await asyncio.sleep(3) - return await self.invoke(query, retries - 1, timeout) + raise TimeoutError("Exceeded maximum number of retries") From 030978d6831a369c9cbaf2500107412b4df34aae Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Sat, 1 Jun 2024 00:52:22 +0300 Subject: [PATCH 069/154] Write update state to session only if Client.skip_updates = False --- pyrogram/client.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pyrogram/client.py b/pyrogram/client.py index 39c4b31366..2db21fe20e 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -623,7 +623,7 @@ async def handle_updates(self, updates): pts = getattr(update, "pts", None) pts_count = getattr(update, "pts_count", None) - if pts: + if pts and not self.skip_updates: await self.storage.update_state( ( utils.get_channel_id(channel_id) if channel_id else 0, @@ -664,15 +664,16 @@ async def handle_updates(self, updates): self.dispatcher.updates_queue.put_nowait((update, users, chats)) elif isinstance(updates, (raw.types.UpdateShortMessage, raw.types.UpdateShortChatMessage)): - await self.storage.update_state( - ( - 0, - updates.pts, - None, - updates.date, - None + if not self.skip_updates: + await self.storage.update_state( + ( + 0, + updates.pts, + None, + updates.date, + None + ) ) - ) diff = await self.invoke( raw.functions.updates.GetDifference( From c44ea520224f56edeb36d887c90d127d12845880 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 1 Jun 2024 17:16:49 +0200 Subject: [PATCH 070/154] Add get_message_effects to get the list of available message effects --- compiler/docs/compiler.py | 2 + docs/source/releases/changes-in-this-fork.rst | 3 +- .../messages/get_custom_emoji_stickers.py | 5 +- pyrogram/methods/stickers/__init__.py | 2 + .../methods/stickers/get_message_effects.py | 67 ++++++++++ pyrogram/types/messages_and_media/__init__.py | 2 + pyrogram/types/messages_and_media/message.py | 2 +- .../messages_and_media/message_effect.py | 119 ++++++++++++++++++ 8 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 pyrogram/methods/stickers/get_message_effects.py create mode 100644 pyrogram/types/messages_and_media/message_effect.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 3e28e9e8ca..2ea6801ec2 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -346,6 +346,7 @@ def get_title_list(s: str) -> list: """, stickers=""" Stickers + get_message_effects get_stickers """, users=""" @@ -520,6 +521,7 @@ def get_title_list(s: str) -> list: GiveawayWinners Location Message + MessageEffect MessageEntity MessageImportInfo MessageOrigin diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 38f5b3b3c9..1968694d1f 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,8 @@ If you found any issue or have any suggestions, feel free to make `an issue . +from .get_message_effects import GetMessageEffects from .get_stickers import GetStickers class Stickers( + GetMessageEffects, GetStickers, ): pass diff --git a/pyrogram/methods/stickers/get_message_effects.py b/pyrogram/methods/stickers/get_message_effects.py new file mode 100644 index 0000000000..b16e00859c --- /dev/null +++ b/pyrogram/methods/stickers/get_message_effects.py @@ -0,0 +1,67 @@ +# 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 . + +import logging +from typing import List + +import pyrogram +from pyrogram import raw +from pyrogram import types + +log = logging.getLogger(__name__) + + +class GetMessageEffects: + async def get_message_effects( + self: "pyrogram.Client" + ) -> List["types.MessageEffect"]: + """Returns information about all available message effects. + + .. include:: /_includes/usable-by/users.rst + + Returns: + List of :obj:`~pyrogram.types.MessageEffect`: A list of message effects is returned. + + Example: + .. code-block:: python + + # Get all message effects + await app.get_message_effects() + + """ + r = await self.invoke( + raw.functions.messages.GetAvailableEffects( + hash=0 + ) + ) + documents = {d.id: d for d in r.documents} + outlst = [] + for effect in r.effects: + effect_animation_document = documents.get(effect.effect_sticker_id, None) + static_icon_document = documents.get(effect.static_icon_id, None) if getattr(effect, "static_icon_id", None) else None + select_animation_document = documents.get(effect.effect_animation_id, None) if getattr(effect, "effect_animation_id", None) else None + outlst.append( + await types.MessageEffect._parse( + self, + effect, + effect_animation_document, + static_icon_document, + select_animation_document + ) + ) + return types.List(outlst) diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index fe812cc81a..969d7c0ad8 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -55,6 +55,7 @@ from .giveaway_winners import GiveawayWinners from .gift_code import GiftCode from .gifted_premium import GiftedPremium +from .message_effect import MessageEffect __all__ = [ "Animation", @@ -71,6 +72,7 @@ "GiveawayWinners", "Location", "Message", + "MessageEffect", "MessageEntity", "MessageReactionCountUpdated", "MessageReactionUpdated", diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 534b7e2417..7e01ea6ee2 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -147,7 +147,7 @@ class Message(Object, Update): Options used for link preview generation for the message, if it is a text message and link preview options were changed effect_id (``str``, *optional*): - Unique identifier of the message effect added to the message. + Unique identifier of the message effect added to the message. Use :meth:`~pyrogram.Client.get_message_effects` to get the list of available message effect ids. animation (:obj:`~pyrogram.types.Animation`, *optional*): Message is an animation, information about the animation. diff --git a/pyrogram/types/messages_and_media/message_effect.py b/pyrogram/types/messages_and_media/message_effect.py new file mode 100644 index 0000000000..8ae3f7a740 --- /dev/null +++ b/pyrogram/types/messages_and_media/message_effect.py @@ -0,0 +1,119 @@ +# 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 Optional + +from pyrogram import raw, types +from ..object import Object + + +class MessageEffect(Object): + """Contains information about an effect added to a message. + + Parameters: + id (``int`` ``64-bit``, *optional*): + Unique identifier of the effect. + + emoji (``str``): + Emoji that represents the effect. + + static_icon (:obj:`~pyrogram.types.Sticker`, *optional*): + Static icon for the effect in WEBP format; may be null if none + + effect_animation (:obj:`~pyrogram.types.Document`, *optional*): + Effect animation for the effect in TGS format. + + select_animation (:obj:`~pyrogram.types.Document`, *optional*): + Select animation for the effect in TGS format. + + is_premium (``bool``, *optional*): + True, if Telegram Premium subscription is required to use the effect. + + """ + + def __init__( + self, + *, + id: int, + emoji: str, + static_icon: Optional["types.Sticker"] = None, + effect_animation: Optional["types.Document"] = None, + select_animation: Optional["types.Document"] = None, + is_premium: Optional[bool] = None + ): + super().__init__() + + self.id = id + self.emoji = emoji + self.static_icon = static_icon + self.effect_animation = effect_animation + self.select_animation = select_animation + self.is_premium = is_premium + + @staticmethod + async def _parse( + client, + effect: "raw.types.AvailableEffect", + effect_animation_document: "raw.types.Document" = None, + static_icon_document: "raw.types.Document" = None, + select_animation_document: "raw.types.Document" = None + ) -> "MessageEffect": + effect_animation = None + static_icon = None + select_animation = None + + effect_sticker_id = effect.effect_sticker_id + static_icon_id = getattr(effect, "static_icon_id", None) + effect_animation_id = getattr(effect, "effect_animation_id", None) + + if effect_animation_document: + effect_animation = await types.Sticker._parse( + client, + effect_animation_document, + {type(i): i for i in effect_animation_document.attributes} + ) + # TODO: FIXME! + if static_icon_document: + document_attributes = { + type(i): i for i in static_icon_document.attributes + } + file_name = getattr(document_attributes.get(raw.types.DocumentAttributeFilename, None), "file_name", None) + static_icon = types.Document._parse( + client, + static_icon_document, + file_name + ) + if select_animation_document: + document_attributes = { + type(i): i for i in select_animation_document.attributes + } + file_name = getattr(document_attributes.get(raw.types.DocumentAttributeFilename, None), "file_name", None) + select_animation = types.Document._parse( + client, + select_animation_document, + file_name + ) + + return MessageEffect( + id=effect.id, + emoji=effect.emoticon, + static_icon=static_icon, + effect_animation=effect_animation, # TODO: FIXME! + select_animation=select_animation, # TODO: FIXME! + is_premium=getattr(effect, "premium_required", None) + ) From 637c5b59030aac5e270abb6f8ef1e9fdcf311831 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 1 Jun 2024 17:39:54 +0200 Subject: [PATCH 071/154] Add the fetch_replies parameter to Client --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/client.py | 6 +++++ pyrogram/dispatcher.py | 6 +++-- pyrogram/methods/bots/send_game.py | 6 +++-- pyrogram/methods/bots/set_game_score.py | 3 ++- .../methods/chat_topics/close_forum_topic.py | 2 +- .../methods/chat_topics/create_forum_topic.py | 2 +- .../methods/chat_topics/edit_forum_topic.py | 2 +- .../methods/chat_topics/get_forum_topic.py | 6 ++++- .../methods/chat_topics/get_forum_topics.py | 6 ++++- .../methods/chat_topics/hide_forum_topic.py | 2 +- .../methods/chat_topics/reopen_forum_topic.py | 2 +- .../methods/chat_topics/unhide_forum_topic.py | 2 +- pyrogram/methods/chats/add_chat_members.py | 4 ++- pyrogram/methods/chats/ban_chat_member.py | 6 +++-- pyrogram/methods/chats/get_dialogs.py | 8 +++++- pyrogram/methods/chats/pin_chat_message.py | 8 +++++- pyrogram/methods/chats/promote_chat_member.py | 3 ++- pyrogram/methods/chats/set_chat_ttl.py | 1 + .../methods/messages/edit_cached_media.py | 2 +- .../methods/messages/edit_message_media.py | 2 +- .../messages/edit_message_reply_markup.py | 3 ++- .../methods/messages/edit_message_text.py | 2 +- pyrogram/methods/messages/forward_messages.py | 3 ++- .../messages/get_discussion_message.py | 8 +++++- .../messages/get_discussion_replies.py | 8 +++++- pyrogram/methods/messages/send_animation.py | 6 +++-- pyrogram/methods/messages/send_audio.py | 6 +++-- .../methods/messages/send_cached_media.py | 6 +++-- pyrogram/methods/messages/send_contact.py | 6 +++-- pyrogram/methods/messages/send_dice.py | 6 +++-- pyrogram/methods/messages/send_document.py | 6 +++-- pyrogram/methods/messages/send_location.py | 6 +++-- pyrogram/methods/messages/send_message.py | 5 ++-- pyrogram/methods/messages/send_photo.py | 6 +++-- pyrogram/methods/messages/send_poll.py | 6 +++-- pyrogram/methods/messages/send_sticker.py | 6 +++-- pyrogram/methods/messages/send_venue.py | 6 +++-- pyrogram/methods/messages/send_video.py | 6 +++-- pyrogram/methods/messages/send_video_note.py | 6 +++-- pyrogram/methods/messages/send_voice.py | 6 +++-- pyrogram/types/messages_and_media/message.py | 3 ++- pyrogram/types/user_and_chats/chat_event.py | 27 ++++++++++++++----- pyrogram/utils.py | 7 ++--- 44 files changed, 164 insertions(+), 66 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 1968694d1f..5fae777572 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue ` + """ APP_VERSION = f"Pyrogram {__version__}" @@ -277,6 +281,7 @@ def __init__( no_joined_notifications: bool = False, client_platform: enums.ClientPlatform = enums.ClientPlatform.OTHER, link_preview_options: "types.LinkPreviewOptions" = None, + fetch_replies: int = 1, _un_docu_gnihts: List = [] ): super().__init__() @@ -315,6 +320,7 @@ def __init__( self.client_platform = client_platform self._un_docu_gnihts = _un_docu_gnihts self.link_preview_options = link_preview_options + self.fetch_replies = fetch_replies self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler") diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index 8016db0aed..3658b7cfdb 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -88,6 +88,7 @@ def __init__(self, client: "pyrogram.Client"): self.groups = OrderedDict() async def message_parser(update, users, chats): + business_connection_id = getattr(update, "connection_id", None) return ( await pyrogram.types.Message._parse( self.client, @@ -95,8 +96,9 @@ async def message_parser(update, users, chats): users, chats, is_scheduled=isinstance(update, UpdateNewScheduledMessage), - business_connection_id=getattr(update, "connection_id", None), - raw_reply_to_message=getattr(update, "reply_to_message", None) + business_connection_id=business_connection_id, + raw_reply_to_message=getattr(update, "reply_to_message", None), + replies=0 if business_connection_id else self.client.fetch_replies ), MessageHandler ) diff --git a/pyrogram/methods/bots/send_game.py b/pyrogram/methods/bots/send_game.py index b4ae79fa94..2f97e98246 100644 --- a/pyrogram/methods/bots/send_game.py +++ b/pyrogram/methods/bots/send_game.py @@ -135,7 +135,8 @@ async def send_game( return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, - {i.id: i for i in r.chats} + {i.id: i for i in r.chats}, + replies=self.fetch_replies ) elif isinstance( i, @@ -149,5 +150,6 @@ async def send_game( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=i.connection_id, - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/bots/set_game_score.py b/pyrogram/methods/bots/set_game_score.py index b3b58b2362..020e17293d 100644 --- a/pyrogram/methods/bots/set_game_score.py +++ b/pyrogram/methods/bots/set_game_score.py @@ -94,7 +94,8 @@ async def set_game_score( return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, - {i.id: i for i in r.chats} + {i.id: i for i in r.chats}, + replies=self.fetch_replies ) return True diff --git a/pyrogram/methods/chat_topics/close_forum_topic.py b/pyrogram/methods/chat_topics/close_forum_topic.py index 92b8479867..754faead6e 100644 --- a/pyrogram/methods/chat_topics/close_forum_topic.py +++ b/pyrogram/methods/chat_topics/close_forum_topic.py @@ -80,5 +80,5 @@ async def close_forum_topic( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=2 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/chat_topics/create_forum_topic.py b/pyrogram/methods/chat_topics/create_forum_topic.py index e92fb9dcfa..41283c3660 100644 --- a/pyrogram/methods/chat_topics/create_forum_topic.py +++ b/pyrogram/methods/chat_topics/create_forum_topic.py @@ -94,5 +94,5 @@ async def create_forum_topic( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=2 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/chat_topics/edit_forum_topic.py b/pyrogram/methods/chat_topics/edit_forum_topic.py index daa1a57729..060e05a5f6 100644 --- a/pyrogram/methods/chat_topics/edit_forum_topic.py +++ b/pyrogram/methods/chat_topics/edit_forum_topic.py @@ -90,5 +90,5 @@ async def edit_forum_topic( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=2 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/chat_topics/get_forum_topic.py b/pyrogram/methods/chat_topics/get_forum_topic.py index 35066e4fb3..a965491023 100644 --- a/pyrogram/methods/chat_topics/get_forum_topic.py +++ b/pyrogram/methods/chat_topics/get_forum_topic.py @@ -76,7 +76,11 @@ async def get_forum_topic( messages = {} for message in getattr(r, "messages", []): messages[message.id] = await types.Message._parse( - self, message, users, chats, replies=0 + self, + message, + users, + chats, + replies=self.fetch_replies ) topics = types.List() diff --git a/pyrogram/methods/chat_topics/get_forum_topics.py b/pyrogram/methods/chat_topics/get_forum_topics.py index b7931bfc6b..f64d0d2e85 100644 --- a/pyrogram/methods/chat_topics/get_forum_topics.py +++ b/pyrogram/methods/chat_topics/get_forum_topics.py @@ -93,7 +93,11 @@ async def get_forum_topics( for message in getattr(r, "messages", []): messages[message.id] = await types.Message._parse( - self, message, users, chats, replies=0 + self, + message, + users, + chats, + replies=self.fetch_replies ) topics = [] diff --git a/pyrogram/methods/chat_topics/hide_forum_topic.py b/pyrogram/methods/chat_topics/hide_forum_topic.py index ca81848117..2ff59fe676 100644 --- a/pyrogram/methods/chat_topics/hide_forum_topic.py +++ b/pyrogram/methods/chat_topics/hide_forum_topic.py @@ -78,5 +78,5 @@ async def hide_forum_topic( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=2 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/chat_topics/reopen_forum_topic.py b/pyrogram/methods/chat_topics/reopen_forum_topic.py index 65b72d1e7d..93f1b0307e 100644 --- a/pyrogram/methods/chat_topics/reopen_forum_topic.py +++ b/pyrogram/methods/chat_topics/reopen_forum_topic.py @@ -82,5 +82,5 @@ async def reopen_forum_topic( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=2 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/chat_topics/unhide_forum_topic.py b/pyrogram/methods/chat_topics/unhide_forum_topic.py index 713f5a216d..40324669b2 100644 --- a/pyrogram/methods/chat_topics/unhide_forum_topic.py +++ b/pyrogram/methods/chat_topics/unhide_forum_topic.py @@ -78,5 +78,5 @@ async def unhide_forum_topic( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=2 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/chats/add_chat_members.py b/pyrogram/methods/chats/add_chat_members.py index 573220c39f..85ae8fe8b7 100644 --- a/pyrogram/methods/chats/add_chat_members.py +++ b/pyrogram/methods/chats/add_chat_members.py @@ -106,9 +106,11 @@ async def add_chat_members( ): _rc.append( await types.Message._parse( - self, i.message, + self, + i.message, {i.id: i for i in rr.updates.users}, {i.id: i for i in rr.updates.chats}, + replies=self.fetch_replies ) ) break diff --git a/pyrogram/methods/chats/ban_chat_member.py b/pyrogram/methods/chats/ban_chat_member.py index 37556dc70d..79769aa640 100644 --- a/pyrogram/methods/chats/ban_chat_member.py +++ b/pyrogram/methods/chats/ban_chat_member.py @@ -109,9 +109,11 @@ async def ban_chat_member( for i in r.updates: if isinstance(i, (raw.types.UpdateNewMessage, raw.types.UpdateNewChannelMessage)): return await types.Message._parse( - self, i.message, + self, + i.message, {i.id: i for i in r.users}, - {i.id: i for i in r.chats} + {i.id: i for i in r.chats}, + replies=self.fetch_replies ) else: return True diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index 3509ccbcca..6f561ee039 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -76,7 +76,13 @@ async def get_dialogs( continue chat_id = utils.get_peer_id(message.peer_id) - messages[chat_id] = await types.Message._parse(self, message, users, chats) + messages[chat_id] = await types.Message._parse( + self, + message, + users, + chats, + replies=self.fetch_replies + ) dialogs = [] diff --git a/pyrogram/methods/chats/pin_chat_message.py b/pyrogram/methods/chats/pin_chat_message.py index 8ec06e7b13..b6dd316726 100644 --- a/pyrogram/methods/chats/pin_chat_message.py +++ b/pyrogram/methods/chats/pin_chat_message.py @@ -78,4 +78,10 @@ async def pin_chat_message( for i in r.updates: if isinstance(i, (raw.types.UpdateNewMessage, raw.types.UpdateNewChannelMessage)): - return await types.Message._parse(self, i.message, users, chats) + return await types.Message._parse( + self, + i.message, + users, + chats, + replies=self.fetch_replies + ) diff --git a/pyrogram/methods/chats/promote_chat_member.py b/pyrogram/methods/chats/promote_chat_member.py index 1100559332..0e82452cbb 100644 --- a/pyrogram/methods/chats/promote_chat_member.py +++ b/pyrogram/methods/chats/promote_chat_member.py @@ -98,7 +98,8 @@ async def promote_chat_member( return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, - {i.id: i for i in r.chats} + {i.id: i for i in r.chats}, + replies=self.fetch_replies ) else: return True diff --git a/pyrogram/methods/chats/set_chat_ttl.py b/pyrogram/methods/chats/set_chat_ttl.py index 2baeeb900e..87ae52bb3f 100644 --- a/pyrogram/methods/chats/set_chat_ttl.py +++ b/pyrogram/methods/chats/set_chat_ttl.py @@ -69,4 +69,5 @@ async def set_chat_ttl( i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, + replies=self.fetch_replies ) diff --git a/pyrogram/methods/messages/edit_cached_media.py b/pyrogram/methods/messages/edit_cached_media.py index a3eddaecaa..c9e973d485 100644 --- a/pyrogram/methods/messages/edit_cached_media.py +++ b/pyrogram/methods/messages/edit_cached_media.py @@ -117,5 +117,5 @@ async def edit_cached_media( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=0 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/messages/edit_message_media.py b/pyrogram/methods/messages/edit_message_media.py index f4fcdde50c..f2fde50851 100644 --- a/pyrogram/methods/messages/edit_message_media.py +++ b/pyrogram/methods/messages/edit_message_media.py @@ -306,5 +306,5 @@ async def edit_message_media( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=0 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/messages/edit_message_reply_markup.py b/pyrogram/methods/messages/edit_message_reply_markup.py index 1cd75c1a8b..abbe5e686b 100644 --- a/pyrogram/methods/messages/edit_message_reply_markup.py +++ b/pyrogram/methods/messages/edit_message_reply_markup.py @@ -73,5 +73,6 @@ async def edit_message_reply_markup( return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, - {i.id: i for i in r.chats} + {i.id: i for i in r.chats}, + replies=self.fetch_replies ) diff --git a/pyrogram/methods/messages/edit_message_text.py b/pyrogram/methods/messages/edit_message_text.py index 8942ba2147..d46ea4665e 100644 --- a/pyrogram/methods/messages/edit_message_text.py +++ b/pyrogram/methods/messages/edit_message_text.py @@ -142,5 +142,5 @@ async def edit_message_text( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=0 + replies=self.fetch_replies ) diff --git a/pyrogram/methods/messages/forward_messages.py b/pyrogram/methods/messages/forward_messages.py index 3771bf43ec..ab6b95a2ab 100644 --- a/pyrogram/methods/messages/forward_messages.py +++ b/pyrogram/methods/messages/forward_messages.py @@ -128,7 +128,8 @@ async def forward_messages( i.message, users, chats, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) ) diff --git a/pyrogram/methods/messages/get_discussion_message.py b/pyrogram/methods/messages/get_discussion_message.py index 58a6b7044d..7d641a8d30 100644 --- a/pyrogram/methods/messages/get_discussion_message.py +++ b/pyrogram/methods/messages/get_discussion_message.py @@ -62,4 +62,10 @@ async def get_discussion_message( users = {u.id: u for u in r.users} chats = {c.id: c for c in r.chats} - return await types.Message._parse(self, r.messages[0], users, chats) + return await types.Message._parse( + self, + r.messages[0], + users, + chats, + replies=self.fetch_replies + ) diff --git a/pyrogram/methods/messages/get_discussion_replies.py b/pyrogram/methods/messages/get_discussion_replies.py index dd23751bb1..7ea8479775 100644 --- a/pyrogram/methods/messages/get_discussion_replies.py +++ b/pyrogram/methods/messages/get_discussion_replies.py @@ -78,7 +78,13 @@ async def get_discussion_replies( return for message in messages: - yield await types.Message._parse(self, message, users, chats, replies=0) + yield await types.Message._parse( + self, + message, + users, + chats, + replies=self.fetch_replies + ) current += 1 diff --git a/pyrogram/methods/messages/send_animation.py b/pyrogram/methods/messages/send_animation.py index 8d6a3acd57..3c63c91af3 100644 --- a/pyrogram/methods/messages/send_animation.py +++ b/pyrogram/methods/messages/send_animation.py @@ -330,7 +330,8 @@ async def progress(current, total): i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) if unsave: @@ -359,7 +360,8 @@ async def progress(current, total): {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_audio.py b/pyrogram/methods/messages/send_audio.py index a562355729..348571942c 100644 --- a/pyrogram/methods/messages/send_audio.py +++ b/pyrogram/methods/messages/send_audio.py @@ -296,7 +296,8 @@ async def progress(current, total): self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -310,7 +311,8 @@ async def progress(current, total): {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except StopTransmission: return None diff --git a/pyrogram/methods/messages/send_cached_media.py b/pyrogram/methods/messages/send_cached_media.py index 4f15cb7a6e..f3ea57e1c5 100644 --- a/pyrogram/methods/messages/send_cached_media.py +++ b/pyrogram/methods/messages/send_cached_media.py @@ -175,7 +175,8 @@ async def send_cached_media( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -191,5 +192,6 @@ async def send_cached_media( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_contact.py b/pyrogram/methods/messages/send_contact.py index 0842fd7abd..c7eeb5e9d9 100644 --- a/pyrogram/methods/messages/send_contact.py +++ b/pyrogram/methods/messages/send_contact.py @@ -164,7 +164,8 @@ async def send_contact( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -178,5 +179,6 @@ async def send_contact( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_dice.py b/pyrogram/methods/messages/send_dice.py index f350a0dea8..dc4f757c67 100644 --- a/pyrogram/methods/messages/send_dice.py +++ b/pyrogram/methods/messages/send_dice.py @@ -158,7 +158,8 @@ async def send_dice( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -172,5 +173,6 @@ async def send_dice( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py index cb65f6af34..fb35d1acf7 100644 --- a/pyrogram/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -274,7 +274,8 @@ async def progress(current, total): self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -288,7 +289,8 @@ async def progress(current, total): {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except StopTransmission: diff --git a/pyrogram/methods/messages/send_location.py b/pyrogram/methods/messages/send_location.py index ad7ac8ebc8..94331e73bf 100644 --- a/pyrogram/methods/messages/send_location.py +++ b/pyrogram/methods/messages/send_location.py @@ -157,7 +157,8 @@ async def send_location( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -171,5 +172,6 @@ async def send_location( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index c09bb81fec..a550078717 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -343,7 +343,7 @@ async def send_message( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), - replies=0 + replies=self.fetch_replies ) elif isinstance( i, @@ -357,5 +357,6 @@ async def send_message( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py index 7bc42668cc..0a02f114f1 100644 --- a/pyrogram/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -272,7 +272,8 @@ async def send_photo( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -286,7 +287,8 @@ async def send_photo( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except pyrogram.StopTransmission: return None diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index 07f7bde6b4..0ea8e2c10e 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -252,7 +252,8 @@ async def send_poll( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -266,5 +267,6 @@ async def send_poll( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_sticker.py b/pyrogram/methods/messages/send_sticker.py index c79a763887..890cb1a39b 100644 --- a/pyrogram/methods/messages/send_sticker.py +++ b/pyrogram/methods/messages/send_sticker.py @@ -254,7 +254,8 @@ async def send_sticker( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -268,7 +269,8 @@ async def send_sticker( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except StopTransmission: return None diff --git a/pyrogram/methods/messages/send_venue.py b/pyrogram/methods/messages/send_venue.py index a1d95c8aa0..730c06e2aa 100644 --- a/pyrogram/methods/messages/send_venue.py +++ b/pyrogram/methods/messages/send_venue.py @@ -181,7 +181,8 @@ async def send_venue( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -195,5 +196,6 @@ async def send_venue( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index 1ead3b898b..6dad5bb51c 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -331,7 +331,8 @@ async def progress(current, total): self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -345,7 +346,8 @@ async def progress(current, total): {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except StopTransmission: return None diff --git a/pyrogram/methods/messages/send_video_note.py b/pyrogram/methods/messages/send_video_note.py index 8ffde7a7a8..506752a761 100644 --- a/pyrogram/methods/messages/send_video_note.py +++ b/pyrogram/methods/messages/send_video_note.py @@ -291,7 +291,8 @@ async def send_video_note( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -305,7 +306,8 @@ async def send_video_note( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except StopTransmission: return None diff --git a/pyrogram/methods/messages/send_voice.py b/pyrogram/methods/messages/send_voice.py index 71e85e1ca1..6cc168fd40 100644 --- a/pyrogram/methods/messages/send_voice.py +++ b/pyrogram/methods/messages/send_voice.py @@ -286,7 +286,8 @@ async def send_voice( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies ) elif isinstance( i, @@ -300,7 +301,8 @@ async def send_voice( {i.id: i for i in r.users}, {i.id: i for i in r.chats}, business_connection_id=getattr(i, "connection_id", business_connection_id), - raw_reply_to_message=i.reply_to_message + raw_reply_to_message=i.reply_to_message, + replies=0 ) except StopTransmission: return None diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 7e01ea6ee2..bb65e289e9 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1283,7 +1283,8 @@ async def _parse( raw_reply_to_message, users, chats, - business_connection_id=business_connection_id + business_connection_id=business_connection_id, + replies=0 ) if not parsed_message.poll: # Do not cache poll messages diff --git a/pyrogram/types/user_and_chats/chat_event.py b/pyrogram/types/user_and_chats/chat_event.py index 22f1cdac48..cdffb562f9 100644 --- a/pyrogram/types/user_and_chats/chat_event.py +++ b/pyrogram/types/user_and_chats/chat_event.py @@ -354,12 +354,21 @@ async def _parse( action = enums.ChatEventAction.CHAT_PERMISSIONS_CHANGED elif isinstance(action, raw.types.ChannelAdminLogEventActionDeleteMessage): - deleted_message = await types.Message._parse(client, action.message, users, chats) + deleted_message = await types.Message._parse( + client, + action.message, + users, + chats + ) action = enums.ChatEventAction.MESSAGE_DELETED elif isinstance(action, raw.types.ChannelAdminLogEventActionEditMessage): - old_message = await types.Message._parse(client, action.prev_message, users, chats) - new_message = await types.Message._parse(client, action.new_message, users, chats) + old_message = await types.Message._parse( + client, action.prev_message, users, chats + ) + new_message = await types.Message._parse( + client, action.new_message, users, chats + ) action = enums.ChatEventAction.MESSAGE_EDITED elif isinstance(action, raw.types.ChannelAdminLogEventActionParticipantInvite): @@ -377,7 +386,9 @@ async def _parse( action = enums.ChatEventAction.MEMBER_PERMISSIONS_CHANGED elif isinstance(action, raw.types.ChannelAdminLogEventActionStopPoll): - stopped_poll = await types.Message._parse(client, action.message, users, chats) + stopped_poll = await types.Message._parse( + client, action.message, users, chats + ) action = enums.ChatEventAction.POLL_STOPPED elif isinstance(action, raw.types.ChannelAdminLogEventActionParticipantJoin): @@ -408,10 +419,14 @@ async def _parse( if isinstance(action.message, raw.types.Message): if message.pinned: - pinned_message = await types.Message._parse(client, message, users, chats) + pinned_message = await types.Message._parse( + client, message, users, chats + ) action = enums.ChatEventAction.MESSAGE_PINNED else: - unpinned_message = await types.Message._parse(client, message, users, chats) + unpinned_message = await types.Message._parse( + client, message, users, chats + ) action = enums.ChatEventAction.MESSAGE_UNPINNED elif isinstance(action, raw.types.ChannelAdminLogEventActionExportedInviteEdit): diff --git a/pyrogram/utils.py b/pyrogram/utils.py index 9d48a17225..18a45ce483 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -118,7 +118,7 @@ async def parse_messages( users, chats, is_scheduled=isinstance(u, raw.types.UpdateNewScheduledMessage), - replies=0 + replies=client.fetch_replies ) ) @@ -135,7 +135,8 @@ async def parse_messages( users, chats, business_connection_id=getattr(u, "connection_id", business_connection_id), - raw_reply_to_message=u.reply_to_message + raw_reply_to_message=u.reply_to_message, + replies=0 ) ) @@ -155,7 +156,7 @@ async def parse_messages( users, chats, is_scheduled=is_scheduled, - replies=replies + replies=client.fetch_replies ) ) From 1080d84328d47b4235f97ed23e46baa69dbe2350 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 1 Jun 2024 17:41:37 +0200 Subject: [PATCH 072/154] Update Pyrogram to v2.1.32.3 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 27d825a300..f6eefa6edb 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.2" +__version__ = "2.1.32.3" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From d0b4d373dbba9b74c5492210a1a8f7c4d2d1d4c8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 1 Jun 2024 19:30:47 +0200 Subject: [PATCH 073/154] Update Pyrogram to v2.1.32.5 --- docs/source/releases/changes-in-this-fork.rst | 19 ++----------- pyrogram/__init__.py | 2 +- pyrogram/methods/messages/__init__.py | 4 +-- pyrogram/methods/messages/send_document.py | 14 ++++++++++ pyrogram/methods/messages/set_reaction.py | 28 +++++++++++++++++++ .../types/bots_and_keyboards/force_reply.py | 19 ++++++++++++- .../reply_keyboard_markup.py | 21 ++++++++++++-- .../input_text_message_content.py | 5 ++-- pyrogram/types/messages_and_media/message.py | 2 ++ 9 files changed, 87 insertions(+), 27 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 5fae777572..3a882df953 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -146,17 +146,11 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ - Documentation Builder Fixes - `faster-pyrogram `_ is not polished or documented for anyone else's use. We don't have the capacity to support `faster-pyrogram `_ as an independent open-source project, nor any desire for it to become an alternative to Pyrogram. Our goal in making this code available is a unified faster Pyrogram. `... `_ - - Lock-free and asynchronous implementation of the sqlite session. - - The possibility of turning off journaling and vacuum when starting a session. - - Improved implementation of rle_encode. - - Implementation of _parse_channel_chat without getattr, in some scenarios. - - Cache of FileId and UniqueFileId instances and of their string-coded versions. - - Use of tcp abridged instead of tcp obfuscated as the default protocol. +-----------------------------+ | Leaked Scheme Layers (2) | @@ -176,7 +170,6 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ - `Add undocumented things `_ - `Add missing enums.SentCodeType `_ -- Renamed ``placeholder`` to ``input_field_placeholder`` in :obj:`~pyrogram.types.ReplyKeyboardMarkup` - `#693 `_ - Revert `e678c05 `_ and stole squashed unauthored changes from `bcd18d5 `_ @@ -222,7 +215,6 @@ If you found any issue or have any suggestions, feel free to make `an issue `_. - Renamed ``send_reaction`` to :meth:`~pyrogram.Client.set_reaction`. - Added support for :meth:`~pyrogram.Client.send_photo`, :meth:`~pyrogram.Client.send_video`, :meth:`~pyrogram.Client.send_animation`, :meth:`~pyrogram.Client.send_voice` messages that could be played once. -- Added ``_raw`` to the :obj:`~pyrogram.types.Chat` object. - Added the field ``via_chat_folder_invite_link`` to the class :obj:`~pyrogram.types.ChatMemberUpdated`. - **BOTS ONLY**: Added updates about a reaction change on a message with non-anonymous reactions, represented by the class :obj:`~pyrogram.handlers.MessageReactionUpdatedHandler` and the field ``message_reaction`` in the class Update. - **BOTS ONLY**: Added updates about reaction changes on a message with anonymous reactions, represented by the class :obj:`~pyrogram.handlers.MessageReactionCountUpdatedHandler` and the field ``message_reaction_count`` in the class Update. @@ -240,9 +232,8 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ -- Added ``_raw`` to the :obj:`~pyrogram.types.Chat`, :obj:`~pyrogram.types.Dialog`, and :obj:`~pyrogram.types.User` objects. +- Added ``_raw`` to the :obj:`~pyrogram.types.Chat`, :obj:`~pyrogram.types.Dialog`, :obj:`~pyrogram.types.Message` and :obj:`~pyrogram.types.User` objects. - Fix downloading media to ``WORKDIR`` when ``WORKDIR`` was not specified. - `Update multiple fragment chat usernames `_ - `Custom Storage Engines `_ @@ -254,12 +245,6 @@ If you found any issue or have any suggestions, feel free to make `an issue . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.3" +__version__ = "2.1.32.5" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index 2fe5aabbdc..90c5858c90 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -56,9 +56,7 @@ from .send_message import SendMessage from .send_photo import SendPhoto from .send_poll import SendPoll -from .set_reaction import ( - SetReaction -) +from .set_reaction import SetReaction from .send_sticker import SendSticker from .send_venue import SendVenue from .send_video import SendVideo diff --git a/pyrogram/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py index fb35d1acf7..928e8cb871 100644 --- a/pyrogram/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -56,6 +56,7 @@ async def send_document( "types.ForceReply" ] = None, reply_to_message_id: int = None, + force_document: bool = None, progress: Callable = None, progress_args: tuple = () ) -> Optional["types.Message"]: @@ -183,6 +184,19 @@ async def progress(current, total): ) reply_parameters = types.ReplyParameters(message_id=reply_to_message_id) + if force_document and disable_content_type_detection: + raise ValueError( + "Parameters `force_document` and `disable_content_type_detection` " + "are mutually exclusive." + ) + + if force_document is not None: + log.warning( + "This property is deprecated. " + "Please use disable_content_type_detection instead" + ) + disable_content_type_detection = force_document + file = None try: diff --git a/pyrogram/methods/messages/set_reaction.py b/pyrogram/methods/messages/set_reaction.py index 113062e3cd..c6cd91e3e3 100644 --- a/pyrogram/methods/messages/set_reaction.py +++ b/pyrogram/methods/messages/set_reaction.py @@ -16,12 +16,15 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import logging from typing import Union from typing import List import pyrogram from pyrogram import raw, types +log = logging.getLogger(__name__) + class SetReaction: async def set_reaction( @@ -123,3 +126,28 @@ async def set_reaction( return r else: raise ValueError("You need to pass one of message_id OR story_id!") + + + async def send_reaction( + self: "pyrogram.Client", + chat_id: Union[int, str], + message_id: int, + emoji: str = "", + big: bool = False, + add_to_recent: bool = True + ) -> bool: + log.warning( + "This property is deprecated. " + "Please use set_reaction instead" + ) + return bool( + await self.invoke( + raw.functions.messages.SendReaction( + reaction=[raw.types.ReactionEmoji(emoticon=emoji)] if emoji else None, + big=big, + peer=await self.resolve_peer(chat_id), + msg_id=message_id, + add_to_recent=add_to_recent + ) + ) + ) diff --git a/pyrogram/types/bots_and_keyboards/force_reply.py b/pyrogram/types/bots_and_keyboards/force_reply.py index 8dd77f0c1a..b07c01e506 100644 --- a/pyrogram/types/bots_and_keyboards/force_reply.py +++ b/pyrogram/types/bots_and_keyboards/force_reply.py @@ -16,11 +16,15 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import logging + import pyrogram from pyrogram import raw from ..object import Object +log = logging.getLogger(__name__) + class ForceReply(Object): """Object used to force clients to show a reply interface. @@ -44,8 +48,21 @@ class ForceReply(Object): def __init__( self, selective: bool = None, - input_field_placeholder: str = None + input_field_placeholder: str = None, + placeholder: str = None ): + if placeholder and input_field_placeholder: + raise ValueError( + "Parameters `placeholder` and `input_field_placeholder` are mutually exclusive." + ) + + if placeholder is not None: + log.warning( + "This property is deprecated. " + "Please use input_field_placeholder instead" + ) + input_field_placeholder = placeholder + super().__init__() self.selective = selective diff --git a/pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py b/pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py index 47cf085497..9aa2c4a82e 100644 --- a/pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py +++ b/pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py @@ -16,13 +16,15 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import logging from typing import List, Union import pyrogram -from pyrogram import raw -from pyrogram import types +from pyrogram import raw, types from ..object import Object +log = logging.getLogger(__name__) + class ReplyKeyboardMarkup(Object): """A custom keyboard with reply options. @@ -63,8 +65,21 @@ def __init__( resize_keyboard: bool = None, one_time_keyboard: bool = None, input_field_placeholder: str = None, - selective: bool = None + selective: bool = None, + placeholder: str = None, ): + if placeholder and input_field_placeholder: + raise ValueError( + "Parameters `placeholder` and `input_field_placeholder` are mutually exclusive." + ) + + if placeholder is not None: + log.warning( + "This property is deprecated. " + "Please use input_field_placeholder instead" + ) + input_field_placeholder = placeholder + super().__init__() self.keyboard = keyboard diff --git a/pyrogram/types/input_message_content/input_text_message_content.py b/pyrogram/types/input_message_content/input_text_message_content.py index fa70df41cd..8de943f429 100644 --- a/pyrogram/types/input_message_content/input_text_message_content.py +++ b/pyrogram/types/input_message_content/input_text_message_content.py @@ -65,8 +65,6 @@ def __init__( ) link_preview_options = types.LinkPreviewOptions(is_disabled=disable_web_page_preview) - link_preview_options = link_preview_options or self.link_preview_options - super().__init__() self.message_text = message_text @@ -83,6 +81,9 @@ async def write(self, client: "pyrogram.Client", reply_markup): self.entities )).values() + if self.link_preview_options is None: + self.link_preview_options = client.link_preview_options + return raw.types.InputBotInlineMessageText( no_webpage=self.link_preview_options.is_disabled if self.link_preview_options else None, invert_media=self.link_preview_options.show_above_text if self.link_preview_options else None, diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index bb65e289e9..f10c2e9443 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -2103,6 +2103,7 @@ async def reply_document( "types.ForceReply" ] = None, reply_to_message_id: int = None, + force_document: bool = None, progress: Callable = None, progress_args: tuple = () ) -> "Message": @@ -2236,6 +2237,7 @@ async def reply_document( protect_content=protect_content, reply_markup=reply_markup, reply_to_message_id=reply_to_message_id, + force_document=force_document, progress=progress, progress_args=progress_args ) From d465190b4002f45d270312d307e2119209b4ba7b Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 2 Jun 2024 12:31:43 +0200 Subject: [PATCH 074/154] Add Hashtag Search methods search_public_hashtag_messages search_public_hashtag_messages_count --- compiler/docs/compiler.py | 2 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/__init__.py | 4 + .../search_public_hashtag_messages.py | 102 ++++++++++++++++++ .../search_public_hashtag_messages_count.py | 55 ++++++++++ 5 files changed, 164 insertions(+) create mode 100644 pyrogram/methods/messages/search_public_hashtag_messages.py create mode 100644 pyrogram/methods/messages/search_public_hashtag_messages_count.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 2ea6801ec2..b808f7c934 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -310,6 +310,8 @@ def get_title_list(s: str) -> list: search_global_count search_messages search_messages_count + search_public_hashtag_messages + search_public_hashtag_messages_count send_animation send_audio send_cached_media diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 3a882df953..319f0f3769 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue +# +# 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 datetime import datetime +from typing import AsyncGenerator + +import pyrogram +from pyrogram import raw, types, utils + + +class SearchPublicHashtagMessages: + async def search_public_hashtag_messages( + self: "pyrogram.Client", + hashtag: str = "", + offset_id: int = 0, + offset_date: datetime = utils.zero_datetime(), + limit: int = 0, + ) -> AsyncGenerator["types.Message", None]: + """Searches for public channel posts with the given hashtag. For optimal performance, the number of returned messages is chosen by Telegram Server and can be smaller than the specified limit. + + If you want to get the posts count only, see :meth:`~pyrogram.Client.search_public_hashtag_messages_count`. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + hashtag (``str``, *optional*): + Hashtag to search for. + + offset_id (``int``, *optional*): + Offset of the first entry to return as received from the previous request; use empty string to get the first chunk of results. + + offset_date (:py:obj:`~datetime.datetime`, *optional*): + Pass a date as offset to retrieve only older messages starting from that date. + + limit (``int``, *optional*): + The maximum number of messages to be returned. + By default, no limit is applied and all posts are returned. + + Returns: + ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. + + Example: + .. code-block:: python + + # Search for "#pyrogram". Get the first 50 results + async for message in app.search_public_hashtag_messages("#pyrogram"): + print(message.text) + + """ + current = 0 + total = abs(limit) or (1 << 31) + limit = min(100, total) + + offset_peer = raw.types.InputPeerEmpty() + + while True: + messages = await utils.parse_messages( + self, + await self.invoke( + raw.functions.channels.SearchPosts( + hashtag=hashtag, + offset_rate=utils.datetime_to_timestamp(offset_date), + offset_peer=offset_peer, + offset_id=offset_id, + limit=limit + ), + sleep_threshold=60 + ), + replies=0 + ) + + if not messages: + return + + last = messages[-1] + + offset_date = utils.datetime_to_timestamp(last.date) + offset_peer = await self.resolve_peer(last.chat.id) + offset_id = last.id + + for message in messages: + yield message + + current += 1 + + if current >= total: + return diff --git a/pyrogram/methods/messages/search_public_hashtag_messages_count.py b/pyrogram/methods/messages/search_public_hashtag_messages_count.py new file mode 100644 index 0000000000..b8cfc08970 --- /dev/null +++ b/pyrogram/methods/messages/search_public_hashtag_messages_count.py @@ -0,0 +1,55 @@ +# 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 . + +import pyrogram +from pyrogram import raw + + +class SearchPublicHashtagMessagesCount: + async def search_public_hashtag_messages_count( + self: "pyrogram.Client", + hashtag: str = "", + ) -> int: + """Get the count of messages with the provided hashtag. + + If you want to get the actual messages, see :meth:`~pyrogram.Client.search_public_hashtag_messages`. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + hashtag (``str``, *optional*): + Hashtag to search for. + + Returns: + ``int``: On success, the messages count is returned. + + """ + r = await self.invoke( + raw.functions.channels.SearchPosts( + hashtag=hashtag, + offset_rate=0, + offset_peer=raw.types.InputPeerEmpty(), + offset_id=0, + limit=1 + ) + ) + + if hasattr(r, "count"): + return r.count + else: + return len(r.messages) From bbd208cb4625010f547c312e889f071090c63b91 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 2 Jun 2024 17:03:18 +0200 Subject: [PATCH 075/154] Add send_web_app_custom_request --- compiler/docs/compiler.py | 1 + compiler/errors/source/400_BAD_REQUEST.tsv | 1 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/bots/__init__.py | 2 + .../bots/send_web_app_custom_request.py | 61 +++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 pyrogram/methods/bots/send_web_app_custom_request.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index b808f7c934..2b4ca9937d 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -187,6 +187,7 @@ def get_title_list(s: str) -> list: set_chat_menu_button get_chat_menu_button answer_web_app_query + send_web_app_custom_request set_bot_name get_bot_name set_bot_info_description diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index d10b36126d..01d0d9acfb 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -417,6 +417,7 @@ STICKER_THUMB_TGS_NOTGS Incorrect stickerset TGS thumb file provided. STICKER_VIDEO_BIG The specified video sticker is too big. STICKER_VIDEO_NODOC You must send the video sticker as a document. STICKER_VIDEO_NOWEBM The specified video sticker is not in webm format. +STORAGE_KEY_REQUIRED A cloud storage key is required. STORIES_NEVER_CREATED This peer hasn't ever posted any stories. STORIES_TOO_MUCH You have hit the maximum active stories limit as specified by the [`story_expiring_limit_*` client configuration parameters](https://core.telegram.org/api/config#story-expiring-limit-default): you should buy a [Premium](/api/premium) subscription, delete an active story, or wait for the oldest story to expire. STORY_ID_EMPTY You specified no story IDs. diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 319f0f3769..c983e4d512 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue +# +# 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 Union + +import pyrogram +from pyrogram import raw, types + + +class SendWebAppCustomRequest: + async def send_web_app_custom_request( + self: "pyrogram.Client", + bot_user_id: Union[int, str], + method: str, + parameters: str + ) -> str: + """Sends a custom request from a Web App. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + bot_user_id (``int`` | ``str``): + Unique identifier of the inline bot you want to get results from. You can specify + a @username (str) or a bot ID (int). + + method (``str``): + The method name. + + parameters (``str``): + JSON-serialized method parameters. + + Returns: + ``str``: On success, a JSON-serialized result is returned. + """ + + r = await self.invoke( + raw.functions.bots.InvokeWebViewCustomMethod( + bot=await self.resolve_peer(bot_user_id), + custom_method=method, + params=raw.types.DataJSON( + data=parameters + ) + ) + ) + + return r.data From 19ac66f49438e28f4767425b4e1ccd335d31f52b Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 3 Jun 2024 18:08:20 +0200 Subject: [PATCH 076/154] Improve documentation of methods. Add cashtag support in searchPublicHashtagMessages. Git-Origin-Commit-Id: 02ad126 --- pyrogram/methods/messages/search_public_hashtag_messages.py | 6 +++--- .../messages/search_public_hashtag_messages_count.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyrogram/methods/messages/search_public_hashtag_messages.py b/pyrogram/methods/messages/search_public_hashtag_messages.py index 7e0fa33de7..fc512d4fc4 100644 --- a/pyrogram/methods/messages/search_public_hashtag_messages.py +++ b/pyrogram/methods/messages/search_public_hashtag_messages.py @@ -31,7 +31,7 @@ async def search_public_hashtag_messages( offset_date: datetime = utils.zero_datetime(), limit: int = 0, ) -> AsyncGenerator["types.Message", None]: - """Searches for public channel posts with the given hashtag. For optimal performance, the number of returned messages is chosen by Telegram Server and can be smaller than the specified limit. + """Searches for public channel posts with the given hashtag or cashtag. For optimal performance, the number of returned messages is chosen by Telegram Server and can be smaller than the specified limit. If you want to get the posts count only, see :meth:`~pyrogram.Client.search_public_hashtag_messages_count`. @@ -39,7 +39,7 @@ async def search_public_hashtag_messages( Parameters: hashtag (``str``, *optional*): - Hashtag to search for. + Hashtag or cashtag to search for. offset_id (``int``, *optional*): Offset of the first entry to return as received from the previous request; use empty string to get the first chunk of results. @@ -58,7 +58,7 @@ async def search_public_hashtag_messages( .. code-block:: python # Search for "#pyrogram". Get the first 50 results - async for message in app.search_public_hashtag_messages("#pyrogram"): + async for message in app.search_public_hashtag_messages("pyrogram", limit=50): print(message.text) """ diff --git a/pyrogram/methods/messages/search_public_hashtag_messages_count.py b/pyrogram/methods/messages/search_public_hashtag_messages_count.py index b8cfc08970..88840fb426 100644 --- a/pyrogram/methods/messages/search_public_hashtag_messages_count.py +++ b/pyrogram/methods/messages/search_public_hashtag_messages_count.py @@ -25,7 +25,7 @@ async def search_public_hashtag_messages_count( self: "pyrogram.Client", hashtag: str = "", ) -> int: - """Get the count of messages with the provided hashtag. + """Get the count of messages with the provided hashtag or cashtag. If you want to get the actual messages, see :meth:`~pyrogram.Client.search_public_hashtag_messages`. @@ -33,7 +33,7 @@ async def search_public_hashtag_messages_count( Parameters: hashtag (``str``, *optional*): - Hashtag to search for. + Hashtag or cashtag to search for. Returns: ``int``: On success, the messages count is returned. From faea7557b814801de86f07dbb9e39b5ab5e5fbf0 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 5 Jun 2024 04:51:50 +0200 Subject: [PATCH 077/154] Fixing bug with BlockQuote entity parser (#31) --- pyrogram/types/messages_and_media/message_entity.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyrogram/types/messages_and_media/message_entity.py b/pyrogram/types/messages_and_media/message_entity.py index a051fcbfbc..33e295e41a 100644 --- a/pyrogram/types/messages_and_media/message_entity.py +++ b/pyrogram/types/messages_and_media/message_entity.py @@ -128,5 +128,10 @@ async def write(self): if entity is raw.types.MessageEntityMentionName: entity = raw.types.InputMessageEntityMentionName + elif self.type in ( + enums.MessageEntityType.BLOCKQUOTE, + enums.MessageEntityType.EXPANDABLE_BLOCKQUOTE, + ): + entity = raw.types.MessageEntityBlockquote return entity(**args) From b11fcfe3cc17d21a85835b09c1404e88b6bd460f Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Thu, 6 Jun 2024 20:18:36 +0530 Subject: [PATCH 078/154] Invoice high-level support (#33) * by stealing without authorship some of the commits from KurimuzonAkuma/pyrogram#67 and pyrogram/pyrogram#535. --- compiler/docs/compiler.py | 12 + compiler/docs/template/bound-methods.rst | 13 + docs/source/releases/changes-in-this-fork.rst | 3 + pyrogram/dispatcher.py | 15 +- pyrogram/enums/message_service_type.py | 3 + pyrogram/filters.py | 16 +- pyrogram/handlers/__init__.py | 1 + .../handlers/pre_checkout_query_handler.py | 51 ++++ pyrogram/methods/business/__init__.py | 6 + .../business/answer_pre_checkout_query.py | 67 +++++ .../methods/business/refund_star_payment.py | 53 ++++ pyrogram/methods/business/send_invoice.py | 239 ++++++++++++++++++ pyrogram/methods/decorators/__init__.py | 3 +- .../decorators/on_pre_checkout_query.py | 62 +++++ pyrogram/types/business/__init__.py | 10 + pyrogram/types/business/labeled_price.py | 59 +++++ pyrogram/types/business/order_info.py | 53 ++++ pyrogram/types/business/pre_checkout_query.py | 149 +++++++++++ pyrogram/types/business/shipping_address.py | 63 +++++ pyrogram/types/business/successful_payment.py | 143 +++++++++++ pyrogram/types/messages_and_media/message.py | 202 ++++++++++++++- 21 files changed, 1216 insertions(+), 7 deletions(-) create mode 100644 pyrogram/handlers/pre_checkout_query_handler.py create mode 100644 pyrogram/methods/business/answer_pre_checkout_query.py create mode 100644 pyrogram/methods/business/refund_star_payment.py create mode 100644 pyrogram/methods/business/send_invoice.py create mode 100644 pyrogram/methods/decorators/on_pre_checkout_query.py create mode 100644 pyrogram/types/business/labeled_price.py create mode 100644 pyrogram/types/business/order_info.py create mode 100644 pyrogram/types/business/pre_checkout_query.py create mode 100644 pyrogram/types/business/shipping_address.py create mode 100644 pyrogram/types/business/successful_payment.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 2b4ca9937d..d0588b5373 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -372,8 +372,11 @@ def get_title_list(s: str) -> list: """, business=""" Telegram Business & Fragment + answer_pre_checkout_query get_business_connection get_collectible_item_info + refund_star_payment + send_invoice """, ) @@ -564,6 +567,11 @@ def get_title_list(s: str) -> list: BusinessOpeningHoursInterval CollectibleItemInfo Invoice + LabeledPrice + OrderInfo + PreCheckoutQuery + ShippingAddress + SuccessfulPayment """, users_chats=""" Users & Chats @@ -705,6 +713,10 @@ def get_title_list(s: str) -> list: InlineQuery InlineQuery.answer """, + pre_checkout_query=""" + PreCheckoutQuery + PreCheckoutQuery.answer + """, chat_join_request=""" ChatJoinRequest ChatJoinRequest.approve diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index 82cdc158e7..bcc02612cb 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -88,6 +88,19 @@ InlineQuery {inline_query_toctree} +PreCheckoutQuery +----------- + +.. hlist:: + :columns: 2 + + {pre_checkout_query_hlist} + +.. toctree:: + :hidden: + + {pre_checkout_query_toctree} + ChatJoinRequest --------------- diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index c983e4d512..4774d6ea8e 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,9 @@ If you found any issue or have any suggestions, feel free to make `an issue bool: # endregion +# region successful_payment_filter +async def successful_payment_filter(_, __, m: Message): + return bool(m.successful_payment) + + +successful_payment = create(successful_payment_filter) +"""Filter messages for successful payments""" + + +# endregion # region service_filter async def service_filter(_, __, m: Message) -> bool: @@ -769,7 +780,7 @@ async def service_filter(_, __, m: Message) -> bool: A service message contains any of the following fields set: *left_chat_member*, *new_chat_title*, *new_chat_photo*, *delete_chat_photo*, *group_chat_created*, *supergroup_chat_created*, *channel_chat_created*, *migrate_to_chat_id*, *migrate_from_chat_id*, *pinned_message*, *game_score*, -*video_chat_started*, *video_chat_ended*, *video_chat_participants_invited*. +*video_chat_started*, *video_chat_ended*, *video_chat_participants_invited*, *successful_payment*. """ @@ -958,6 +969,7 @@ def regex(pattern: Union[str, Pattern], flags: int = 0) -> Filter: - :obj:`~pyrogram.types.Message`: The filter will match ``text`` or ``caption``. - :obj:`~pyrogram.types.CallbackQuery`: The filter will match ``data``. - :obj:`~pyrogram.types.InlineQuery`: The filter will match ``query``. + - :obj:`~pyrogram.types.PreCheckoutQuery`: The filter will match ``payload``. When a pattern matches, all the `Match Objects `_ are stored in the ``matches`` field of the update object itself. @@ -977,6 +989,8 @@ async def func(flt, _, update: Update) -> bool: value: str | bytes = update.data elif isinstance(update, InlineQuery): value: str = update.query + elif isinstance(update, PreCheckoutQuery): + value: str = update.payload else: raise ValueError(f"Regex filter doesn't work with {type(update)}") diff --git a/pyrogram/handlers/__init__.py b/pyrogram/handlers/__init__.py index 0ce9deaa21..1460432499 100644 --- a/pyrogram/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -30,3 +30,4 @@ from .user_status_handler import UserStatusHandler from .message_reaction_updated_handler import MessageReactionUpdatedHandler from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler +from .pre_checkout_query_handler import PreCheckoutQueryHandler diff --git a/pyrogram/handlers/pre_checkout_query_handler.py b/pyrogram/handlers/pre_checkout_query_handler.py new file mode 100644 index 0000000000..1eccff1bc7 --- /dev/null +++ b/pyrogram/handlers/pre_checkout_query_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 PreCheckoutQueryHandler(Handler): + """The PreCheckoutQueryHandler handler class. Used to handle pre-checkout queries coming from invoice buttons. + + 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_pre_checkout_query` decorator. + + Parameters: + callback (``Callable``): + Pass a function that will be called when a new PreCheckoutQuery arrives. It takes *(client, pre_checkout_query)* + 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 callback queries to be passed + in your callback function. + + Other parameters: + client (:obj:`~pyrogram.Client`): + The Client itself, useful when you want to call other API methods inside the message handler. + + pre_checkout_query (:obj:`~pyrogram.types.PreCheckoutQuery`): + The received callback query. + + """ + + def __init__(self, callback: Callable, filters=None): + super().__init__(callback, filters) diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index 3825b2dfa0..a9d833e5ff 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -16,12 +16,18 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from .answer_pre_checkout_query import AnswerPreCheckoutQuery from .get_business_connection import GetBusinessConnection from .get_collectible_item_info import GetCollectibleItemInfo +from .refund_star_payment import RefundStarPayment +from .send_invoice import SendInvoice class TelegramBusiness( + AnswerPreCheckoutQuery, GetBusinessConnection, GetCollectibleItemInfo, + RefundStarPayment, + SendInvoice, ): pass diff --git a/pyrogram/methods/business/answer_pre_checkout_query.py b/pyrogram/methods/business/answer_pre_checkout_query.py new file mode 100644 index 0000000000..88a524895e --- /dev/null +++ b/pyrogram/methods/business/answer_pre_checkout_query.py @@ -0,0 +1,67 @@ +# 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 . + +import pyrogram +from pyrogram import raw + + +class AnswerPreCheckoutQuery: + async def answer_pre_checkout_query( + self: "pyrogram.Client", + pre_checkout_query_id: str, + ok: bool, + error_message: str = None + ): + """Once the user has confirmed their payment and shipping details, the API sends the final confirmation in the form of an :obj:`~pyrogram.handlers.PreCheckoutQueryHandler`. + + Use this method to respond to such pre-checkout queries. + + **Note**: The API must receive an answer within 10 seconds after the pre-checkout query was sent. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + pre_checkout_query_id (``str``): + Unique identifier for the query to be answered. + + ok (``bool``): + Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems. + + error_message (``str``, *optional*): + Required if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user. + + Returns: + ``bool``: True, on success. + + Example: + .. code-block:: python + + # Proceed with the order + await app.answer_pre_checkout_query(query_id, ok=True) + + # Answer with error message + await app.answer_pre_checkout_query(query_id, ok=False, error_message="Error Message displayed to the user") + + """ + return await self.invoke( + raw.functions.messages.SetBotPrecheckoutResults( + query_id=int(pre_checkout_query_id), + success=ok or None, + error=error_message or None + ) + ) diff --git a/pyrogram/methods/business/refund_star_payment.py b/pyrogram/methods/business/refund_star_payment.py new file mode 100644 index 0000000000..12c4967731 --- /dev/null +++ b/pyrogram/methods/business/refund_star_payment.py @@ -0,0 +1,53 @@ +# 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 Union + +import pyrogram +from pyrogram import raw + + +class RefundStarPayment: + async def refund_star_payment( + self: "pyrogram.Client", + user_id: Union[int, str], + telegram_payment_charge_id: str + ) -> bool: + """Refunds a successful payment in `Telegram Stars `_. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target user, whose payment will be refunded. + + telegram_payment_charge_id (``str``): + Telegram payment identifier. + + Returns: + ``bool``: True on success + + """ + + r = await self.invoke( + raw.functions.payments.RefundStarsCharge( + user_id=await self.resolve_peer(user_id), + charge_id=telegram_payment_charge_id + ) + ) + return bool(r) diff --git a/pyrogram/methods/business/send_invoice.py b/pyrogram/methods/business/send_invoice.py new file mode 100644 index 0000000000..dc3a048ee6 --- /dev/null +++ b/pyrogram/methods/business/send_invoice.py @@ -0,0 +1,239 @@ +# 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 . + +import logging +from typing import List, Optional, Union + +import pyrogram +from pyrogram import enums, raw, utils, types + +log = logging.getLogger(__name__) + + +class SendInvoice: + async def send_invoice( + self: "pyrogram.Client", + chat_id: Union[int, str], + title: str, + description: str, + payload: Union[str, bytes], + currency: str, + prices: List["types.LabeledPrice"], + message_thread_id: int = None, + provider_token: str = None, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + start_parameter: str = None, + provider_data: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + is_flexible: bool = None, + disable_notification: bool = None, + protect_content: bool = None, + message_effect_id: int = None, + reply_parameters: "types.ReplyParameters" = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None + ) -> "types.Message": + """Use this method to send invoices. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + title (``str``): + Product name, 1-32 characters. + + description (``str``): + Product description, 1-255 characters + + payload (``str`` | ``bytes``): + Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. + + currency (``str``): + Three-letter ISO 4217 currency code, see `more on currencies `_. Pass ``XTR`` for payments in `Telegram Stars `_. + + prices (List of :obj:`~pyrogram.types.LabeledPrice`): + Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_. + + message_thread_id (``int``, *optional*): + If the message is in a thread, ID of the original message. + + provider_token (``str``, *optional*): + Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_. + + max_tip_amount (``int``, *optional*): + The maximum accepted amount for tips in the smallest units of the currency (integer, **not** float/double). For example, for a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_. + + suggested_tip_amounts (List of ``int``, *optional*): + An array of suggested amounts of tips in the smallest units of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed ``max_tip_amount``. + + start_parameter (``str``, *optional*): + Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a Pay button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a URL button with a deep link to the bot (instead of a Pay button), with the value used as the start parameter. + + provider_data (``str``, *optional*): + JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. + + photo_url (``str``, *optional*): + URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. + + photo_size (``int``, *optional*): + Photo size in bytes + + photo_width (``int``, *optional*): + Photo width + + photo_height (``int``, *optional*): + Photo height + + need_name (``bool``, *optional*): + Pass True if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_. + + need_phone_number (``bool``, *optional*): + Pass True if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_. + + need_email (``bool``, *optional*): + Pass True if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_. + + need_shipping_address (``bool``, *optional*): + Pass True if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_. + + send_phone_number_to_provider (``bool``, *optional*): + Pass True if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + send_email_to_provider (``bool``, *optional*): + Pass True if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + is_flexible (``bool``, *optional*): + Pass True if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): + Description of the message to reply to + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): + Additional interface options. An object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + + caption (``str``, *optional*): + Document caption, 0-1024 characters. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent invoice message is returned. + + """ + reply_to = await utils._get_reply_message_parameters( + self, + message_thread_id, + reply_parameters + ) + + rpc = raw.functions.messages.SendMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaInvoice( + title=title, + description=description, + photo=raw.types.InputWebDocument( + url=photo_url, + mime_type="image/jpg", + size=photo_size, + attributes=[ + raw.types.DocumentAttributeImageSize( + w=photo_width, + h=photo_height + ) + ] + ) if photo_url else None, + invoice=raw.types.Invoice( + currency=currency, + prices=[i.write() for i in prices], + test=self.test_mode, + name_requested=need_name, + phone_requested=need_phone_number, + email_requested=need_email, + shipping_address_requested=need_shipping_address, + flexible=is_flexible, + phone_to_provider=send_phone_number_to_provider, + email_to_provider=send_email_to_provider + ), + payload=payload.encode() if isinstance(payload, str) else payload, + provider=provider_token, + provider_data=raw.types.DataJSON( + data=provider_data if provider_data else "{}" + ), + start_param=start_parameter + ), + silent=disable_notification or None, + reply_to=reply_to, + random_id=self.rnd_id(), + noforwards=protect_content, + reply_markup=await reply_markup.write(self) if reply_markup else None, + effect=message_effect_id, + **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) + ) + r = await self.invoke(rpc) + + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage + ) + ): + return await types.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies + ) diff --git a/pyrogram/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py index d7ab7bcb41..2bda666c29 100644 --- a/pyrogram/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -30,6 +30,7 @@ from .on_user_status import OnUserStatus from .on_message_reaction_updated import OnMessageReactionUpdated from .on_message_reaction_count_updated import OnMessageReactionCountUpdated +from .on_pre_checkout_query import OnPreCheckoutQuery class Decorators( @@ -42,7 +43,7 @@ class Decorators( OnChosenInlineResult, OnCallbackQuery, - + OnPreCheckoutQuery, OnPoll, OnChatMemberUpdated, diff --git a/pyrogram/methods/decorators/on_pre_checkout_query.py b/pyrogram/methods/decorators/on_pre_checkout_query.py new file mode 100644 index 0000000000..7d33abe502 --- /dev/null +++ b/pyrogram/methods/decorators/on_pre_checkout_query.py @@ -0,0 +1,62 @@ +# 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, Optional, Union + +import pyrogram +from pyrogram.filters import Filter + + +class OnPreCheckoutQuery: + def on_pre_checkout_query( + self=None, + filters=None, + group: int = 0, + ) -> Callable: + """Decorator for handling pre-checkout queries. + + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.PreCheckoutQueryHandler`. + + Parameters: + filters (:obj:`~pyrogram.filters`, *optional*): + Pass one or more filters to allow only a subset of callback queries 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.PreCheckoutQueryHandler(func, filters), group) + elif isinstance(self, Filter) or self is None: + if not hasattr(func, "handlers"): + func.handlers = [] + + func.handlers.append( + ( + pyrogram.handlers.PreCheckoutQueryHandler(func, self), + group if filters is None else filters + ) + ) + + return func + + return decorator diff --git a/pyrogram/types/business/__init__.py b/pyrogram/types/business/__init__.py index 8e4dd1eb0c..fb2d9ddc90 100644 --- a/pyrogram/types/business/__init__.py +++ b/pyrogram/types/business/__init__.py @@ -23,6 +23,11 @@ from .business_opening_hours_interval import BusinessOpeningHoursInterval from .collectible_item_info import CollectibleItemInfo from .invoice import Invoice +from .labeled_price import LabeledPrice +from .order_info import OrderInfo +from .pre_checkout_query import PreCheckoutQuery +from .shipping_address import ShippingAddress +from .successful_payment import SuccessfulPayment __all__ = [ "BusinessConnection", @@ -32,4 +37,9 @@ "BusinessOpeningHoursInterval", "CollectibleItemInfo", "Invoice", + "LabeledPrice", + "OrderInfo", + "PreCheckoutQuery", + "ShippingAddress", + "SuccessfulPayment", ] diff --git a/pyrogram/types/business/labeled_price.py b/pyrogram/types/business/labeled_price.py new file mode 100644 index 0000000000..ccd2a42fca --- /dev/null +++ b/pyrogram/types/business/labeled_price.py @@ -0,0 +1,59 @@ +# 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 . + +import pyrogram +from pyrogram import raw + +from ..object import Object + + +class LabeledPrice(Object): + """This object represents a portion of the price for goods or services. + + Parameters: + label (``str``): + Portion label. + + amount (``int``): + Price of the product in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + """ + + def __init__( + self, + label: str, + amount: str + ): + super().__init__() + + self.label = label + self.amount = amount + + @staticmethod + def _parse(labeled_price: "raw.types.LabeledPrice") -> "LabeledPrice": + if isinstance(labeled_price, raw.types.LabeledPrice): + return LabeledPrice( + label=labeled_price.label, + amount=labeled_price.amount + ) + + def write(self): + return raw.types.LabeledPrice( + label=self.label, + amount=self.amount + ) diff --git a/pyrogram/types/business/order_info.py b/pyrogram/types/business/order_info.py new file mode 100644 index 0000000000..448ee1e313 --- /dev/null +++ b/pyrogram/types/business/order_info.py @@ -0,0 +1,53 @@ +# 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 ..object import Object + + +class OrderInfo(Object): + """This object represents information about an order. + + Parameters: + name (``str``, *optional*): + User name. + + phone_number (``str``, *optional*): + User's phone number. + + email (``str``, *optional*): + User email. + + shipping_address (:obj:`~pyrogram.types.ShippingAddress`, *optional*): + User shipping address. + + """ + + def __init__( + self, + *, + name: str = None, + phone_number: str = None, + email: str = None, + shipping_address: "types.ShippingAddress" = None + ): + super().__init__() + + self.name = name + self.phone_number = phone_number + self.email = email + self.shipping_address = shipping_address diff --git a/pyrogram/types/business/pre_checkout_query.py b/pyrogram/types/business/pre_checkout_query.py new file mode 100644 index 0000000000..c1c765d3b7 --- /dev/null +++ b/pyrogram/types/business/pre_checkout_query.py @@ -0,0 +1,149 @@ +# 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 Union, Optional + +import pyrogram +from pyrogram import raw, types + +from ..object import Object +from ..update import Update + + +class PreCheckoutQuery(Object, Update): + """This object contains information about an incoming pre-checkout query. + + Parameters: + id (``str``): + Unique query identifier. + + from_user (:obj:`~pyrogram.types.User`): + User who sent the query. + + currency (``str``): + Three-letter ISO 4217 `currency `_ code, or ``XTR`` for payments in `Telegram Stars `_. + + total_amount (``int``): + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + invoice_payload (``str``): + Bot specified invoice payload. Only available to the bot that received the payment. + + shipping_option_id (``str``, *optional*): + Identifier of the shipping option chosen by the user. Only available to the bot that received the payment. + + order_info (:obj:`~pyrogram.types.OrderInfo`, *optional*): + Order information provided by the user. Only available to the bot that received the payment. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + id: str, + from_user: "types.User", + currency: str, + total_amount: int, + invoice_payload: str, + shipping_option_id: str = None, + order_info: "types.OrderInfo" = None + ): + super().__init__(client) + + self.id = id + self.from_user = from_user + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.shipping_option_id = shipping_option_id + self.order_info = order_info + + @staticmethod + async def _parse( + client: "pyrogram.Client", + pre_checkout_query: "raw.types.UpdateBotPrecheckoutQuery", + users: dict + ) -> "PreCheckoutQuery": + # Try to decode pre-checkout query payload into string. If that fails, fallback to bytes instead of decoding by + # ignoring/replacing errors, this way, button clicks will still work. + try: + payload = pre_checkout_query.payload.decode() + except (UnicodeDecodeError, AttributeError): + payload = pre_checkout_query.payload + + return PreCheckoutQuery( + id=str(pre_checkout_query.query_id), + from_user=types.User._parse(client, users[pre_checkout_query.user_id]), + currency=pre_checkout_query.currency, + total_amount=pre_checkout_query.total_amount, + invoice_payload=payload, + shipping_option_id=pre_checkout_query.shipping_option_id, + order_info=types.OrderInfo( + name=pre_checkout_query.info.name, + phone_number=pre_checkout_query.info.phone, + email=pre_checkout_query.info.email, + shipping_address=types.ShippingAddress( + country_code=pre_checkout_query.info.shipping_address.country_iso2, + state=pre_checkout_query.info.shipping_address.state, + city=pre_checkout_query.info.shipping_address.city, + street_line1=pre_checkout_query.info.shipping_address.street_line1, + street_line2=pre_checkout_query.info.shipping_address.street_line2, + post_code=pre_checkout_query.info.shipping_address.post_code + ) + ) if pre_checkout_query.info else None, + client=client + ) + + async def answer( + self, + ok: bool, + error_message: str = None + ): + """Bound method *answer* of :obj:`~pyrogram.types.PreCheckoutQuery`. + + Use this method as a shortcut for: + + .. code-block:: python + + await client.answer_pre_checkout_query( + pre_checkout_query.id, + success=True + ) + + Example: + .. code-block:: python + + await pre_checkout_query.answer(ok=True) + + Parameters: + ok (``bool``): + Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems. + + error_message (``str``, *optional*): + Required if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user. + + Returns: + ``bool``: True, on success. + + """ + return await self._client.answer_pre_checkout_query( + pre_checkout_query_id=self.id, + ok=ok, + error_message=error_message + ) diff --git a/pyrogram/types/business/shipping_address.py b/pyrogram/types/business/shipping_address.py new file mode 100644 index 0000000000..cd9af47285 --- /dev/null +++ b/pyrogram/types/business/shipping_address.py @@ -0,0 +1,63 @@ +# 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 ..object import Object + + +class ShippingAddress(Object): + """This object represents a shipping address. + + Parameters: + country_code (``str``): + Two-letter `ISO 3166-1 alpha-2 `_ country code. + + state (``str``): + State, if applicable. + + city (``str``): + City. + + street_line1 (``str``): + First line for the address. + + street_line2 (``str``): + Second line for the address. + + post_code (``str``): + Address post code. + + """ + + def __init__( + self, + *, + country_code: str, + state: str, + city: str, + street_line1: str, + street_line2: str, + post_code: str + ): + super().__init__() + + self.country_code = country_code + self.state = state + self.city = city + self.street_line1 = street_line1 + self.street_line2 = street_line2 + self.post_code = post_code diff --git a/pyrogram/types/business/successful_payment.py b/pyrogram/types/business/successful_payment.py new file mode 100644 index 0000000000..1cb1fc952b --- /dev/null +++ b/pyrogram/types/business/successful_payment.py @@ -0,0 +1,143 @@ +# 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 Union + +import pyrogram +from pyrogram import raw, types + +from ..object import Object + + +class SuccessfulPayment(Object): + """This object contains basic information about a successful payment. + + Parameters: + currency (``str``): + Three-letter ISO 4217 `currency `_ code, or ``XTR`` for payments in `Telegram Stars `_. + + total_amount (``int``): + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + invoice_payload (``str``): + Bot specified invoice payload. Only available to the bot that received the payment. + + shipping_option_id (``str``, *optional*): + Identifier of the shipping option chosen by the user. Only available to the bot that received the payment. + + order_info (:obj:`~pyrogram.types.OrderInfo`, *optional*): + Order information provided by the user. Only available to the bot that received the payment. + + telegram_payment_charge_id (``str``): + Telegram payment identifier. Only available to the bot that received the payment. + + provider_payment_charge_id (``str``): + Provider payment identifier. Only available to the bot that received the payment. + + is_recurring (``bool``, *optional*): + True, if this is a recurring payment. + + is_first_recurring (``bool``, *optional*): + True, if this is the first recurring payment. + + invoice_name (``str``, *optional*): + Name of the invoice; may be empty if unknown + + """ + + def __init__( + self, + *, + currency: str, + total_amount: str, + invoice_payload: str, + telegram_payment_charge_id: str, + provider_payment_charge_id: str, + shipping_option_id: str = None, + order_info: "types.OrderInfo" = None, + is_recurring: bool = None, + is_first_recurring: bool = None, + invoice_name: str = None + ): + super().__init__() + + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.telegram_payment_charge_id = telegram_payment_charge_id + self.provider_payment_charge_id = provider_payment_charge_id + self.shipping_option_id = shipping_option_id + self.order_info = order_info + self.is_recurring = is_recurring + self.is_first_recurring = is_first_recurring + self.invoice_name = invoice_name + + @staticmethod + def _parse( + client: "pyrogram.Client", + successful_payment: Union[ + "raw.types.MessageActionPaymentSent", + "raw.types.MessageActionPaymentSentMe" + ] + ) -> "SuccessfulPayment": + invoice_payload = None + telegram_payment_charge_id = None + provider_payment_charge_id = None + shipping_option_id = None + order_info = None + + if isinstance(successful_payment, raw.types.MessageActionPaymentSentMe): + # Try to decode invoice payload into string. If that fails, fallback to bytes instead of decoding by + # ignoring/replacing errors, this way, button clicks will still work. + try: + invoice_payload = successful_payment.payload.decode() + except (UnicodeDecodeError, AttributeError): + invoice_payload = successful_payment.payload + + telegram_payment_charge_id = successful_payment.charge.id + provider_payment_charge_id = successful_payment.charge.provider_charge_id + shipping_option_id = getattr(successful_payment, "shipping_option_id", None) + + if successful_payment.info: + payment_info = successful_payment.info + order_info = types.OrderInfo( + name=getattr(payment_info, "name", None), + phone_number=getattr(payment_info, "phone", None), + email=getattr(payment_info, "email", None), + shipping_address=types.ShippingAddress( + country_code=payment_info.shipping_address.country_iso2, + state=payment_info.shipping_address.state, + city=payment_info.shipping_address.city, + street_line1=payment_info.shipping_address.street_line1, + street_line2=payment_info.shipping_address.street_line2, + post_code=payment_info.shipping_address.post_code + ) + ) + + return SuccessfulPayment( + currency=successful_payment.currency, + total_amount=successful_payment.total_amount, + invoice_payload=invoice_payload, + telegram_payment_charge_id=telegram_payment_charge_id, + provider_payment_charge_id=shipping_option_id, + shipping_option_id=shipping_option_id, + order_info=order_info, + is_recurring=getattr(successful_payment, "recurring_used", None), + is_first_recurring=getattr(successful_payment, "recurring_init", None), + invoice_name=getattr(successful_payment, "invoice_slug", None) + ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index f10c2e9443..28061d56bb 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -263,6 +263,9 @@ class Message(Object, Update): invoice (:obj:`~pyrogram.types.Invoice`, *optional*): Message is an invoice for a `payment `_, information about the invoice. `More about payments » `_ + successful_payment (:obj:`~pyrogram.types.SuccessfulPayment`, *optional*): + Message is a service message about a successful payment, information about the payment. `More about payments »`_ + users_shared (:obj:`~pyrogram.types.UsersShared`, *optional*): Service message: users were shared with the bot @@ -392,7 +395,7 @@ class Message(Object, Update): """ - # TODO: Add game missing field. Also invoice, successful_payment, connected_website + # TODO: Add game missing field. Also connected_website def __init__( self, @@ -458,7 +461,7 @@ def __init__( migrate_from_chat_id: int = None, pinned_message: "Message" = None, invoice: "types.Invoice" = None, - + successful_payment: "types.SuccessfulPayment" = None, users_shared: "types.UsersShared" = None, chat_shared: "types.ChatShared" = None, @@ -608,6 +611,7 @@ def __init__( self.custom_action = custom_action self.sender_business_bot = sender_business_bot self.business_connection_id = business_connection_id + self.successful_payment = successful_payment self._raw = _raw @staticmethod @@ -689,6 +693,7 @@ async def _parse( forum_topic_reopened = None general_forum_topic_hidden = None general_forum_topic_unhidden = None + successful_payment = None service_type = None @@ -878,6 +883,10 @@ async def _parse( service_type = enums.MessageServiceType.FORUM_TOPIC_CREATED forum_topic_created = types.ForumTopicCreated._parse(action) + elif isinstance(action, (raw.types.MessageActionPaymentSent, raw.types.MessageActionPaymentSentMe)): + successful_payment = types.SuccessfulPayment._parse(client, action) + service_type = enums.MessageServiceType.SUCCESSFUL_PAYMENT + elif isinstance(action, raw.types.MessageActionTopicEdit): title = getattr(action, "title", None) icon_emoji_id = getattr(action, "icon_emoji_id", None) @@ -932,6 +941,7 @@ async def _parse( gifted_premium=gifted_premium, users_shared=users_shared, chat_shared=chat_shared, + successful_payment=successful_payment, chat_ttl_period=chat_ttl_period, chat_ttl_setting_from=chat_ttl_setting_from, boost_added=boost_added, @@ -3657,6 +3667,194 @@ async def reply_voice( progress_args=progress_args ) + async def reply_invoice( + self, + title: str, + description: str, + payload: Union[str, bytes], + currency: str, + prices: List["types.LabeledPrice"], + message_thread_id: int = None, + quote: bool = None, + provider_token: str = None, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + start_parameter: str = None, + provider_data: str = None, + photo_url: str = "", + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + is_flexible: bool = None, + disable_notification: bool = None, + protect_content: bool = None, + message_effect_id: int = None, + reply_parameters: "types.ReplyParameters" = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None + ) -> "Message": + """Bound method *reply_invoice* of :obj:`~pyrogram.types.Message`. + + Parameters: + title (``str``): + Product name, 1-32 characters. + + description (``str``): + Product description, 1-255 characters + + payload (``str`` | ``bytes``): + Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. + + currency (``str``): + Three-letter ISO 4217 currency code, see `more on currencies `_. Pass ``XTR`` for payments in `Telegram Stars `_. + + prices (List of :obj:`~pyrogram.types.LabeledPrice`): + Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_. + + message_thread_id (``int``, *optional*): + If the message is in a thread, ID of the original message. + + quote (``bool``, *optional*): + If ``True``, the message will be sent as a reply to this message. + If *reply_to_message_id* is passed, this parameter will be ignored. + Defaults to ``True`` in group chats and ``False`` in private chats. + + provider_token (``str``, *optional*): + Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_. + + max_tip_amount (``int``, *optional*): + The maximum accepted amount for tips in the smallest units of the currency (integer, **not** float/double). For example, for a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_. + + suggested_tip_amounts (List of ``int``, *optional*): + An array of suggested amounts of tips in the smallest units of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed ``max_tip_amount``. + + start_parameter (``str``, *optional*): + Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a Pay button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a URL button with a deep link to the bot (instead of a Pay button), with the value used as the start parameter. + + provider_data (``str``, *optional*): + JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. + + photo_url (``str``, *optional*): + URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. + + photo_size (``int``, *optional*): + Photo size in bytes + + photo_width (``int``, *optional*): + Photo width + + photo_height (``int``, *optional*): + Photo height + + need_name (``bool``, *optional*): + Pass True if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_. + + need_phone_number (``bool``, *optional*): + Pass True if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_. + + need_email (``bool``, *optional*): + Pass True if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_. + + need_shipping_address (``bool``, *optional*): + Pass True if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_. + + send_phone_number_to_provider (``bool``, *optional*): + Pass True if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + send_email_to_provider (``bool``, *optional*): + Pass True if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + is_flexible (``bool``, *optional*): + Pass True if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + message_effect_id (``int`` ``64-bit``, *optional*): + Unique identifier of the message effect to be added to the message; for private chats only. + + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): + Description of the message to reply to + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): + Additional interface options. An object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + + caption (``str``, *optional*): + Document caption, 0-1024 characters. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + Returns: + On success, the sent :obj:`~pyrogram.types.Message` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if quote is None: + quote = self.chat.type != enums.ChatType.PRIVATE + + if not reply_parameters and quote: + reply_parameters = types.ReplyParameters( + message_id=self.id + ) + + return await self._client.send_invoice( + chat_id=self.chat.id, + title=title, + description=description, + payload=payload, + currency=currency, + prices=prices, + message_thread_id=message_thread_id or self.message_thread_id, + provider_token=provider_token, + max_tip_amount=max_tip_amount, + suggested_tip_amounts=suggested_tip_amounts, + start_parameter=start_parameter, + provider_data=provider_data, + photo_url=photo_url, + photo_size=photo_size, + photo_width=photo_width, + photo_height=photo_height, + need_name=need_name, + need_phone_number=need_phone_number, + need_email=need_email, + need_shipping_address=need_shipping_address, + send_phone_number_to_provider=send_phone_number_to_provider, + send_email_to_provider=send_email_to_provider, + is_flexible=is_flexible, + disable_notification=disable_notification, + protect_content=protect_content or self.has_protected_content, + message_effect_id=message_effect_id or self.effect_id, + reply_parameters=reply_parameters, + reply_markup=reply_markup, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities + ) + async def edit_text( self, text: str, From 99389056174fd9220ca9723a25ea5ff1d98f0755 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 6 Jun 2024 17:02:45 +0200 Subject: [PATCH 079/154] Bug Fixes (#32) --- pyrogram/methods/bots/send_game.py | 3 +++ pyrogram/methods/messages/edit_inline_text.py | 4 +--- pyrogram/methods/messages/send_audio.py | 8 ++++---- pyrogram/types/messages_and_media/message.py | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pyrogram/methods/bots/send_game.py b/pyrogram/methods/bots/send_game.py index 2f97e98246..a04707b629 100644 --- a/pyrogram/methods/bots/send_game.py +++ b/pyrogram/methods/bots/send_game.py @@ -16,11 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import logging from typing import Union import pyrogram from pyrogram import raw, utils, types +log = logging.getLogger(__name__) + class SendGame: async def send_game( diff --git a/pyrogram/methods/messages/edit_inline_text.py b/pyrogram/methods/messages/edit_inline_text.py index 411901225b..2f0dd30ef1 100644 --- a/pyrogram/methods/messages/edit_inline_text.py +++ b/pyrogram/methods/messages/edit_inline_text.py @@ -20,9 +20,7 @@ from typing import Optional, List import pyrogram -from pyrogram import raw, enums -from pyrogram import types -from pyrogram import utils +from pyrogram import raw, enums, types, utils from .inline_session import get_session log = logging.getLogger(__name__) diff --git a/pyrogram/methods/messages/send_audio.py b/pyrogram/methods/messages/send_audio.py index 348571942c..bace37df5b 100644 --- a/pyrogram/methods/messages/send_audio.py +++ b/pyrogram/methods/messages/send_audio.py @@ -16,20 +16,20 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import logging import os import re from datetime import datetime from typing import Union, BinaryIO, List, Optional, Callable import pyrogram -from pyrogram import StopTransmission, enums -from pyrogram import raw -from pyrogram import types -from pyrogram import utils +from pyrogram import StopTransmission, enums, raw, types, utils from pyrogram.errors import FilePartMissing from pyrogram.file_id import FileType from .inline_session import get_session +log = logging.getLogger(__name__) + class SendAudio: async def send_audio( diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 28061d56bb..8fa2deeb97 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -4310,7 +4310,7 @@ async def copy( chat_id=chat_id, disable_notification=disable_notification, message_effect_id=self.effect_id, - show_caption_above_media=show_caption_above_media, + show_caption_above_media=show_caption_above_media or self.show_caption_above_media, reply_parameters=reply_parameters, message_thread_id=message_thread_id or self.message_thread_id, business_connection_id=business_connection_id or self.business_connection_id, From 83a96da928278b1a96458c78ada15eaa75832a80 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 6 Jun 2024 17:05:44 +0200 Subject: [PATCH 080/154] Update Pyrogram to v2.1.32.6 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index b1fbdc6208..245d25df6b 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.5" +__version__ = "2.1.32.6" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 16224c2f854cbb627b561b58bc37e5315ec90e1f Mon Sep 17 00:00:00 2001 From: Yehuda lev <94082865+yehuda-lev@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:07:21 +0300 Subject: [PATCH 081/154] [payments] fix `amount` of `LabeledPrice` to `int` (#34) --- pyrogram/types/business/labeled_price.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/types/business/labeled_price.py b/pyrogram/types/business/labeled_price.py index ccd2a42fca..aabb4d9b52 100644 --- a/pyrogram/types/business/labeled_price.py +++ b/pyrogram/types/business/labeled_price.py @@ -37,7 +37,7 @@ class LabeledPrice(Object): def __init__( self, label: str, - amount: str + amount: int ): super().__init__() From 939bfb3746f3223f3ae9ece12823cf871ae6b475 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 7 Jun 2024 19:15:16 +0200 Subject: [PATCH 082/154] Add create_invoice_link Update documentation of pay button --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/methods/business/__init__.py | 2 + .../methods/business/create_invoice_link.py | 162 ++++++++++++++++++ .../inline_keyboard_button.py | 3 +- 5 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 pyrogram/methods/business/create_invoice_link.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index d0588b5373..b180e57c3c 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -373,6 +373,7 @@ def get_title_list(s: str) -> list: business=""" Telegram Business & Fragment answer_pre_checkout_query + create_invoice_link get_business_connection get_collectible_item_info refund_star_payment diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 4774d6ea8e..765cb93716 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -16,7 +16,7 @@ If you found any issue or have any suggestions, feel free to make `an issue . from .answer_pre_checkout_query import AnswerPreCheckoutQuery +from .create_invoice_link import CreateInvoiceLink from .get_business_connection import GetBusinessConnection from .get_collectible_item_info import GetCollectibleItemInfo from .refund_star_payment import RefundStarPayment @@ -25,6 +26,7 @@ class TelegramBusiness( AnswerPreCheckoutQuery, + CreateInvoiceLink, GetBusinessConnection, GetCollectibleItemInfo, RefundStarPayment, diff --git a/pyrogram/methods/business/create_invoice_link.py b/pyrogram/methods/business/create_invoice_link.py new file mode 100644 index 0000000000..6298836445 --- /dev/null +++ b/pyrogram/methods/business/create_invoice_link.py @@ -0,0 +1,162 @@ +# 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 . + +import logging +from typing import List, Optional, Union + +import pyrogram +from pyrogram import enums, raw, utils, types + +log = logging.getLogger(__name__) + + +class CreateInvoiceLink: + async def create_invoice_link( + self: "pyrogram.Client", + title: str, + description: str, + payload: Union[str, bytes], + currency: str, + prices: List["types.LabeledPrice"], + provider_token: str = None, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + start_parameter: str = None, + provider_data: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + is_flexible: bool = None + ) -> str: + """Use this method to create a link for an invoice. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + title (``str``): + Product name, 1-32 characters. + + description (``str``): + Product description, 1-255 characters + + payload (``str`` | ``bytes``): + Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. + + currency (``str``): + Three-letter ISO 4217 currency code, see `more on currencies `_. Pass ``XTR`` for payments in `Telegram Stars `_. + + prices (List of :obj:`~pyrogram.types.LabeledPrice`): + Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_. + + provider_token (``str``, *optional*): + Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_. + + max_tip_amount (``int``, *optional*): + The maximum accepted amount for tips in the smallest units of the currency (integer, **not** float/double). For example, for a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_. + + suggested_tip_amounts (List of ``int``, *optional*): + An array of suggested amounts of tips in the smallest units of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed ``max_tip_amount``. + + start_parameter (``str``, *optional*): + Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a Pay button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a URL button with a deep link to the bot (instead of a Pay button), with the value used as the start parameter. + + provider_data (``str``, *optional*): + JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. + + photo_url (``str``, *optional*): + URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. + + photo_size (``int``, *optional*): + Photo size in bytes + + photo_width (``int``, *optional*): + Photo width + + photo_height (``int``, *optional*): + Photo height + + need_name (``bool``, *optional*): + Pass True if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_. + + need_phone_number (``bool``, *optional*): + Pass True if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_. + + need_email (``bool``, *optional*): + Pass True if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_. + + need_shipping_address (``bool``, *optional*): + Pass True if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_. + + send_phone_number_to_provider (``bool``, *optional*): + Pass True if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + send_email_to_provider (``bool``, *optional*): + Pass True if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + is_flexible (``bool``, *optional*): + Pass True if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_. + + Returns: + ``str``: On success, the created invoice link is returned. + + """ + + rpc = raw.functions.payments.ExportInvoice( + invoice_media=raw.types.InputMediaInvoice( + title=title, + description=description, + photo=raw.types.InputWebDocument( + url=photo_url, + mime_type="image/jpg", + size=photo_size, + attributes=[ + raw.types.DocumentAttributeImageSize( + w=photo_width, + h=photo_height + ) + ] + ) if photo_url else None, + invoice=raw.types.Invoice( + currency=currency, + prices=[i.write() for i in prices], + test=self.test_mode, + name_requested=need_name, + phone_requested=need_phone_number, + email_requested=need_email, + shipping_address_requested=need_shipping_address, + flexible=is_flexible, + phone_to_provider=send_phone_number_to_provider, + email_to_provider=send_email_to_provider + ), + payload=payload.encode() if isinstance(payload, str) else payload, + provider=provider_token, + provider_data=raw.types.DataJSON( + data=provider_data if provider_data else "{}" + ), + start_param=start_parameter + ) + ) + r = await self.invoke(rpc) + return r.url diff --git a/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py b/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py index 5ea38a283b..e7b682552d 100644 --- a/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py @@ -74,7 +74,8 @@ class InlineKeyboardButton(Object): **NOTE**: This type of button **must** always be the first button in the first row. pay (``bool``, *optional*): - Specify True, to send a Pay button. + Specify True, to send a Pay button. Substrings "⭐" and "XTR" in the buttons's text will be replaced with a Telegram Star icon. + **NOTE**: This type of button **must** always be the first button in the first row and can only be used in invoice messages. callback_data_with_password (``bytes``, *optional*): From d7301e10425155b2c16bc728f66857643e724164 Mon Sep 17 00:00:00 2001 From: Zaid _ Date: Fri, 7 Jun 2024 19:45:12 +0200 Subject: [PATCH 083/154] Add invite_group_call_participants method (#35) --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/phone/__init__.py | 4 +- .../phone/invite_group_call_participants.py | 96 +++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/phone/invite_group_call_participants.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index b180e57c3c..3bf898e85d 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -345,6 +345,7 @@ def get_title_list(s: str) -> list: """, phone=""" Phone + invite_group_call_participants load_group_call_participants """, stickers=""" diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 765cb93716..c7dd55c0be 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_). - Added the types :obj:`~pyrogram.types.LabeledPrice`, :obj:`~pyrogram.types.OrderInfo`, :obj:`~pyrogram.types.PreCheckoutQuery`, :obj:`~pyrogram.types.ShippingAddress`, :obj:`~pyrogram.types.SuccessfulPayment`, :obj:`~pyrogram.types.`. - Added the ``successful_payment`` parameter to the :obj:`~pyrogram.types.Message`. Added the filter :obj:`~pyrogram.filters.successful_payment` to detect service messages of Successful Payment type. - Added the methods :meth:`~pyrogram.Client.send_invoice`, :meth:`~pyrogram.Client.answer_pre_checkout_query` (:meth:`~pyrogram.types.PreCheckoutQuery.answer`), :meth:`~pyrogram.Client.refund_star_payment`, :meth:`~pyrogram.Client.create_invoice_link`. diff --git a/pyrogram/methods/phone/__init__.py b/pyrogram/methods/phone/__init__.py index 3787ed06dd..955b660307 100644 --- a/pyrogram/methods/phone/__init__.py +++ b/pyrogram/methods/phone/__init__.py @@ -18,9 +18,11 @@ # along with Pyrogram. If not, see . from .load_group_call_participants import LoadGroupCallParticipants +from .invite_group_call_participants import InviteGroupCallParticipants class Phone( - LoadGroupCallParticipants + InviteGroupCallParticipants, + LoadGroupCallParticipants, ): pass diff --git a/pyrogram/methods/phone/invite_group_call_participants.py b/pyrogram/methods/phone/invite_group_call_participants.py new file mode 100644 index 0000000000..affe7f1550 --- /dev/null +++ b/pyrogram/methods/phone/invite_group_call_participants.py @@ -0,0 +1,96 @@ +# 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 Union, List + +import pyrogram +from pyrogram import types, raw, utils + + +class InviteGroupCallParticipants: + async def invite_group_call_participants( + self: "pyrogram.Client", + chat_id: Union[int, str], + user_ids: Union[Union[int, str], List[Union[int, str]]], + ) -> "types.Message": + """Invites users to an active group call. Sends a service message of type :obj:`~pyrogram.enums.MessageServiceType.VIDEO_CHAT_PARTICIPANTS_INVITED` for video chats. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. A chat can be either a basic group or a supergroup. + + user_ids (``int`` | ``str`` | List of ``int`` or ``str``): + Users identifiers to invite to group call in the chat. + You can pass an ID (int) or username (str). + At most 10 users can be invited simultaneously. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent service message is returned. + + Example: + .. code-block:: python + + await app.invite_group_call_participants(chat_id, user_id) + + """ + peer = await self.resolve_peer(chat_id) + + if isinstance(peer, raw.types.InputPeerChannel): + r = await self.invoke(raw.functions.channels.GetFullChannel(channel=peer)) + elif isinstance(peer, raw.types.InputPeerChat): + r = await self.invoke( + raw.functions.messages.GetFullChat(chat_id=peer.chat_id) + ) + else: + raise ValueError("Target chat should be group, supergroup or channel.") + + call = r.full_chat.call + + if call is None: + raise ValueError("No active group call at this chat.") + + user_ids = [user_ids] if not isinstance(user_ids, list) else user_ids + + r = await self.invoke( + raw.functions.phone.InviteToGroupCall( + call=call, + users=[ + await self.resolve_peer(i) + for i in user_ids + ] + ) + ) + + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewMessage, + raw.types.UpdateNewScheduledMessage + ) + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + ) From 8bb36ed50003b769a086513377ef4bbeb637fcdc Mon Sep 17 00:00:00 2001 From: Malay Patra <97306538+malay9418@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:32:56 +0200 Subject: [PATCH 084/154] feat(connectivity): support connections in the replIT environment This commit adds support for connectivity by exploiting environment variables. Ref: https://ask.replit.com/t/pyrogram-network-issue/33679/46 https://ask.replit.com/t/pyrogram-network-issue/33679/47 --- docs/source/releases/changes-in-this-fork.rst | 3 ++- pyrogram/session/internals/data_center.py | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index c7dd55c0be..b29837582f 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_. Set the environment variable ``PYROGRAM_REPLIT_NWTRAFIK_PORT`` value to ``5222`` if you want to connect to Production Telegram Servers, **OR** Set the environment variable ``PYROGRAM_REPLIT_WNTRAFIK_PORT`` value to ``5223`` if you want to connect to Test Telegram Servers, before starting the :obj:`~pyrogram.Client`. - Added the :meth:`~pyrogram.Client.invite_group_call_participants` (`#35 `_). - Added the types :obj:`~pyrogram.types.LabeledPrice`, :obj:`~pyrogram.types.OrderInfo`, :obj:`~pyrogram.types.PreCheckoutQuery`, :obj:`~pyrogram.types.ShippingAddress`, :obj:`~pyrogram.types.SuccessfulPayment`, :obj:`~pyrogram.types.`. - Added the ``successful_payment`` parameter to the :obj:`~pyrogram.types.Message`. Added the filter :obj:`~pyrogram.filters.successful_payment` to detect service messages of Successful Payment type. @@ -204,7 +205,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_. - Added new parameter ``no_joined_notifications`` to :obj:`~pyrogram.Client`. - Fix history TTL Service Message Parse. -- Added environment variables ``PYROGRAM_DONOT_LOG_UNKNOWN_ERRORS``. Thanks to `... `_. +- Thanks to `... `_. If you want to change the location of the ``unknown_errors.txt`` file that is created by :obj:`~pyrogram.Client`, set the environment variable ``PYROGRAM_LOG_UNKNOWN_ERRORS_FILENAME`` value to the path where the file should get created. - Renamed ``force_document`` to ``disable_content_type_detection`` in :meth:`~pyrogram.Client.send_document` and :meth:`~pyrogram.types.Message.reply_document`. - Added missing attributes ``added_to_attachment_menu``, ``can_be_added_to_attachment_menu``, ``can_join_groups``, ``can_read_all_group_messages``, ``supports_inline_queries``, ``restricts_new_chats`` to the :obj:`~pyrogram.types.User`. - Migrate project to ``pyproject.toml`` from ``setup.py``. diff --git a/pyrogram/session/internals/data_center.py b/pyrogram/session/internals/data_center.py index d314626352..1b185fd4d7 100644 --- a/pyrogram/session/internals/data_center.py +++ b/pyrogram/session/internals/data_center.py @@ -18,6 +18,8 @@ from typing import Tuple +import os + class DataCenter: TEST = { @@ -60,6 +62,9 @@ class DataCenter: 4: "2001:067c:04e8:f004:0000:0000:0000:000b" } + TEST_PORT = int(os.environ.get("PYROGRAM_REPLIT_WNTRAFIK_PORT", 80)) + PROD_PORT = int(os.environ.get("PYROGRAM_REPLIT_NWTRAFIK_PORT", 443)) + def __new__(cls, dc_id: int, test_mode: bool, ipv6: bool, media: bool) -> Tuple[str, int]: if test_mode: if ipv6: @@ -67,7 +72,7 @@ def __new__(cls, dc_id: int, test_mode: bool, ipv6: bool, media: bool) -> Tuple[ else: ip = cls.TEST[dc_id] - return ip, 80 + return ip, cls.TEST_PORT else: if ipv6: if media: @@ -80,4 +85,4 @@ def __new__(cls, dc_id: int, test_mode: bool, ipv6: bool, media: bool) -> Tuple[ else: ip = cls.PROD[dc_id] - return ip, 443 + return ip, cls.PROD_PORT From c85c9425114e35f8eaa6eddaebc5c7bae8a7f7bf Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 8 Jun 2024 19:24:52 +0200 Subject: [PATCH 085/154] Attempt to fix docs-build --- .github/workflows/build-docs.yml | 4 ++-- pyrogram/types/messages_and_media/story.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index f4ec1e65dd..c6bd18ea2b 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -22,9 +22,9 @@ jobs: make rm -rf .github compiler Pyrogram* pyrogram* tests .gitignore COPYING* rm -f MANIFEST* Makefile NOTICE README.md - rm -f pyproject.toml + rm -f pyproject.toml hatch_build.py setup.py mv docs/build/html/* . - rm -rf docs venv + rm -rf docs venv __pycache__ touch .nojekyll git checkout --orphan gh-pages git config user.email "14043624+delivrance@users.noreply.github.com" diff --git a/pyrogram/types/messages_and_media/story.py b/pyrogram/types/messages_and_media/story.py index cb9fbd0dfd..42daa3f740 100644 --- a/pyrogram/types/messages_and_media/story.py +++ b/pyrogram/types/messages_and_media/story.py @@ -138,7 +138,7 @@ async def _parse( chats: dict, story_media: "raw.types.MessageMediaStory", reply_story: "raw.types.MessageReplyStoryHeader" - ) -> "Video": + ) -> "Story": story_id = None chat = None @@ -158,7 +158,6 @@ async def _parse( skipped = None deleted = None - # TODO: investigate a bug here if story_media: if story_media.peer: raw_peer_id = utils.get_peer_id(story_media.peer) @@ -166,8 +165,9 @@ async def _parse( story_id = getattr(story_media, "id", None) if reply_story: if reply_story.peer: - raw_peer_id = utils.get_peer_id(reply_story.peer) - chat = await client.get_chat(raw_peer_id, False) + raw_peer_id = utils.get_raw_peer_id(reply_story.peer) + + chat = types.Chat._parse_chat(client, chats.get(raw_peer_id)) story_id = getattr(reply_story, "story_id", None) if story_id and not client.me.is_bot: try: @@ -179,7 +179,7 @@ async def _parse( ) ) ).stories[0] - except (RPCError,IndexError): + except (RPCError, IndexError): pass else: if isinstance(story_item, raw.types.StoryItemDeleted): From 822f38acb254ccfe617d6eb9df29920ae92fa5f2 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 8 Jun 2024 20:18:33 +0200 Subject: [PATCH 086/154] Add ShippingQuery and answer_shipping_query Add on_shipping_query updates. Also, fix spelling mistakes in previous commits. --- compiler/docs/compiler.py | 7 + compiler/docs/template/bound-methods.rst | 13 ++ docs/source/api/decorators.rst | 4 +- docs/source/api/handlers.rst | 4 +- docs/source/releases/changes-in-this-fork.rst | 4 +- pyrogram/dispatcher.py | 15 +- pyrogram/handlers/__init__.py | 1 + .../handlers/pre_checkout_query_handler.py | 2 +- pyrogram/handlers/shipping_query_handler.py | 51 +++++++ pyrogram/methods/business/__init__.py | 1 + .../methods/business/answer_shipping_query.py | 83 +++++++++++ pyrogram/methods/decorators/__init__.py | 3 +- .../methods/decorators/on_shipping_query.py | 62 +++++++++ pyrogram/types/business/__init__.py | 4 + pyrogram/types/business/pre_checkout_query.py | 2 +- pyrogram/types/business/shipping_option.py | 74 ++++++++++ pyrogram/types/business/shipping_query.py | 131 ++++++++++++++++++ 17 files changed, 449 insertions(+), 12 deletions(-) create mode 100644 pyrogram/handlers/shipping_query_handler.py create mode 100644 pyrogram/methods/business/answer_shipping_query.py create mode 100644 pyrogram/methods/decorators/on_shipping_query.py create mode 100644 pyrogram/types/business/shipping_option.py create mode 100644 pyrogram/types/business/shipping_query.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 3bf898e85d..5adb8c7704 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -374,6 +374,7 @@ def get_title_list(s: str) -> list: business=""" Telegram Business & Fragment answer_pre_checkout_query + answer_shipping_query create_invoice_link get_business_connection get_collectible_item_info @@ -573,6 +574,8 @@ def get_title_list(s: str) -> list: OrderInfo PreCheckoutQuery ShippingAddress + ShippingOption + ShippingQuery SuccessfulPayment """, users_chats=""" @@ -719,6 +722,10 @@ def get_title_list(s: str) -> list: PreCheckoutQuery PreCheckoutQuery.answer """, + shipping_query=""" + ShippingQuery + ShippingQuery.answer + """, chat_join_request=""" ChatJoinRequest ChatJoinRequest.approve diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index bcc02612cb..dc35f4ea24 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -101,6 +101,19 @@ PreCheckoutQuery {pre_checkout_query_toctree} +ShippingQuery +----------- + +.. hlist:: + :columns: 2 + + {shipping_query_hlist} + +.. toctree:: + :hidden: + + {shipping_query_toctree} + ChatJoinRequest --------------- diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index 15ce487473..1d143eb3a0 100644 --- a/docs/source/api/decorators.rst +++ b/docs/source/api/decorators.rst @@ -67,8 +67,8 @@ Details .. autodecorator:: pyrogram.Client.on_inline_query() .. autodecorator:: pyrogram.Client.on_chosen_inline_result() .. autodecorator:: pyrogram.Client.on_callback_query() - - +.. autodecorator:: pyrogram.Client.on_shipping_query() +.. autodecorator:: pyrogram.Client.on_pre_checkout_query() .. autodecorator:: pyrogram.Client.on_poll() diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst index 0b25fb4621..eb32fdf1df 100644 --- a/docs/source/api/handlers.rst +++ b/docs/source/api/handlers.rst @@ -68,8 +68,8 @@ Details .. autoclass:: InlineQueryHandler() .. autoclass:: ChosenInlineResultHandler() .. autoclass:: CallbackQueryHandler() - - +.. autoclass:: ShippingQueryHandler() +.. autoclass:: PreCheckoutQueryHandler() .. autoclass:: PollHandler() diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index b29837582f..b5459f9f97 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -16,9 +16,9 @@ If you found any issue or have any suggestions, feel free to make `an issue `_. Set the environment variable ``PYROGRAM_REPLIT_NWTRAFIK_PORT`` value to ``5222`` if you want to connect to Production Telegram Servers, **OR** Set the environment variable ``PYROGRAM_REPLIT_WNTRAFIK_PORT`` value to ``5223`` if you want to connect to Test Telegram Servers, before starting the :obj:`~pyrogram.Client`. - Added the :meth:`~pyrogram.Client.invite_group_call_participants` (`#35 `_). -- Added the types :obj:`~pyrogram.types.LabeledPrice`, :obj:`~pyrogram.types.OrderInfo`, :obj:`~pyrogram.types.PreCheckoutQuery`, :obj:`~pyrogram.types.ShippingAddress`, :obj:`~pyrogram.types.SuccessfulPayment`, :obj:`~pyrogram.types.`. +- Added the types :obj:`~pyrogram.types.LabeledPrice`, :obj:`~pyrogram.types.OrderInfo`, :obj:`~pyrogram.types.PreCheckoutQuery`, :obj:`~pyrogram.types.ShippingAddress`, :obj:`~pyrogram.types.ShippingOption`, :obj:`~pyrogram.types.ShippingQuery` and :obj:`~pyrogram.types.SuccessfulPayment`. - Added the ``successful_payment`` parameter to the :obj:`~pyrogram.types.Message`. Added the filter :obj:`~pyrogram.filters.successful_payment` to detect service messages of Successful Payment type. -- Added the methods :meth:`~pyrogram.Client.send_invoice`, :meth:`~pyrogram.Client.answer_pre_checkout_query` (:meth:`~pyrogram.types.PreCheckoutQuery.answer`), :meth:`~pyrogram.Client.refund_star_payment`, :meth:`~pyrogram.Client.create_invoice_link`. +- Added the methods :meth:`~pyrogram.Client.send_invoice`, :meth:`~pyrogram.Client.answer_pre_checkout_query` (:meth:`~pyrogram.types.PreCheckoutQuery.answer`), :meth:`~pyrogram.Client.answer_shipping_query` (:meth:`~pyrogram.types.ShippingQuery.answer`), :meth:`~pyrogram.Client.refund_star_payment` and :meth:`~pyrogram.Client.create_invoice_link`. - Added the :meth:`~pyrogram.Client.send_web_app_custom_request`. - Added the :meth:`~pyrogram.Client.search_public_hashtag_messages` and :meth:`~pyrogram.Client.search_public_hashtag_messages_count`. - Added the ``fetch_replies`` parameter to :obj:`~pyrogram.Client`. diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index 65dd4e6f2e..559ff41199 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -32,7 +32,7 @@ InlineQueryHandler, ChosenInlineResultHandler, CallbackQueryHandler, - + ShippingQueryHandler, PreCheckoutQueryHandler, PollHandler, @@ -58,7 +58,8 @@ UpdateBotNewBusinessMessage, UpdateBotEditBusinessMessage, UpdateBotDeleteBusinessMessage, - UpdateBotPrecheckoutQuery + UpdateBotPrecheckoutQuery, + UpdateBotShippingQuery, ) log = logging.getLogger(__name__) @@ -78,6 +79,7 @@ class Dispatcher: MESSAGE_BOT_NA_REACTION_UPDATES = (UpdateBotMessageReaction,) MESSAGE_BOT_A_REACTION_UPDATES = (UpdateBotMessageReactions,) PRE_CHECKOUT_QUERY_UPDATES = (UpdateBotPrecheckoutQuery,) + SHIPPING_QUERY_UPDATES = (UpdateBotShippingQuery,) def __init__(self, client: "pyrogram.Client"): self.client = client @@ -175,6 +177,12 @@ async def message_bot_a_reaction_parser(update, users, chats): MessageReactionCountUpdatedHandler ) + async def shipping_query_parser(update, users, chats): + return ( + await pyrogram.types.ShippingQuery._parse(self.client, update, users), + ShippingQueryHandler + ) + async def pre_checkout_query_parser(update, users, chats): return ( await pyrogram.types.PreCheckoutQuery._parse(self.client, update, users), @@ -194,7 +202,8 @@ async def pre_checkout_query_parser(update, users, chats): Dispatcher.CHAT_JOIN_REQUEST_UPDATES: chat_join_request_parser, Dispatcher.MESSAGE_BOT_NA_REACTION_UPDATES: message_bot_na_reaction_parser, Dispatcher.MESSAGE_BOT_A_REACTION_UPDATES: message_bot_a_reaction_parser, - Dispatcher.PRE_CHECKOUT_QUERY_UPDATES: pre_checkout_query_parser + Dispatcher.PRE_CHECKOUT_QUERY_UPDATES: pre_checkout_query_parser, + Dispatcher.SHIPPING_QUERY_UPDATES: shipping_query_parser, } self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple} diff --git a/pyrogram/handlers/__init__.py b/pyrogram/handlers/__init__.py index 1460432499..a86165483c 100644 --- a/pyrogram/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -31,3 +31,4 @@ from .message_reaction_updated_handler import MessageReactionUpdatedHandler from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler from .pre_checkout_query_handler import PreCheckoutQueryHandler +from .shipping_query_handler import ShippingQueryHandler diff --git a/pyrogram/handlers/pre_checkout_query_handler.py b/pyrogram/handlers/pre_checkout_query_handler.py index 1eccff1bc7..c68b9aa478 100644 --- a/pyrogram/handlers/pre_checkout_query_handler.py +++ b/pyrogram/handlers/pre_checkout_query_handler.py @@ -43,7 +43,7 @@ class PreCheckoutQueryHandler(Handler): The Client itself, useful when you want to call other API methods inside the message handler. pre_checkout_query (:obj:`~pyrogram.types.PreCheckoutQuery`): - The received callback query. + New incoming pre-checkout query. Contains full information about checkout. """ diff --git a/pyrogram/handlers/shipping_query_handler.py b/pyrogram/handlers/shipping_query_handler.py new file mode 100644 index 0000000000..478a3745fa --- /dev/null +++ b/pyrogram/handlers/shipping_query_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 ShippingQueryHandler(Handler): + """The ShippingQueryHandler handler class. Used to handle shipping queries coming only from invoice buttons with flexible price. + + 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_shipping_query` decorator. + + Parameters: + callback (``Callable``): + Pass a function that will be called when a new PreCheckoutQuery arrives. It takes *(client, shipping_query)* + 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 callback queries to be passed + in your callback function. + + Other parameters: + client (:obj:`~pyrogram.Client`): + The Client itself, useful when you want to call other API methods inside the message handler. + + shipping_query (:obj:`~pyrogram.types.ShippingQuery`): + New incoming shipping query. Only for invoices with flexible price. + + """ + + def __init__(self, callback: Callable, filters=None): + super().__init__(callback, filters) diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index dd01d9d0fc..b205ed97bb 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -17,6 +17,7 @@ # along with Pyrogram. If not, see . from .answer_pre_checkout_query import AnswerPreCheckoutQuery +from .answer_shipping_query import AnswerShippingQuery from .create_invoice_link import CreateInvoiceLink from .get_business_connection import GetBusinessConnection from .get_collectible_item_info import GetCollectibleItemInfo diff --git a/pyrogram/methods/business/answer_shipping_query.py b/pyrogram/methods/business/answer_shipping_query.py new file mode 100644 index 0000000000..ab41200bd3 --- /dev/null +++ b/pyrogram/methods/business/answer_shipping_query.py @@ -0,0 +1,83 @@ +# 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 List + +import pyrogram +from pyrogram import raw, types + + +class AnswerShippingQuery: + async def answer_shipping_query( + self: "pyrogram.Client", + shipping_query_id: str, + ok: bool, + shipping_options: List["types.ShippingOptions"] = None, + error_message: str = None + ): + """If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the API sends the confirmation in the form of an :obj:`~pyrogram.handlers.ShippingQueryHandler`. + + Use this method to reply to shipping queries. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + shipping_query_id (``str``): + Unique identifier for the query to be answered. + + ok (``bool``): + Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems. + + shipping_options (List of :obj:`~pyrogram.types.ShippingOptions`, *optional*): + Required if ok is True. A array of available shipping options. + + error_message (``str``, *optional*): + Required if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user. + + Returns: + ``bool``: True, on success. + + Example: + .. code-block:: python + + # Proceed with the order + await app.answer_shipping_query(query_id, ok=True, shipping_options=shipping_options) + + # Answer with error message + await app.answer_shipping_query(query_id, ok=False, error_message="Error Message displayed to the user") + + """ + r = None + if ok: + r = await self.invoke( + raw.functions.messages.SetBotShippingResults( + query_id=int(pre_checkout_query_id), + shipping_options=[ + so.write() + for so in shipping_options + ] + ) + ) + else: + r = await self.invoke( + raw.functions.messages.SetBotShippingResults( + query_id=int(pre_checkout_query_id), + error=error_message or None + ) + ) + return r diff --git a/pyrogram/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py index 2bda666c29..f267543c82 100644 --- a/pyrogram/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -31,6 +31,7 @@ from .on_message_reaction_updated import OnMessageReactionUpdated from .on_message_reaction_count_updated import OnMessageReactionCountUpdated from .on_pre_checkout_query import OnPreCheckoutQuery +from .on_shipping_query import OnShippingQuery class Decorators( @@ -42,7 +43,7 @@ class Decorators( OnInlineQuery, OnChosenInlineResult, OnCallbackQuery, - + OnShippingQuery, OnPreCheckoutQuery, OnPoll, diff --git a/pyrogram/methods/decorators/on_shipping_query.py b/pyrogram/methods/decorators/on_shipping_query.py new file mode 100644 index 0000000000..7128a88b2d --- /dev/null +++ b/pyrogram/methods/decorators/on_shipping_query.py @@ -0,0 +1,62 @@ +# 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, Optional, Union + +import pyrogram +from pyrogram.filters import Filter + + +class OnShippingQuery: + def on_shipping_query( + self=None, + filters=None, + group: int = 0, + ) -> Callable: + """Decorator for handling shipping queries. + + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.ShippingQueryHandler`. + + Parameters: + filters (:obj:`~pyrogram.filters`, *optional*): + Pass one or more filters to allow only a subset of callback queries 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.ShippingQueryHandler(func, filters), group) + elif isinstance(self, Filter) or self is None: + if not hasattr(func, "handlers"): + func.handlers = [] + + func.handlers.append( + ( + pyrogram.handlers.ShippingQueryHandler(func, self), + group if filters is None else filters + ) + ) + + return func + + return decorator diff --git a/pyrogram/types/business/__init__.py b/pyrogram/types/business/__init__.py index fb2d9ddc90..3bc22e44a0 100644 --- a/pyrogram/types/business/__init__.py +++ b/pyrogram/types/business/__init__.py @@ -27,6 +27,8 @@ from .order_info import OrderInfo from .pre_checkout_query import PreCheckoutQuery from .shipping_address import ShippingAddress +from .shipping_option import ShippingOption +from .shipping_query import ShippingQuery from .successful_payment import SuccessfulPayment __all__ = [ @@ -41,5 +43,7 @@ "OrderInfo", "PreCheckoutQuery", "ShippingAddress", + "ShippingOption", + "ShippingQuery", "SuccessfulPayment", ] diff --git a/pyrogram/types/business/pre_checkout_query.py b/pyrogram/types/business/pre_checkout_query.py index c1c765d3b7..c542794a04 100644 --- a/pyrogram/types/business/pre_checkout_query.py +++ b/pyrogram/types/business/pre_checkout_query.py @@ -123,7 +123,7 @@ async def answer( await client.answer_pre_checkout_query( pre_checkout_query.id, - success=True + ok=True ) Example: diff --git a/pyrogram/types/business/shipping_option.py b/pyrogram/types/business/shipping_option.py new file mode 100644 index 0000000000..a0fa193494 --- /dev/null +++ b/pyrogram/types/business/shipping_option.py @@ -0,0 +1,74 @@ +# 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 List + +import pyrogram +from pyrogram import raw, types + +from ..object import Object + + +class ShippingOption(Object): + """This object represents one shipping option. + + Parameters: + id (``str``): + Shipping option identifier. + + title (``str``): + Option title. + + prices (List of :obj:`~pyrogram.types.LabeledPrice`): + List of price portions. + + """ + + def __init__( + self, + id: str, + title: str, + prices: "types.LabeledPrice" + ): + super().__init__() + + self.id = id + self.title = title + self.prices = prices + + @staticmethod + def _parse(shipping_option: "raw.types.ShippingOption") -> "ShippingOption": + if isinstance(shipping_option, raw.types.ShippingOption): + return ShippingOption( + id=shipping_option.id, + title=shipping_option.title, + prices=[ + types.LabeledPrice._parse(price) + for price in shipping_option.prices + ] + ) + + def write(self): + return raw.types.ShippingOption( + id=self.id, + title=self.title, + prices=[ + price.write() + for price in self.prices + ] + ) diff --git a/pyrogram/types/business/shipping_query.py b/pyrogram/types/business/shipping_query.py new file mode 100644 index 0000000000..753bac4a96 --- /dev/null +++ b/pyrogram/types/business/shipping_query.py @@ -0,0 +1,131 @@ +# 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 Union, Optional + +import pyrogram +from pyrogram import raw, types + +from ..object import Object +from ..update import Update + + +class ShippingQuery(Object, Update): + """This object contains information about an incoming shipping query. + + Parameters: + id (``str``): + Unique query identifier. + + from_user (:obj:`~pyrogram.types.User`): + User who sent the query. + + invoice_payload (``str``): + Bot specified invoice payload. Only available to the bot that received the payment. + + shipping_address (:obj:`~pyrogram.types.ShippingAddress`): + User specified shipping address. Only available to the bot that received the payment. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + id: str, + from_user: "types.User", + invoice_payload: str, + shipping_address: "types.ShippingAddress" = None + ): + super().__init__(client) + + self.id = id + self.from_user = from_user + self.invoice_payload = invoice_payload + self.shipping_address = shipping_address + + @staticmethod + async def _parse( + client: "pyrogram.Client", + shipping_query: "raw.types.updateBotShippingQuery", + users: dict + ) -> "PreCheckoutQuery": + # Try to decode pre-checkout query payload into string. If that fails, fallback to bytes instead of decoding by + # ignoring/replacing errors, this way, button clicks will still work. + try: + payload = shipping_query.payload.decode() + except (UnicodeDecodeError, AttributeError): + payload = shipping_query.payload + + return PreCheckoutQuery( + id=str(shipping_query.query_id), + from_user=types.User._parse(client, users[shipping_query.user_id]), + invoice_payload=payload, + shipping_address=types.ShippingAddress( + country_code=shipping_query.shipping_address.country_iso2, + state=pshipping_query.shipping_address.state, + city=shipping_query.shipping_address.city, + street_line1=shipping_query.shipping_address.street_line1, + street_line2=shipping_query.shipping_address.street_line2, + post_code=shipping_query.shipping_address.post_code + ), + client=client + ) + + async def answer( + self, + ok: bool, + shipping_options: "types.ShippingOptions" = None, + error_message: str = None + ): + """Bound method *answer* of :obj:`~pyrogram.types.ShippingQuery`. + + Use this method as a shortcut for: + + .. code-block:: python + + await client.answer_shipping_query( + shipping_query.id, + ok=True + ) + + Example: + .. code-block:: python + + await shipping_query.answer(ok=True) + + Parameters: + ok (``bool``): + Pass True if delivery to the specified address is possible and False if there are any problems (for example, if delivery to the specified address is not possible). + + shipping_options (:obj:`~pyrogram.types.ShippingOptions`, *optional*): + Required if ok is True. A JSON-serialized array of available shipping options. + + error_message (``str``, *optional*): + Required if ok is False. Error message in human readable form that explains why it is impossible to complete the order (e.g. "Sorry, delivery to your desired address is unavailable'). Telegram will display this message to the user. + + Returns: + ``bool``: True, on success. + + """ + return await self._client.answer_shipping_query( + shipping_query_id=self.id, + ok=ok, + shipping_options=shipping_options, + error_message=error_message + ) From a1da2c5029a898dd375826e5170b4bf2132e2dce Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 9 Jun 2024 15:07:55 +0200 Subject: [PATCH 087/154] Add on_story updates in High Level Git-Origin-Commit-Id: 3a01fea Co-authored-by: wulan17 Co-authored-by: KurimuzonAkuma --- docs/source/api/decorators.rst | 2 + docs/source/api/handlers.rst | 2 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/dispatcher.py | 18 +- pyrogram/handlers/__init__.py | 1 + pyrogram/handlers/story_handler.py | 49 +++++ pyrogram/methods/decorators/__init__.py | 2 + .../decorators/on_pre_checkout_query.py | 2 + pyrogram/methods/decorators/on_raw_update.py | 2 - .../methods/decorators/on_shipping_query.py | 2 + pyrogram/methods/decorators/on_story.py | 64 +++++++ .../external_reply_info.py | 2 +- pyrogram/types/messages_and_media/message.py | 4 +- pyrogram/types/messages_and_media/story.py | 169 ++++++++++++++---- 14 files changed, 279 insertions(+), 41 deletions(-) create mode 100644 pyrogram/handlers/story_handler.py create mode 100644 pyrogram/methods/decorators/on_story.py diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index 1d143eb3a0..0013ba86d2 100644 --- a/docs/source/api/decorators.rst +++ b/docs/source/api/decorators.rst @@ -51,6 +51,7 @@ Index - :meth:`~Client.on_deleted_messages` - :meth:`~Client.on_user_status` - :meth:`~Client.on_disconnect` + - :meth:`~Client.on_story` - :meth:`~Client.on_raw_update` ----- @@ -79,4 +80,5 @@ Details .. autodecorator:: pyrogram.Client.on_deleted_messages() .. autodecorator:: pyrogram.Client.on_user_status() .. autodecorator:: pyrogram.Client.on_disconnect() +.. autodecorator:: pyrogram.Client.on_story() .. autodecorator:: pyrogram.Client.on_raw_update() diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst index eb32fdf1df..9aebe5ebd6 100644 --- a/docs/source/api/handlers.rst +++ b/docs/source/api/handlers.rst @@ -52,6 +52,7 @@ Index - :class:`UserStatusHandler` - :class:`DisconnectHandler` + - :class:`StoryHandler` - :class:`RawUpdateHandler` ----- @@ -80,4 +81,5 @@ Details .. autoclass:: DeletedMessagesHandler() .. autoclass:: UserStatusHandler() .. autoclass:: DisconnectHandler() +.. autoclass:: StoryHandler() .. autoclass:: RawUpdateHandler() diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index b5459f9f97..32c257d4ca 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_. Set the environment variable ``PYROGRAM_REPLIT_NWTRAFIK_PORT`` value to ``5222`` if you want to connect to Production Telegram Servers, **OR** Set the environment variable ``PYROGRAM_REPLIT_WNTRAFIK_PORT`` value to ``5223`` if you want to connect to Test Telegram Servers, before starting the :obj:`~pyrogram.Client`. - Added the :meth:`~pyrogram.Client.invite_group_call_participants` (`#35 `_). - Added the types :obj:`~pyrogram.types.LabeledPrice`, :obj:`~pyrogram.types.OrderInfo`, :obj:`~pyrogram.types.PreCheckoutQuery`, :obj:`~pyrogram.types.ShippingAddress`, :obj:`~pyrogram.types.ShippingOption`, :obj:`~pyrogram.types.ShippingQuery` and :obj:`~pyrogram.types.SuccessfulPayment`. diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index 559ff41199..bd7fef8407 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -43,6 +43,7 @@ DeletedMessagesHandler, UserStatusHandler, + StoryHandler, RawUpdateHandler ) from pyrogram.raw.types import ( @@ -60,6 +61,7 @@ UpdateBotDeleteBusinessMessage, UpdateBotPrecheckoutQuery, UpdateBotShippingQuery, + UpdateStory, ) log = logging.getLogger(__name__) @@ -80,6 +82,7 @@ class Dispatcher: MESSAGE_BOT_A_REACTION_UPDATES = (UpdateBotMessageReactions,) PRE_CHECKOUT_QUERY_UPDATES = (UpdateBotPrecheckoutQuery,) SHIPPING_QUERY_UPDATES = (UpdateBotShippingQuery,) + NEW_STORY_UPDATES = (UpdateStory,) def __init__(self, client: "pyrogram.Client"): self.client = client @@ -189,6 +192,18 @@ async def pre_checkout_query_parser(update, users, chats): PreCheckoutQueryHandler ) + async def story_parser(update, users, chats): + return ( + await pyrogram.types.Story._parse( + self.client, + users, + chats, + None, None, + update + ), + StoryHandler + ) + self.update_parsers = { Dispatcher.NEW_MESSAGE_UPDATES: message_parser, Dispatcher.EDIT_MESSAGE_UPDATES: edited_message_parser, @@ -202,8 +217,9 @@ async def pre_checkout_query_parser(update, users, chats): Dispatcher.CHAT_JOIN_REQUEST_UPDATES: chat_join_request_parser, Dispatcher.MESSAGE_BOT_NA_REACTION_UPDATES: message_bot_na_reaction_parser, Dispatcher.MESSAGE_BOT_A_REACTION_UPDATES: message_bot_a_reaction_parser, - Dispatcher.PRE_CHECKOUT_QUERY_UPDATES: pre_checkout_query_parser, Dispatcher.SHIPPING_QUERY_UPDATES: shipping_query_parser, + Dispatcher.PRE_CHECKOUT_QUERY_UPDATES: pre_checkout_query_parser, + Dispatcher.NEW_STORY_UPDATES: story_parser, } self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple} diff --git a/pyrogram/handlers/__init__.py b/pyrogram/handlers/__init__.py index a86165483c..5ef7d3d6f8 100644 --- a/pyrogram/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -32,3 +32,4 @@ from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler from .pre_checkout_query_handler import PreCheckoutQueryHandler from .shipping_query_handler import ShippingQueryHandler +from .story_handler import StoryHandler diff --git a/pyrogram/handlers/story_handler.py b/pyrogram/handlers/story_handler.py new file mode 100644 index 0000000000..b6a07d1cd0 --- /dev/null +++ b/pyrogram/handlers/story_handler.py @@ -0,0 +1,49 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Callable + +from .handler import Handler + + +class StoryHandler(Handler): + """The Story handler class. Used to handle new stories. + 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_story` decorator. + + Parameters: + callback (``Callable``): + Pass a function that will be called when a new Stories arrives. It takes *(client, story)* + 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 stories 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 story handler. + + story (:obj:`~pyrogram.types.Story`): + The received story. + """ + + def __init__(self, callback: Callable, filters=None): + super().__init__(callback, filters) diff --git a/pyrogram/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py index f267543c82..fc90783ed9 100644 --- a/pyrogram/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -32,6 +32,7 @@ from .on_message_reaction_count_updated import OnMessageReactionCountUpdated from .on_pre_checkout_query import OnPreCheckoutQuery from .on_shipping_query import OnShippingQuery +from .on_story import OnStory class Decorators( @@ -53,6 +54,7 @@ class Decorators( OnDisconnect, OnUserStatus, + OnStory, OnRawUpdate, ): pass diff --git a/pyrogram/methods/decorators/on_pre_checkout_query.py b/pyrogram/methods/decorators/on_pre_checkout_query.py index 7d33abe502..0a28edb718 100644 --- a/pyrogram/methods/decorators/on_pre_checkout_query.py +++ b/pyrogram/methods/decorators/on_pre_checkout_query.py @@ -33,6 +33,8 @@ def on_pre_checkout_query( This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.handlers.PreCheckoutQueryHandler`. + .. include:: /_includes/usable-by/bots.rst + Parameters: filters (:obj:`~pyrogram.filters`, *optional*): Pass one or more filters to allow only a subset of callback queries to be passed diff --git a/pyrogram/methods/decorators/on_raw_update.py b/pyrogram/methods/decorators/on_raw_update.py index 1c50378ea4..644bc8a5b9 100644 --- a/pyrogram/methods/decorators/on_raw_update.py +++ b/pyrogram/methods/decorators/on_raw_update.py @@ -31,8 +31,6 @@ def on_raw_update( This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.handlers.RawUpdateHandler`. - .. include:: /_includes/usable-by/users-bots.rst - Parameters: group (``int``, *optional*): The group identifier, defaults to 0. diff --git a/pyrogram/methods/decorators/on_shipping_query.py b/pyrogram/methods/decorators/on_shipping_query.py index 7128a88b2d..e8962ef4ac 100644 --- a/pyrogram/methods/decorators/on_shipping_query.py +++ b/pyrogram/methods/decorators/on_shipping_query.py @@ -33,6 +33,8 @@ def on_shipping_query( This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.handlers.ShippingQueryHandler`. + .. include:: /_includes/usable-by/bots.rst + Parameters: filters (:obj:`~pyrogram.filters`, *optional*): Pass one or more filters to allow only a subset of callback queries to be passed diff --git a/pyrogram/methods/decorators/on_story.py b/pyrogram/methods/decorators/on_story.py new file mode 100644 index 0000000000..ea0407b9a0 --- /dev/null +++ b/pyrogram/methods/decorators/on_story.py @@ -0,0 +1,64 @@ +# 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, Optional, Union + +import pyrogram +from pyrogram.filters import Filter + + +class OnStory: + def on_story( + self: Union["OnStory", Filter, None] = None, + filters: Optional[Filter] = None, + group: int = 0, + ) -> Callable: + """Decorator for handling new stories. + + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.StoryHandler`. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + filters (:obj:`~pyrogram.filters`, *optional*): + Pass one or more filters to allow only a subset of stories 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.StoryHandler(func, filters), group) + elif isinstance(self, Filter) or self is None: + if not hasattr(func, "handlers"): + func.handlers = [] + + func.handlers.append( + ( + pyrogram.handlers.StoryHandler(func, self), + group if filters is None else filters + ) + ) + + return func + + return decorator diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index c001d7172e..07efce5880 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -291,7 +291,7 @@ async def _parse( dice = types.Dice._parse(client, media) media_type = enums.MessageMediaType.DICE elif isinstance(media, raw.types.MessageMediaStory): - story = await types.Story._parse(client, chats, media, None) + story = await types.Story._parse(client, users, chats, media, None) media_type = enums.MessageMediaType.STORY elif isinstance(media, raw.types.MessageMediaGiveaway): giveaway = types.Giveaway._parse(client, chats, media) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 8fa2deeb97..e9777bb96c 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1121,7 +1121,7 @@ async def _parse( dice = types.Dice._parse(client, media) media_type = enums.MessageMediaType.DICE elif isinstance(media, raw.types.MessageMediaStory): - story = await types.Story._parse(client, chats, media, None) + story = await types.Story._parse(client, users, chats, media, None) media_type = enums.MessageMediaType.STORY elif isinstance(media, raw.types.MessageMediaGiveaway): giveaway = types.Giveaway._parse(client, chats, media) @@ -1267,7 +1267,7 @@ async def _parse( ) if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): - parsed_message.reply_to_story = await types.Story._parse(client, chats, None, message.reply_to) + parsed_message.reply_to_story = await types.Story._parse(client, users, chats, None, message.reply_to) if replies: try: diff --git a/pyrogram/types/messages_and_media/story.py b/pyrogram/types/messages_and_media/story.py index 42daa3f740..5aa3171972 100644 --- a/pyrogram/types/messages_and_media/story.py +++ b/pyrogram/types/messages_and_media/story.py @@ -131,17 +131,88 @@ def __init__( self.deleted = deleted self._raw = _raw + @staticmethod + def _parse_story_item( + client, + story_item: "raw.types.StoryItem" + ): + date = None + expire_date = None + media = None + has_protected_content = None + photo = None + video = None + edited = None + pinned = None + caption = None + caption_entities = None + views = None + forwards = None + reactions = None + skipped = None + deleted = None + + if isinstance(story_item, raw.types.StoryItemDeleted): + deleted = True + elif isinstance(story_item, raw.types.StoryItemSkipped): + skipped = True + else: + date = utils.timestamp_to_datetime(story_item.date) + expire_date = utils.timestamp_to_datetime(story_item.expire_date) + if isinstance(story_item.media, raw.types.MessageMediaPhoto): + photo = types.Photo._parse(client, story_item.media.photo, story_item.media.ttl_seconds) + media = enums.MessageMediaType.PHOTO + elif isinstance(story_item.media, raw.types.MessageMediaDocument): + doc = story_item.media.document + attributes = {type(i): i for i in doc.attributes} + video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None) + video = types.Video._parse(client, doc, video_attributes, None) + media = enums.MessageMediaType.VIDEO + has_protected_content = story_item.noforwards + edited = story_item.edited + pinned = story_item.pinned + entities = [e for e in (types.MessageEntity._parse(client, entity, {}) for entity in story_item.entities) if e] + caption = Str(story_item.caption or "").init(entities) or None + caption_entities = entities or None + if story_item.views: + views = getattr(story_item.views, "views_count", None) + forwards = getattr(story_item.views, "forwards_count", None) + reactions = [ + types.Reaction._parse_count(client, reaction) + for reaction in getattr(story_item.views, "reactions", []) + ] or None + return ( + date, + expire_date, + media, + has_protected_content, + photo, + video, + edited, + pinned, + caption, + caption_entities, + views, + forwards, + reactions, + skipped, + deleted + ) @staticmethod async def _parse( client, + users: dict, chats: dict, story_media: "raw.types.MessageMediaStory", - reply_story: "raw.types.MessageReplyStoryHeader" + reply_story: "raw.types.MessageReplyStoryHeader", + story_update: "raw.types.UpdateStory" ) -> "Story": story_id = None chat = None + rawupdate = None + date = None expire_date = None media = None @@ -159,16 +230,27 @@ async def _parse( deleted = None if story_media: + rawupdate = story_media + if story_media.peer: - raw_peer_id = utils.get_peer_id(story_media.peer) - chat = await client.get_chat(raw_peer_id, False) + raw_peer_id = utils.get_raw_peer_id(story_media.peer) + if isinstance(story_media.peer, raw.types.PeerUser): + chat = types.Chat._parse_chat(client, users.get(raw_peer_id)) + else: + chat = types.Chat._parse_chat(client, chats.get(raw_peer_id)) story_id = getattr(story_media, "id", None) + if reply_story: + rawupdate = reply_story + if reply_story.peer: raw_peer_id = utils.get_raw_peer_id(reply_story.peer) - - chat = types.Chat._parse_chat(client, chats.get(raw_peer_id)) + if isinstance(reply_story.peer, raw.types.PeerUser): + chat = types.Chat._parse_chat(client, users.get(raw_peer_id)) + else: + chat = types.Chat._parse_chat(client, chats.get(raw_peer_id)) story_id = getattr(reply_story, "story_id", None) + if story_id and not client.me.is_bot: try: story_item = ( @@ -182,38 +264,55 @@ async def _parse( except (RPCError, IndexError): pass else: - if isinstance(story_item, raw.types.StoryItemDeleted): - deleted = True - elif isinstance(story_item, raw.types.StoryItemSkipped): - skipped = True - else: - date = utils.timestamp_to_datetime(story_item.date) - expire_date = utils.timestamp_to_datetime(story_item.expire_date) - if isinstance(story_item.media, raw.types.MessageMediaPhoto): - photo = types.Photo._parse(client, story_item.media.photo, story_item.media.ttl_seconds) - media = enums.MessageMediaType.PHOTO - elif isinstance(story_item.media, raw.types.MessageMediaDocument): - doc = story_item.media.document - attributes = {type(i): i for i in doc.attributes} - video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None) - video = types.Video._parse(client, doc, video_attributes, None) - media = enums.MessageMediaType.VIDEO - has_protected_content = story_item.noforwards - edited = story_item.edited - pinned = story_item.pinned - entities = [e for e in (types.MessageEntity._parse(client, entity, {}) for entity in story_item.entities) if e] - caption = Str(story_item.caption or "").init(entities) or None - caption_entities = entities or None - if story_item.views: - views = getattr(story_item.views, "views_count", None) - forwards = getattr(story_item.views, "forwards_count", None) - reactions = [ - types.Reaction._parse_count(client, reaction) - for reaction in getattr(story_item.views, "reactions", []) - ] or None + ( + date, + expire_date, + media, + has_protected_content, + photo, + video, + edited, + pinned, + caption, + caption_entities, + views, + forwards, + reactions, + skipped, + deleted + ) = Story._parse_story_item(client, story_item) + + if story_update: + rawupdate = story_update + + raw_peer_id = utils.get_raw_peer_id(story_update.peer) + if isinstance(story_update.peer, raw.types.PeerUser): + chat = types.Chat._parse_chat(client, users.get(raw_peer_id)) + else: + chat = types.Chat._parse_chat(client, chats.get(raw_peer_id)) + + story_id = getattr(story_update.story, "id", None) + ( + date, + expire_date, + media, + has_protected_content, + photo, + video, + edited, + pinned, + caption, + caption_entities, + views, + forwards, + reactions, + skipped, + deleted + ) = Story._parse_story_item(client, story_update.story) + return Story( client=client, - _raw=story_media, + _raw=rawupdate, id=story_id, chat=chat, date=date, From f6e3e92c7d3ba4da2a926c59af002303eba02f42 Mon Sep 17 00:00:00 2001 From: Zaid _ <162994967+zaid5o5@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:59:39 +0300 Subject: [PATCH 088/154] add three more methods for phone calls. (#37) * temporary workaround https://t.me/c/1220993104/1379063 --- compiler/docs/compiler.py | 5 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/phone/__init__.py | 6 ++ pyrogram/methods/phone/create_video_chat.py | 96 +++++++++++++++++++ pyrogram/methods/phone/discard_group_call.py | 85 ++++++++++++++++ .../methods/phone/get_video_chat_rtmp_url.py | 63 ++++++++++++ .../phone/invite_group_call_participants.py | 2 +- pyrogram/types/user_and_chats/__init__.py | 2 + pyrogram/types/user_and_chats/rtmp_url.py | 46 +++++++++ 9 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/phone/create_video_chat.py create mode 100644 pyrogram/methods/phone/discard_group_call.py create mode 100644 pyrogram/methods/phone/get_video_chat_rtmp_url.py create mode 100644 pyrogram/types/user_and_chats/rtmp_url.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 5adb8c7704..6b64f5b104 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -345,8 +345,12 @@ def get_title_list(s: str) -> list: """, phone=""" Phone + create_video_chat + discard_group_call + get_video_chat_rtmp_url invite_group_call_participants load_group_call_participants + """, stickers=""" Stickers @@ -608,6 +612,7 @@ def get_title_list(s: str) -> list: VideoChatParticipantsInvited VideoChatScheduled VideoChatStarted + RtmpUrl """, ) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 32c257d4ca..2e4804bc80 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_). - Added :meth:`~Client.on_story` to listen to story updates. - Ability to run in `replit` environment without creating `a deployment `_. Set the environment variable ``PYROGRAM_REPLIT_NWTRAFIK_PORT`` value to ``5222`` if you want to connect to Production Telegram Servers, **OR** Set the environment variable ``PYROGRAM_REPLIT_WNTRAFIK_PORT`` value to ``5223`` if you want to connect to Test Telegram Servers, before starting the :obj:`~pyrogram.Client`. - Added the :meth:`~pyrogram.Client.invite_group_call_participants` (`#35 `_). diff --git a/pyrogram/methods/phone/__init__.py b/pyrogram/methods/phone/__init__.py index 955b660307..622c8f526f 100644 --- a/pyrogram/methods/phone/__init__.py +++ b/pyrogram/methods/phone/__init__.py @@ -19,10 +19,16 @@ from .load_group_call_participants import LoadGroupCallParticipants from .invite_group_call_participants import InviteGroupCallParticipants +from .create_video_chat import CreateVideoChat +from .discard_group_call import DiscardGroupCall +from .get_video_chat_rtmp_url import GetVideoChatRtmpUrl class Phone( InviteGroupCallParticipants, LoadGroupCallParticipants, + CreateVideoChat, + DiscardGroupCall, + GetVideoChatRtmpUrl, ): pass diff --git a/pyrogram/methods/phone/create_video_chat.py b/pyrogram/methods/phone/create_video_chat.py new file mode 100644 index 0000000000..2477dbfe3e --- /dev/null +++ b/pyrogram/methods/phone/create_video_chat.py @@ -0,0 +1,96 @@ +# 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 Union + +from datetime import datetime + +import pyrogram +from pyrogram import types, raw, utils + + +class CreateVideoChat: + async def create_video_chat( + self: "pyrogram.Client", + chat_id: Union[int, str], + title: str = None, + start_date: datetime = utils.zero_datetime(), + is_rtmp_stream: bool = None + ) -> "types.Message": + """Creates a video chat (a group call bound to a chat). + + Available only for basic groups, supergroups and channels; requires can_manage_video_chats administrator right. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat in which the video chat will be created. A chat can be either a basic group, supergroup or a channel. + + title (``str``, *optional*): + Group call title; if empty, chat title will be used. + + start_date (:py:obj:`~datetime.datetime`, *optional*): + Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 to start the video chat immediately. The date must be at least 10 seconds and at most 8 days in the future. + + is_rtmp_stream (``bool``, *optional*): + Pass true to create an RTMP stream instead of an ordinary video chat; requires owner privileges. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent service message is returned. + + Example: + .. code-block:: python + + await app.create_video_chat(chat_id) + + """ + peer = await self.resolve_peer(chat_id) + + if not isinstance(peer, (raw.types.InputPeerChat, raw.types.InputPeerChannel)): + raise ValueError( + "Target chat should be group, supergroup or channel." + ) + + r = await self.invoke( + raw.functions.phone.CreateGroupCall( + rtmp_stream=is_rtmp_stream, + peer=peer, + # TODO: temp. workaround + random_id=self.rnd_id() >> 32, + title=title, + schedule_date=utils.datetime_to_timestamp(start_date), + ) + ) + + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewMessage, + raw.types.UpdateNewScheduledMessage, + ), + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + ) diff --git a/pyrogram/methods/phone/discard_group_call.py b/pyrogram/methods/phone/discard_group_call.py new file mode 100644 index 0000000000..fb911a7e99 --- /dev/null +++ b/pyrogram/methods/phone/discard_group_call.py @@ -0,0 +1,85 @@ +# 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 Union + +import pyrogram +from pyrogram import types, raw + + +class DiscardGroupCall: + async def discard_group_call( + # TODO + self: "pyrogram.Client", + chat_id: Union[int, str], + ) -> "types.Message": + """Terminate a group/channel call or livestream + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. A chat can be either a basic group, supergroup or a channel. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent service message is returned. + + Example: + .. code-block:: python + + await app.discard_group_call(chat_id) + + """ + peer = await self.resolve_peer(chat_id) + + if isinstance(peer, raw.types.InputPeerChannel): + r = await self.invoke(raw.functions.channels.GetFullChannel(channel=peer)) + elif isinstance(peer, raw.types.InputPeerChat): + r = await self.invoke( + raw.functions.messages.GetFullChat(chat_id=peer.chat_id) + ) + else: + raise ValueError("Target chat should be group, supergroup or channel.") + + call = r.full_chat.call + + if call is None: + raise ValueError("No active group call at this chat.") + + r = await self.invoke( + raw.functions.phone.DiscardGroupCall( + call=call + ) + ) + + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewMessage, + raw.types.UpdateNewScheduledMessage, + ), + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + ) diff --git a/pyrogram/methods/phone/get_video_chat_rtmp_url.py b/pyrogram/methods/phone/get_video_chat_rtmp_url.py new file mode 100644 index 0000000000..bbf14f752f --- /dev/null +++ b/pyrogram/methods/phone/get_video_chat_rtmp_url.py @@ -0,0 +1,63 @@ +# 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 Union + +import pyrogram +from pyrogram import types, raw + + +class GetVideoChatRtmpUrl: + async def get_video_chat_rtmp_url( + self: "pyrogram.Client", + chat_id: Union[int, str], + replace: bool = False + ) -> "types.RtmpUrl": + """Returns RTMP URL for streaming to the chat; requires owner privileges. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. A chat can be either a basic group, supergroup or a channel. + + replace (``bool``, *optional*): + Whether to replace the previous stream key or simply return the existing one. Defaults to False, i.e., return the existing one. + + Returns: + :obj:`~pyrogram.types.RtmpUrl`: On success, the RTMP URL and stream key is returned. + + Example: + .. code-block:: python + + await app.get_stream_rtmp_url(chat_id) + + """ + peer = await self.resolve_peer(chat_id) + + if not isinstance(peer, (raw.types.InputPeerChat, raw.types.InputPeerChannel)): + raise ValueError("Target chat should be group, supergroup or channel.") + + r = await self.invoke( + raw.functions.phone.GetGroupCallStreamRtmpUrl( + peer=peer, + revoke=replace + ) + ) + + return types.RtmpUrl._parse(r) diff --git a/pyrogram/methods/phone/invite_group_call_participants.py b/pyrogram/methods/phone/invite_group_call_participants.py index affe7f1550..3b6db763fd 100644 --- a/pyrogram/methods/phone/invite_group_call_participants.py +++ b/pyrogram/methods/phone/invite_group_call_participants.py @@ -19,7 +19,7 @@ from typing import Union, List import pyrogram -from pyrogram import types, raw, utils +from pyrogram import types, raw class InviteGroupCallParticipants: diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py index 403aa0aceb..83c215e26a 100644 --- a/pyrogram/types/user_and_chats/__init__.py +++ b/pyrogram/types/user_and_chats/__init__.py @@ -44,6 +44,7 @@ from .video_chat_participants_invited import VideoChatParticipantsInvited from .video_chat_scheduled import VideoChatScheduled from .video_chat_started import VideoChatStarted +from .rtmp_url import RtmpUrl __all__ = [ "Birthdate", @@ -74,4 +75,5 @@ "VideoChatParticipantsInvited", "VideoChatScheduled", "VideoChatStarted", + "RtmpUrl", ] diff --git a/pyrogram/types/user_and_chats/rtmp_url.py b/pyrogram/types/user_and_chats/rtmp_url.py new file mode 100644 index 0000000000..a8ca06b4e5 --- /dev/null +++ b/pyrogram/types/user_and_chats/rtmp_url.py @@ -0,0 +1,46 @@ +# 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 pyrogram import raw +from ..object import Object + + +class RtmpUrl(Object): + """Represents an RTMP URL and stream key to be used in streaming software. + + Parameters: + url (``str``): + The URL. + + stream_key (``str``): + Stream key. + + """ + + def __init__(self, *, url: str, stream_key: str): + super().__init__(None) + + self.url = url + self.stream_key = stream_key + + @staticmethod + def _parse(rtmp_url: "raw.types.GroupCallStreamRtmpUrl") -> "RtmpUrl": + return RtmpUrl( + url=rtmp_url.url, + stream_key=rtmp_url.key + ) From 1078d07a4ab6550da4865b40d40c3712d9fe4679 Mon Sep 17 00:00:00 2001 From: Zaid _ <162994967+zaid5o5@users.noreply.github.com> Date: Sun, 9 Jun 2024 21:46:09 +0300 Subject: [PATCH 089/154] Add translate (#39) --- compiler/docs/compiler.py | 3 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/__init__.py | 3 +- pyrogram/methods/messages/translate_text.py | 139 ++++++++++++++++++ pyrogram/types/messages_and_media/__init__.py | 2 + pyrogram/types/messages_and_media/message.py | 39 +++++ .../messages_and_media/translated_text.py | 61 ++++++++ 7 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/messages/translate_text.py create mode 100644 pyrogram/types/messages_and_media/translated_text.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 6b64f5b104..22a6ad39bc 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -336,6 +336,8 @@ def get_title_list(s: str) -> list: view_messages vote_poll get_chat_sponsored_messages + translate_text + translate_message_text """, password=""" Password @@ -552,6 +554,7 @@ def get_title_list(s: str) -> list: ReactionTypeEmoji ReactionTypeCustomEmoji Thumbnail + TranslatedText StrippedThumbnail Poll PollOption diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 2e4804bc80..70a606cd9b 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_). - Added the methods :meth:`~pyrogram.Client.create_video_chat`, :meth:`~pyrogram.Client.discard_group_call`, :meth:`~pyrogram.Client.get_video_chat_rtmp_url` and the type :obj:`~pyrogram.types.RtmpUrl` (`#37 `_). - Added :meth:`~Client.on_story` to listen to story updates. - Ability to run in `replit` environment without creating `a deployment `_. Set the environment variable ``PYROGRAM_REPLIT_NWTRAFIK_PORT`` value to ``5222`` if you want to connect to Production Telegram Servers, **OR** Set the environment variable ``PYROGRAM_REPLIT_WNTRAFIK_PORT`` value to ``5223`` if you want to connect to Test Telegram Servers, before starting the :obj:`~pyrogram.Client`. diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index 5a006f23e4..588cf2ffb8 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -69,7 +69,7 @@ from .get_chat_sponsored_messages import GetChatSponsoredMessages from .search_public_hashtag_messages import SearchPublicHashtagMessages from .search_public_hashtag_messages_count import SearchPublicHashtagMessagesCount - +from .translate_text import TranslateText class Messages( CopyMediaGroup, @@ -125,5 +125,6 @@ class Messages( ViewMessages, VotePoll, GetChatSponsoredMessages, + TranslateText, ): pass diff --git a/pyrogram/methods/messages/translate_text.py b/pyrogram/methods/messages/translate_text.py new file mode 100644 index 0000000000..fa1b367488 --- /dev/null +++ b/pyrogram/methods/messages/translate_text.py @@ -0,0 +1,139 @@ +# 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 List, Optional, Union + +import pyrogram +from pyrogram import enums, raw, types, utils + + +class TranslateText: + async def translate_message_text( + self: "pyrogram.Client", + to_language_code: str, + chat_id: Union[int, str], + message_ids: Union[int, List[int]] + ) -> Union["types.TranslatedText", List["types.TranslatedText"]]: + """Extracts text or caption of the given message and translates it to the given language. If the current user is a Telegram Premium user, then text formatting is preserved. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + to_language_code (``str``): + Language code of the language to which the message is translated. + Must be one of "af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg", "ca", "ceb", "zh-CN", "zh", "zh-Hans", "zh-TW", "zh-Hant", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fi", "fr", "fy", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "iw", "hi", "hmn", "hu", "is", "ig", "id", "in", "ga", "it", "ja", "jv", "kn", "kk", "km", "rw", "ko", "ku", "ky", "lo", "la", "lv", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "ny", "or", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm", "gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "tr", "tk", "uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "ji", "yo", "zu". + + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + message_ids (``int`` | List of ``int``): + Identifier or list of message identifiers of the target message. + + Returns: + :obj:`~pyrogram.types.TranslatedText` | List of :obj:`~pyrogram.types.TranslatedText`: In case *message_ids* was not + a list, a single result is returned, otherwise a list of results is returned. + + Example: + .. code-block:: python + + await app.translate_message_text("en", chat_id, message_id) + """ + ids = [message_ids] if not isinstance(message_ids, list) else message_ids + + r = await self.invoke( + raw.functions.messages.TranslateText( + to_lang=to_language_code, + peer=await self.resolve_peer(chat_id), + id=ids + ) + ) + + return ( + types.TranslatedText._parse(self, r.result[0]) + if len(r.result) == 1 + else [ + types.TranslatedText._parse(self, i) + for i in r.result + ] + ) + + + async def translate_text( + self: "pyrogram.Client", + to_language_code: str, + text: str, + parse_mode: Optional["enums.ParseMode"] = None, + entities: List["types.MessageEntity"] = None + ) -> Union["types.TranslatedText", List["types.TranslatedText"]]: + """Translates a text to the given language. If the current user is a Telegram Premium user, then text formatting is preserved. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + to_language_code (``str``): + Language code of the language to which the message is translated. + Must be one of "af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg", "ca", "ceb", "zh-CN", "zh", "zh-Hans", "zh-TW", "zh-Hant", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fi", "fr", "fy", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "iw", "hi", "hmn", "hu", "is", "ig", "id", "in", "ga", "it", "ja", "jv", "kn", "kk", "km", "rw", "ko", "ku", "ky", "lo", "la", "lv", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "ny", "or", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm", "gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "tr", "tk", "uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "ji", "yo", "zu". + + text (``str``): + Text to translate. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in message text, which can be specified instead of *parse_mode*. + + Returns: + :obj:`~pyrogram.types.TranslatedText` | List of :obj:`~pyrogram.types.TranslatedText`: In case *message_ids* was not + a list, a single result is returned, otherwise a list of results is returned. + + Example: + .. code-block:: python + + await app.translate_text("fa", "Pyrogram") + """ + message, entities = ( + await utils.parse_text_entities( + self, + text, + parse_mode, + entities + ) + ).values() + + r = await self.invoke( + raw.functions.messages.TranslateText( + to_lang=to_language_code, + text=[ + raw.types.TextWithEntities( + text=message, + entities=entities or [] + ) + ] + ) + ) + + return ( + types.TranslatedText._parse(self, r.result[0]) + if len(r.result) == 1 + else [ + types.TranslatedText._parse(self, i) + for i in r.result + ] + ) diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index 969d7c0ad8..c1851cd41c 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -56,6 +56,7 @@ from .gift_code import GiftCode from .gifted_premium import GiftedPremium from .message_effect import MessageEffect +from .translated_text import TranslatedText __all__ = [ "Animation", @@ -96,4 +97,5 @@ "Voice", "WebAppData", "WebPage", + "TranslatedText" ] diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index e9777bb96c..b9fb70bd6f 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -5118,3 +5118,42 @@ async def view(self, force_read: bool = True) -> bool: message_ids=self.id, force_read=force_read ) + + async def translate( + self, + to_language_code: str + ) -> "types.TranslatedText": + """Bound method *translate* of :obj:`~pyrogram.types.Message`. + + Use as a shortcut for: + + .. code-block:: python + + await client.translate_message_text( + chat_id=message.chat.id, + message_ids=message_id, + to_language_code="en" + ) + + Example: + .. code-block:: python + + await message.translate("en") + + Parameters: + to_language_code (``str``): + Language code of the language to which the message is translated. + Must be one of "af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg", "ca", "ceb", "zh-CN", "zh", "zh-Hans", "zh-TW", "zh-Hant", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fi", "fr", "fy", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "iw", "hi", "hmn", "hu", "is", "ig", "id", "in", "ga", "it", "ja", "jv", "kn", "kk", "km", "rw", "ko", "ku", "ky", "lo", "la", "lv", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "ny", "or", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm", "gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "tr", "tk", "uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "ji", "yo", "zu". + + Returns: + :obj:`~pyrogram.types.TranslatedText`: The translated result is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + + """ + return await self._client.translate_message_text( + chat_id=self.chat.id, + message_ids=self.id, + to_language_code=to_language_code + ) diff --git a/pyrogram/types/messages_and_media/translated_text.py b/pyrogram/types/messages_and_media/translated_text.py new file mode 100644 index 0000000000..f171b4f826 --- /dev/null +++ b/pyrogram/types/messages_and_media/translated_text.py @@ -0,0 +1,61 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import List + +import pyrogram +from pyrogram import raw, types + +from ..object import Object +from .message import Str + + +class TranslatedText(Object): + """A translated text with entities. + + Parameters: + text (``str``): + Translated text. + + entities (``str``, *optional*): + Entities of the text. + """ + + def __init__( + self, + *, + text: str, + entities: List["types.MessageEntity"] = None + ): + self.text = text + self.entities = entities + + @staticmethod + def _parse( + client, + translate_result: "raw.types.TextWithEntities" + ) -> "TranslatedText": + entities = [ + types.MessageEntity._parse(client, entity, {}) + for entity in translate_result.entities + ] + entities = types.List(filter(lambda x: x is not None, entities)) + + return TranslatedText( + text=Str(translate_result.text).init(entities) or None, entities=entities or None + ) From e0985a53c18b3ae6cce33bdece1c63d49b4d5c79 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 9 Jun 2024 20:47:56 +0200 Subject: [PATCH 090/154] Update Pyrogram to v2.1.32.7 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 245d25df6b..f4b42de9e2 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.6" +__version__ = "2.1.32.7" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From b19aaa0b7dad94f70e893f854030af891aac1318 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Mon, 10 Jun 2024 00:39:14 +0530 Subject: [PATCH 091/154] Fix typos. --- compiler/docs/compiler.py | 1 + pyrogram/types/messages_and_media/translated_text.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 22a6ad39bc..59a1e19fb7 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -686,6 +686,7 @@ def get_title_list(s: str) -> list: Message.react Message.read Message.view + Message.translate """, chat=""" Chat diff --git a/pyrogram/types/messages_and_media/translated_text.py b/pyrogram/types/messages_and_media/translated_text.py index f171b4f826..e6e3f6bd80 100644 --- a/pyrogram/types/messages_and_media/translated_text.py +++ b/pyrogram/types/messages_and_media/translated_text.py @@ -32,7 +32,7 @@ class TranslatedText(Object): text (``str``): Translated text. - entities (``str``, *optional*): + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): Entities of the text. """ From 38b99b69fd11cdc6ce5507f5f74d183ef5e2698a Mon Sep 17 00:00:00 2001 From: Zaid _ <162994967+zaid5o5@users.noreply.github.com> Date: Mon, 10 Jun 2024 19:01:13 +0300 Subject: [PATCH 092/154] Add ChatBackground type (#40) --- compiler/docs/compiler.py | 1 + pyrogram/types/user_and_chats/__init__.py | 2 + pyrogram/types/user_and_chats/chat.py | 11 ++ .../types/user_and_chats/chat_background.py | 113 ++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 pyrogram/types/user_and_chats/chat_background.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 59a1e19fb7..6793352622 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -616,6 +616,7 @@ def get_title_list(s: str) -> list: VideoChatScheduled VideoChatStarted RtmpUrl + ChatBackground """, ) diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py index 83c215e26a..a20c2d1866 100644 --- a/pyrogram/types/user_and_chats/__init__.py +++ b/pyrogram/types/user_and_chats/__init__.py @@ -45,6 +45,7 @@ from .video_chat_scheduled import VideoChatScheduled from .video_chat_started import VideoChatStarted from .rtmp_url import RtmpUrl +from .chat_background import ChatBackground __all__ = [ "Birthdate", @@ -76,4 +77,5 @@ "VideoChatScheduled", "VideoChatStarted", "RtmpUrl", + "ChatBackground" ] diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 4f60a38615..9a1c1045ea 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -92,6 +92,9 @@ class Chat(Object): emoji_status (:obj:`~pyrogram.types.EmojiStatus`, *optional*): Emoji status. + background (:obj:`~pyrogram.types.ChatBackground`, *optional*): + A chat background. + bio (``str``, *optional*): Bio of the other party in a private chat. Returned only in :meth:`~pyrogram.Client.get_chat`. @@ -254,6 +257,7 @@ def __init__( accent_color: "types.ChatColor" = None, profile_color: "types.ChatColor" = None, emoji_status: "types.EmojiStatus" = None, + background: "types.ChatBackground" = None, has_visible_history: bool = None, has_hidden_members: bool = None, has_aggressive_anti_spam_enabled: bool = None, @@ -308,6 +312,7 @@ def __init__( self.accent_color = accent_color self.profile_color = profile_color self.emoji_status = emoji_status + self.background = background self.has_visible_history = has_visible_history self.has_hidden_members = has_hidden_members self.has_aggressive_anti_spam_enabled = has_aggressive_anti_spam_enabled @@ -326,6 +331,7 @@ def __init__( self.business_location = business_location self.business_opening_hours = business_opening_hours self.active_usernames = active_usernames + self.max_reaction_count = max_reaction_count self._raw = _raw @staticmethod @@ -544,6 +550,8 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. full_user.business_work_hours ) + if getattr(full_user, "wallpaper", None): + parsed_chat.background = types.ChatBackground._parse(client, full_user.wallpaper) else: full_chat = chat_full.full_chat chat_raw = chats[full_chat.id] @@ -616,6 +624,9 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. ) parsed_chat.max_reaction_count = getattr(full_chat, "reactions_limit", 11) + if getattr(full_chat, "wallpaper", None): + parsed_chat.background = types.ChatBackground._parse(client, full_chat.wallpaper) + parsed_chat.personal_chat = personal_chat parsed_chat.personal_chat_message = personal_chat_message parsed_chat._raw = chat_full diff --git a/pyrogram/types/user_and_chats/chat_background.py b/pyrogram/types/user_and_chats/chat_background.py new file mode 100644 index 0000000000..a4b2d2ab54 --- /dev/null +++ b/pyrogram/types/user_and_chats/chat_background.py @@ -0,0 +1,113 @@ +# 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 datetime import datetime +from typing import List + +import pyrogram +from pyrogram import raw, utils +from pyrogram import types +from pyrogram.file_id import ( + FileId, + FileType, + FileUniqueId, + FileUniqueType, + ThumbnailSource, +) +from ..object import Object + + +class ChatBackground(Object): + """Describes a background set for a specific chat. + + Parameters: + file_id (``str``): + Identifier for this file, which can be used to download the file. + + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. + + file_size (``int``): + File size. + + date (:py:obj:`~datetime.datetime`): + Date the background was setted. + + slug (``str``): + Identifier of the background code. + You can combine it with `https://t.me/bg/{slug}` + to get link for this background. + + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): + Available thumbnails of this background. + + link (``str``, *property*): + Generate a link to this background code. + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + file_id: str, + file_unique_id: str, + file_size: int, + date: datetime, + slug: str, + thumbs: List["types.Thumbnail"] = None, + ): + super().__init__(client) + + self.file_id = file_id + self.file_unique_id = file_unique_id + self.file_size = file_size + self.date = date + self.slug = slug + self.thumbs = thumbs + + @property + def link(self) -> str: + return f"https://t.me/bg/{self.slug}" + + @staticmethod + def _parse( + client, + wallpaper: "raw.types.Wallpaper", + ) -> "ChatBackground": + return ChatBackground( + file_id=FileId( + dc_id=wallpaper.document.dc_id, + file_reference=wallpaper.document.file_reference, + access_hash=wallpaper.document.access_hash, + file_type=FileType.BACKGROUND, + media_id=wallpaper.document.id, + volume_id=0, + local_id=0, + thumbnail_source=ThumbnailSource.THUMBNAIL, + thumbnail_file_type=FileType.BACKGROUND, + ).encode(), + file_unique_id=FileUniqueId( + file_unique_type=FileUniqueType.DOCUMENT, media_id=wallpaper.document.id + ).encode(), + file_size=wallpaper.document.size, + slug=wallpaper.slug, + date=utils.timestamp_to_datetime(wallpaper.document.date), + thumbs=types.Thumbnail._parse(client, wallpaper.document), + client=client, + ) From 1dd4fa01ab7abb5d8347b59c1c4b749d59092277 Mon Sep 17 00:00:00 2001 From: Zaid _ <162994967+zaid5o5@users.noreply.github.com> Date: Mon, 10 Jun 2024 18:52:14 +0200 Subject: [PATCH 093/154] Fix condition in parsing Story --- pyrogram/types/input_message_content/external_reply_info.py | 2 +- pyrogram/types/messages_and_media/message.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index 07efce5880..5074a1ca49 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -291,7 +291,7 @@ async def _parse( dice = types.Dice._parse(client, media) media_type = enums.MessageMediaType.DICE elif isinstance(media, raw.types.MessageMediaStory): - story = await types.Story._parse(client, users, chats, media, None) + story = await types.Story._parse(client, users, chats, media, None, None) media_type = enums.MessageMediaType.STORY elif isinstance(media, raw.types.MessageMediaGiveaway): giveaway = types.Giveaway._parse(client, chats, media) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index b9fb70bd6f..f92c04d002 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1121,7 +1121,7 @@ async def _parse( dice = types.Dice._parse(client, media) media_type = enums.MessageMediaType.DICE elif isinstance(media, raw.types.MessageMediaStory): - story = await types.Story._parse(client, users, chats, media, None) + story = await types.Story._parse(client, users, chats, media, None, None) media_type = enums.MessageMediaType.STORY elif isinstance(media, raw.types.MessageMediaGiveaway): giveaway = types.Giveaway._parse(client, chats, media) @@ -1267,7 +1267,7 @@ async def _parse( ) if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): - parsed_message.reply_to_story = await types.Story._parse(client, users, chats, None, message.reply_to) + parsed_message.reply_to_story = await types.Story._parse(client, users, chats, None, message.reply_to, None) if replies: try: From e4f3e7a70d3f32360acf41ee5184b359baaa113a Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Tue, 11 Jun 2024 13:37:10 +0300 Subject: [PATCH 094/154] Add index on usernames.id Closes: KurimuzonAkuma/pyrogram#70 Fixes: merge-conflict with https://github.com/pyrogram/pyrogram/commit/c434828 --- pyrogram/storage/file_storage.py | 8 ++++++- pyrogram/storage/sqlite_storage.py | 37 +++++++++++++++++------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/pyrogram/storage/file_storage.py b/pyrogram/storage/file_storage.py index 837f857c4b..e263b7eb0d 100644 --- a/pyrogram/storage/file_storage.py +++ b/pyrogram/storage/file_storage.py @@ -38,7 +38,7 @@ FOREIGN KEY (id) REFERENCES peers(id) ); -CREATE INDEX idx_usernames_username ON usernames (username); +CREATE INDEX IF NOT EXISTS idx_usernames_username ON usernames (username); """ UPDATE_STATE_SCHEMA = """ @@ -99,6 +99,12 @@ async def update(self): version += 1 + if version == 5: + with self.conn: + self.conn.executescript("CREATE INDEX IF NOT EXISTS idx_usernames_id ON usernames (id);") + + version += 1 + await self.version(version) async def open(self): diff --git a/pyrogram/storage/sqlite_storage.py b/pyrogram/storage/sqlite_storage.py index f62bb0431d..f9abb800f7 100644 --- a/pyrogram/storage/sqlite_storage.py +++ b/pyrogram/storage/sqlite_storage.py @@ -75,9 +75,10 @@ number INTEGER PRIMARY KEY ); -CREATE INDEX idx_peers_id ON peers (id); -CREATE INDEX idx_peers_phone_number ON peers (phone_number); -CREATE INDEX idx_usernames_username ON usernames (username); +CREATE INDEX IF NOT EXISTS idx_peers_id ON peers (id); +CREATE INDEX IF NOT EXISTS idx_peers_phone_number ON peers (phone_number); +CREATE INDEX IF NOT EXISTS idx_usernames_id ON usernames (id); +CREATE INDEX IF NOT EXISTS idx_usernames_username ON usernames (username); CREATE TRIGGER trg_peers_last_update_on AFTER UPDATE @@ -112,7 +113,7 @@ def get_input_peer(peer_id: int, access_hash: int, peer_type: str): class SQLiteStorage(Storage): - VERSION = 5 + VERSION = 6 USERNAME_TTL = 8 * 60 * 60 def __init__(self, name: str): @@ -158,23 +159,27 @@ def _update_peers_impl(self, peers): peers_data = [] usernames_data = [] ids_to_delete = [] - for peer_data in peers: - id, access_hash, type, usernames, phone_number = peer_data + for id, access_hash, type, usernames, phone_number in peers: + ids_to_delete.append((id,)) + peers_data.append((id, access_hash, type, phone_number)) - self.conn.execute( - "REPLACE INTO peers (id, access_hash, type, phone_number)" - "VALUES (?, ?, ?, ?)", - (id, access_hash, type, phone_number) - ) + if usernames: + usernames_data.extend([(id, username) for username in usernames]) - self.conn.execute( - "DELETE FROM usernames WHERE id = ?", - (id,) - ) + self.conn.executemany( + "REPLACE INTO peers (id, access_hash, type, phone_number) VALUES (?, ?, ?, ?)", + peers_data + ) + + self.conn.executemany( + "DELETE FROM usernames WHERE id = ?", + ids_to_delete + ) + if usernames_data: self.conn.executemany( "REPLACE INTO usernames (id, username) VALUES (?, ?)", - [(id, username) for username in usernames] if usernames else [(id, None)] + usernames_data ) async def update_peers(self, peers: List[Tuple[int, int, str, List[str], str]]): From c5e9aaabbc0e0b4102673ac50ba2a7ee6046ccfb Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Thu, 13 Jun 2024 19:41:36 +0530 Subject: [PATCH 095/154] Improve documentation of some methods delete_forum_topic download_media send_document send_media_group send_video --- pyrogram/methods/chat_topics/delete_forum_topic.py | 3 ++- pyrogram/methods/messages/download_media.py | 4 +++- pyrogram/methods/messages/send_document.py | 2 +- pyrogram/methods/messages/send_media_group.py | 3 +-- pyrogram/methods/messages/send_video.py | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pyrogram/methods/chat_topics/delete_forum_topic.py b/pyrogram/methods/chat_topics/delete_forum_topic.py index df34c969b8..10e06dc24a 100644 --- a/pyrogram/methods/chat_topics/delete_forum_topic.py +++ b/pyrogram/methods/chat_topics/delete_forum_topic.py @@ -30,7 +30,8 @@ async def delete_forum_topic( message_thread_id: int ) -> int: """Use this method to delete a forum topic along with all its messages in a forum supergroup chat. - The bot must be an administrator in the chat for this to work and must have the can_delete_messages administrator rights. + The bot must be an administrator in the chat for this to work and must have the can_delete_messages administrator rights + unless the user is creator of the topic, the topic has no messages from other users and has at most 11 messages. .. include:: /_includes/usable-by/users-bots.rst diff --git a/pyrogram/methods/messages/download_media.py b/pyrogram/methods/messages/download_media.py index 225beccb46..b1bdea7e9e 100644 --- a/pyrogram/methods/messages/download_media.py +++ b/pyrogram/methods/messages/download_media.py @@ -155,7 +155,9 @@ async def progress(current, total): media = None if not media: - raise ValueError("This message doesn't contain any downloadable media") + raise ValueError( + f"The message {message if isinstance(message, str) else message.id} doesn't contain any downloadable media" + ) if isinstance(media, str): file_id_str = media diff --git a/pyrogram/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py index 928e8cb871..a0435115eb 100644 --- a/pyrogram/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -41,7 +41,7 @@ async def send_document( parse_mode: Optional["enums.ParseMode"] = None, caption_entities: List["types.MessageEntity"] = None, file_name: str = None, - disable_content_type_detection: bool = None, + disable_content_type_detection: bool = True, disable_notification: bool = None, reply_parameters: "types.ReplyParameters" = None, message_thread_id: int = None, diff --git a/pyrogram/methods/messages/send_media_group.py b/pyrogram/methods/messages/send_media_group.py index bb61cd6384..0477c016d2 100644 --- a/pyrogram/methods/messages/send_media_group.py +++ b/pyrogram/methods/messages/send_media_group.py @@ -253,8 +253,7 @@ async def send_media_group( media=raw.types.InputMediaUploadedDocument( file=await self.save_file(i.media), thumb=await self.save_file(i.thumb), - nosound_video=i.disable_content_type_detection, - force_file=not i.disable_content_type_detection or None, + nosound_video=i.disable_content_type_detection or True, spoiler=i.has_spoiler, mime_type=self.guess_mime_type(getattr(i.media, "name", "video.mp4")) or "video/mp4", attributes=[ diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index 6dad5bb51c..6b76344f34 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -229,6 +229,7 @@ async def progress(current, total): mime_type=self.guess_mime_type(video) or "video/mp4", file=file, ttl_seconds=ttl_seconds, + nosound_video=True, spoiler=has_spoiler, thumb=thumb, attributes=[ From 983d396a1e846965768e71477492b21d75321d60 Mon Sep 17 00:00:00 2001 From: Artem Ukolov <43943664+deus-developer@users.noreply.github.com> Date: Mon, 17 Jun 2024 08:07:52 +0200 Subject: [PATCH 096/154] Implement non-blocking TCP connection (KurimuzonAkuma/pyrogram#71) --- pyrogram/client.py | 7 +- pyrogram/connection/connection.py | 23 ++- pyrogram/connection/transport/tcp/__init__.py | 2 +- pyrogram/connection/transport/tcp/tcp.py | 147 ++++++++++++------ .../connection/transport/tcp/tcp_abridged.py | 10 +- .../transport/tcp/tcp_abridged_o.py | 10 +- pyrogram/connection/transport/tcp/tcp_full.py | 12 +- .../transport/tcp/tcp_intermediate.py | 10 +- .../transport/tcp/tcp_intermediate_o.py | 10 +- pyrogram/session/auth.py | 21 ++- pyrogram/session/session.py | 16 +- 11 files changed, 172 insertions(+), 96 deletions(-) diff --git a/pyrogram/client.py b/pyrogram/client.py index 15043306ae..5426dd3091 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -32,7 +32,7 @@ from io import StringIO, BytesIO from mimetypes import MimeTypes from pathlib import Path -from typing import Union, List, Optional, Callable, AsyncGenerator +from typing import Union, List, Optional, Callable, AsyncGenerator, Type import pyrogram from pyrogram import __version__, __license__ @@ -52,6 +52,8 @@ from pyrogram.storage import Storage, FileStorage, MemoryStorage from pyrogram.types import User, TermsOfService from pyrogram.utils import ainput +from .connection import Connection +from .connection.transport import TCP, TCPAbridged from .dispatcher import Dispatcher from .file_id import FileId, FileType, ThumbnailSource from .mime_types import mime_types @@ -333,6 +335,9 @@ def __init__( else: self.storage = FileStorage(self.name, self.WORKDIR) + self.connection_factory = Connection + self.protocol_factory = TCPAbridged + self.dispatcher = Dispatcher(self) self.rnd_id = MsgId diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py index 1107673f1a..8db9724fb4 100644 --- a/pyrogram/connection/connection.py +++ b/pyrogram/connection/connection.py @@ -18,7 +18,7 @@ import asyncio import logging -from typing import Optional +from typing import Optional, Type from .transport import TCP, TCPAbridged from ..session.internals import DataCenter @@ -29,19 +29,28 @@ class Connection: MAX_CONNECTION_ATTEMPTS = 3 - def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, media: bool = False): + def __init__( + self, + dc_id: int, + test_mode: bool, + ipv6: bool, + proxy: dict, + media: bool = False, + protocol_factory: Type[TCP] = TCPAbridged + ) -> None: self.dc_id = dc_id self.test_mode = test_mode self.ipv6 = ipv6 self.proxy = proxy self.media = media + self.protocol_factory = protocol_factory self.address = DataCenter(dc_id, test_mode, ipv6, media) - self.protocol: TCP = None + self.protocol: Optional[TCP] = None - async def connect(self): + async def connect(self) -> None: for i in range(Connection.MAX_CONNECTION_ATTEMPTS): - self.protocol = TCPAbridged(self.ipv6, self.proxy) + self.protocol = self.protocol_factory(ipv6=self.ipv6, proxy=self.proxy) try: log.info("Connecting...") @@ -61,11 +70,11 @@ async def connect(self): log.warning("Connection failed! Trying again...") raise ConnectionError - async def close(self): + async def close(self) -> None: await self.protocol.close() log.info("Disconnected") - async def send(self, data: bytes): + async def send(self, data: bytes) -> None: await self.protocol.send(data) async def recv(self) -> Optional[bytes]: diff --git a/pyrogram/connection/transport/tcp/__init__.py b/pyrogram/connection/transport/tcp/__init__.py index 3e23a88379..bae35e8825 100644 --- a/pyrogram/connection/transport/tcp/__init__.py +++ b/pyrogram/connection/transport/tcp/__init__.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from .tcp import TCP +from .tcp import TCP, Proxy from .tcp_abridged import TCPAbridged from .tcp_abridged_o import TCPAbridgedO from .tcp_full import TCPFull diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py index ce9fe3f3a3..9994fb8220 100644 --- a/pyrogram/connection/transport/tcp/tcp.py +++ b/pyrogram/connection/transport/tcp/tcp.py @@ -21,90 +21,135 @@ import logging import socket from concurrent.futures import ThreadPoolExecutor +from typing import Tuple, Dict, TypedDict, Optional import socks log = logging.getLogger(__name__) +proxy_type_by_scheme: Dict[str, int] = { + "SOCKS4": socks.SOCKS4, + "SOCKS5": socks.SOCKS5, + "HTTP": socks.HTTP, +} + + +class Proxy(TypedDict): + scheme: str + hostname: str + port: int + username: Optional[str] + password: Optional[str] + class TCP: TIMEOUT = 10 - def __init__(self, ipv6: bool, proxy: dict): - self.socket = None + def __init__(self, ipv6: bool, proxy: Proxy) -> None: + self.ipv6 = ipv6 + self.proxy = proxy - self.reader = None - self.writer = None + self.reader: Optional[asyncio.StreamReader] = None + self.writer: Optional[asyncio.StreamWriter] = None self.lock = asyncio.Lock() self.loop = asyncio.get_event_loop() - self.proxy = proxy + async def _connect_via_proxy( + self, + destination: Tuple[str, int] + ) -> None: + scheme = self.proxy.get("scheme") + if scheme is None: + raise ValueError("No scheme specified") - if proxy: - hostname = proxy.get("hostname") - - try: - ip_address = ipaddress.ip_address(hostname) - except ValueError: - self.socket = socks.socksocket(socket.AF_INET) - else: - if isinstance(ip_address, ipaddress.IPv6Address): - self.socket = socks.socksocket(socket.AF_INET6) - else: - self.socket = socks.socksocket(socket.AF_INET) + proxy_type = proxy_type_by_scheme.get(scheme.upper()) + if proxy_type is None: + raise ValueError(f"Unknown proxy type {scheme}") - self.socket.set_proxy( - proxy_type=getattr(socks, proxy.get("scheme").upper()), - addr=hostname, - port=proxy.get("port", None), - username=proxy.get("username", None), - password=proxy.get("password", None) - ) + hostname = self.proxy.get("hostname") + port = self.proxy.get("port") + username = self.proxy.get("username") + password = self.proxy.get("password") - self.socket.settimeout(TCP.TIMEOUT) - - log.info("Using proxy %s", hostname) + try: + ip_address = ipaddress.ip_address(hostname) + except ValueError: + is_proxy_ipv6 = False else: - self.socket = socket.socket( - socket.AF_INET6 if ipv6 - else socket.AF_INET - ) - - self.socket.setblocking(False) - - async def connect(self, address: tuple): + is_proxy_ipv6 = isinstance(ip_address, ipaddress.IPv6Address) + + proxy_family = socket.AF_INET6 if is_proxy_ipv6 else socket.AF_INET + sock = socks.socksocket(proxy_family) + + sock.set_proxy( + proxy_type=proxy_type, + addr=hostname, + port=port, + username=username, + password=password + ) + sock.settimeout(TCP.TIMEOUT) + + await self.loop.sock_connect( + sock=sock, + address=destination + ) + + sock.setblocking(False) + + self.reader, self.writer = await asyncio.open_connection( + sock=sock + ) + + async def _connect_via_direct( + self, + destination: Tuple[str, int] + ) -> None: + host, port = destination + family = socket.AF_INET6 if self.ipv6 else socket.AF_INET + self.reader, self.writer = await asyncio.open_connection( + host=host, + port=port, + family=family + ) + + async def _connect(self, destination: Tuple[str, int]) -> None: if self.proxy: - with ThreadPoolExecutor(1) as executor: - await self.loop.run_in_executor(executor, self.socket.connect, address) + await self._connect_via_proxy(destination) else: - try: - await asyncio.wait_for(asyncio.get_event_loop().sock_connect(self.socket, address), TCP.TIMEOUT) - except asyncio.TimeoutError: # Re-raise as TimeoutError. asyncio.TimeoutError is deprecated in 3.11 - raise TimeoutError("Connection timed out") + await self._connect_via_direct(destination) + + async def connect(self, address: Tuple[str, int]) -> None: + try: + await asyncio.wait_for(self._connect(address), TCP.TIMEOUT) + except asyncio.TimeoutError: # Re-raise as TimeoutError. asyncio.TimeoutError is deprecated in 3.11 + raise TimeoutError("Connection timed out") - self.reader, self.writer = await asyncio.open_connection(sock=self.socket) + async def close(self) -> None: + if self.writer is None: + return None - async def close(self): try: - if self.writer is not None: - self.writer.close() - await asyncio.wait_for(self.writer.wait_closed(), TCP.TIMEOUT) + self.writer.close() + await asyncio.wait_for(self.writer.wait_closed(), TCP.TIMEOUT) except Exception as e: log.info("Close exception: %s %s", type(e).__name__, e) - async def send(self, data: bytes): + async def send(self, data: bytes) -> None: + if self.writer is None: + return None + async with self.lock: try: - if self.writer is not None: - self.writer.write(data) - await self.writer.drain() + self.writer.write(data) + await self.writer.drain() except Exception as e: # error coming somewhere here log.exception("Send exception: %s %s", type(e).__name__, e) raise OSError(e) - async def recv(self, length: int = 0): + async def recv(self, length: int = 0) -> Optional[bytes]: data = b"" while len(data) < length: diff --git a/pyrogram/connection/transport/tcp/tcp_abridged.py b/pyrogram/connection/transport/tcp/tcp_abridged.py index 77d44cf41c..4cb4c1b2a3 100644 --- a/pyrogram/connection/transport/tcp/tcp_abridged.py +++ b/pyrogram/connection/transport/tcp/tcp_abridged.py @@ -17,22 +17,22 @@ # along with Pyrogram. If not, see . import logging -from typing import Optional +from typing import Optional, Tuple -from .tcp import TCP +from .tcp import TCP, Proxy log = logging.getLogger(__name__) class TCPAbridged(TCP): - def __init__(self, ipv6: bool, proxy: dict): + def __init__(self, ipv6: bool, proxy: Proxy) -> None: super().__init__(ipv6, proxy) - async def connect(self, address: tuple): + async def connect(self, address: Tuple[str, int]) -> None: await super().connect(address) await super().send(b"\xef") - async def send(self, data: bytes, *args): + async def send(self, data: bytes, *args) -> None: length = len(data) // 4 await super().send( diff --git a/pyrogram/connection/transport/tcp/tcp_abridged_o.py b/pyrogram/connection/transport/tcp/tcp_abridged_o.py index 6f57ab1154..20efb5ec3f 100644 --- a/pyrogram/connection/transport/tcp/tcp_abridged_o.py +++ b/pyrogram/connection/transport/tcp/tcp_abridged_o.py @@ -18,11 +18,11 @@ import logging import os -from typing import Optional +from typing import Optional, Tuple import pyrogram from pyrogram.crypto import aes -from .tcp import TCP +from .tcp import TCP, Proxy log = logging.getLogger(__name__) @@ -30,13 +30,13 @@ class TCPAbridgedO(TCP): RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4) - def __init__(self, ipv6: bool, proxy: dict): + def __init__(self, ipv6: bool, proxy: Proxy) -> None: super().__init__(ipv6, proxy) self.encrypt = None self.decrypt = None - async def connect(self, address: tuple): + async def connect(self, address: Tuple[str, int]) -> None: await super().connect(address) while True: @@ -55,7 +55,7 @@ async def connect(self, address: tuple): await super().send(nonce) - async def send(self, data: bytes, *args): + async def send(self, data: bytes, *args) -> None: length = len(data) // 4 data = (bytes([length]) if length <= 126 else b"\x7f" + length.to_bytes(3, "little")) + data payload = await self.loop.run_in_executor(pyrogram.crypto_executor, aes.ctr256_encrypt, data, *self.encrypt) diff --git a/pyrogram/connection/transport/tcp/tcp_full.py b/pyrogram/connection/transport/tcp/tcp_full.py index 8bd89000c8..ad9d981718 100644 --- a/pyrogram/connection/transport/tcp/tcp_full.py +++ b/pyrogram/connection/transport/tcp/tcp_full.py @@ -19,24 +19,24 @@ import logging from binascii import crc32 from struct import pack, unpack -from typing import Optional +from typing import Optional, Tuple -from .tcp import TCP +from .tcp import TCP, Proxy log = logging.getLogger(__name__) class TCPFull(TCP): - def __init__(self, ipv6: bool, proxy: dict): + def __init__(self, ipv6: bool, proxy: Proxy) -> None: super().__init__(ipv6, proxy) - self.seq_no = None + self.seq_no: Optional[int] = None - async def connect(self, address: tuple): + async def connect(self, address: Tuple[str, int]) -> None: await super().connect(address) self.seq_no = 0 - async def send(self, data: bytes, *args): + async def send(self, data: bytes, *args) -> None: data = pack(" None: super().__init__(ipv6, proxy) - async def connect(self, address: tuple): + async def connect(self, address: Tuple[str, int]) -> None: await super().connect(address) await super().send(b"\xee" * 4) - async def send(self, data: bytes, *args): + async def send(self, data: bytes, *args) -> None: await super().send(pack(" Optional[bytes]: diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py index 48b2d44520..3f47bdfe0a 100644 --- a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py +++ b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py @@ -19,10 +19,10 @@ import logging import os from struct import pack, unpack -from typing import Optional +from typing import Optional, Tuple from pyrogram.crypto import aes -from .tcp import TCP +from .tcp import TCP, Proxy log = logging.getLogger(__name__) @@ -30,13 +30,13 @@ class TCPIntermediateO(TCP): RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4) - def __init__(self, ipv6: bool, proxy: dict): + def __init__(self, ipv6: bool, proxy: Proxy) -> None: super().__init__(ipv6, proxy) self.encrypt = None self.decrypt = None - async def connect(self, address: tuple): + async def connect(self, address: Tuple[str, int]) -> None: await super().connect(address) while True: @@ -55,7 +55,7 @@ async def connect(self, address: tuple): await super().send(nonce) - async def send(self, data: bytes, *args): + async def send(self, data: bytes, *args) -> None: await super().send( aes.ctr256_encrypt( pack(" bytes: @@ -76,7 +84,14 @@ async def create(self): # The server may close the connection at any time, causing the auth key creation to fail. # If that happens, just try again up to MAX_RETRIES times. while True: - self.connection = Connection(self.dc_id, self.test_mode, self.ipv6, self.proxy) + self.connection = self.connection_factory( + dc_id=self.dc_id, + test_mode=self.test_mode, + ipv6=self.ipv6, + proxy=self.proxy, + media=False, + protocol_factory=self.protocol_factory + ) try: log.info("Start creating a new auth key on DC%s", self.dc_id) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index a6ee2119d3..88c8b44694 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -23,6 +23,7 @@ from datetime import datetime, timedelta from hashlib import sha1 from io import BytesIO +from typing import Optional import pyrogram from pyrogram import raw @@ -85,7 +86,7 @@ def __init__( self.is_media = is_media self.is_cdn = is_cdn - self.connection = None + self.connection: Optional[Connection] = None self.auth_key_id = sha1(auth_key).digest()[-8:] @@ -113,12 +114,13 @@ def __init__( async def start(self): while True: - self.connection = Connection( - self.dc_id, - self.test_mode, - self.client.ipv6, - self.client.proxy, - self.is_media + self.connection = self.client.connection_factory( + dc_id=self.dc_id, + test_mode=self.test_mode, + ipv6=self.client.ipv6, + proxy=self.client.proxy, + media=self.is_media, + protocol_factory=self.client.protocol_factory ) try: From 34266515ecb60f3b026b52378d912f867653afef Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 18 Jun 2024 06:58:58 +0200 Subject: [PATCH 097/154] Added support for InputMessageContent classes, according to BOT API. --- compiler/docs/compiler.py | 4 + docs/source/releases/changes-in-this-fork.rst | 2 + pyrogram/methods/messages/send_location.py | 8 +- pyrogram/methods/messages/send_venue.py | 4 +- .../types/input_message_content/__init__.py | 8 + .../input_contact_message_content.py | 68 +++++++ .../input_invoice_message_content.py | 174 ++++++++++++++++++ .../input_location_message_content.py | 82 +++++++++ .../input_message_content.py | 14 +- .../input_text_message_content.py | 2 +- .../input_venue_message_content.py | 87 +++++++++ pyrogram/types/messages_and_media/message.py | 7 + 12 files changed, 449 insertions(+), 11 deletions(-) create mode 100644 pyrogram/types/input_message_content/input_contact_message_content.py create mode 100644 pyrogram/types/input_message_content/input_invoice_message_content.py create mode 100644 pyrogram/types/input_message_content/input_location_message_content.py create mode 100644 pyrogram/types/input_message_content/input_venue_message_content.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 6793352622..a48b658bc0 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -517,6 +517,10 @@ def get_title_list(s: str) -> list: InputMessageContent InputPollOption InputTextMessageContent + InputLocationMessageContent + InputVenueMessageContent + InputContactMessageContent + InputInvoiceMessageContent ReplyParameters TextQuote """, diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 70a606cd9b..ef4ec1a46f 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,8 @@ If you found any issue or have any suggestions, feel free to make `an issue `_) - Added the methods :meth:`~pyrogram.Client.translate_text`, :meth:`~pyrogram.Client.translate_message_text`, :meth:`~pyrogram.types.Message.translate` and the type :obj:`~pyrogram.types.TranslatedText` (`#39 `_). - Added the methods :meth:`~pyrogram.Client.create_video_chat`, :meth:`~pyrogram.Client.discard_group_call`, :meth:`~pyrogram.Client.get_video_chat_rtmp_url` and the type :obj:`~pyrogram.types.RtmpUrl` (`#37 `_). - Added :meth:`~Client.on_story` to listen to story updates. diff --git a/pyrogram/methods/messages/send_location.py b/pyrogram/methods/messages/send_location.py index 94331e73bf..9d88ea2627 100644 --- a/pyrogram/methods/messages/send_location.py +++ b/pyrogram/methods/messages/send_location.py @@ -33,6 +33,8 @@ async def send_location( chat_id: Union[int, str], latitude: float, longitude: float, + horizontal_accuracy: float = None, + # TODO disable_notification: bool = None, reply_parameters: "types.ReplyParameters" = None, message_thread_id: int = None, @@ -64,6 +66,9 @@ async def send_location( longitude (``float``): Longitude of the location. + horizontal_accuracy (``float``, *optional*): + The radius of uncertainty for the location, measured in meters; 0-1500. + disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. @@ -122,7 +127,8 @@ async def send_location( media=raw.types.InputMediaGeoPoint( geo_point=raw.types.InputGeoPoint( lat=latitude, - long=longitude + long=longitude, + accuracy_radius=horizontal_accuracy ) ), message="", diff --git a/pyrogram/methods/messages/send_venue.py b/pyrogram/methods/messages/send_venue.py index 730c06e2aa..67577bec78 100644 --- a/pyrogram/methods/messages/send_venue.py +++ b/pyrogram/methods/messages/send_venue.py @@ -36,6 +36,8 @@ async def send_venue( address: str, foursquare_id: str = "", foursquare_type: str = "", + google_place_id: str = "", + google_place_type: str = "", disable_notification: bool = None, reply_parameters: "types.ReplyParameters" = None, message_thread_id: int = None, @@ -145,7 +147,7 @@ async def send_venue( ), title=title, address=address, - provider="", + provider="", # TODO venue_id=foursquare_id, venue_type=foursquare_type ), diff --git a/pyrogram/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py index 1a48488f44..1eb7f0775d 100644 --- a/pyrogram/types/input_message_content/__init__.py +++ b/pyrogram/types/input_message_content/__init__.py @@ -18,6 +18,10 @@ from .input_message_content import InputMessageContent from .input_text_message_content import InputTextMessageContent +from .input_location_message_content import InputLocationMessageContent +from .input_venue_message_content import InputVenueMessageContent +from .input_contact_message_content import InputContactMessageContent +from .input_invoice_message_content import InputInvoiceMessageContent from .reply_parameters import ReplyParameters from .external_reply_info import ExternalReplyInfo from .text_quote import TextQuote @@ -28,6 +32,10 @@ "InputMessageContent", "InputPollOption", "InputTextMessageContent", + "InputLocationMessageContent", + "InputVenueMessageContent", + "InputContactMessageContent", + "InputInvoiceMessageContent", "ReplyParameters", "TextQuote", ] diff --git a/pyrogram/types/input_message_content/input_contact_message_content.py b/pyrogram/types/input_message_content/input_contact_message_content.py new file mode 100644 index 0000000000..0566f25d95 --- /dev/null +++ b/pyrogram/types/input_message_content/input_contact_message_content.py @@ -0,0 +1,68 @@ +# 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 . + +import logging +from typing import Optional + +import pyrogram +from pyrogram import raw +from .input_message_content import InputMessageContent + +log = logging.getLogger(__name__) + + +class InputContactMessageContent(InputMessageContent): + """Content of a contact message to be sent as the result of an inline query. + + Parameters: + phone_number (``str``): + Contact's phone number. + + first_name (``str``): + Contact's first name. + + last_name (``str``, *optional*): + Contact's last name. + + vcard (``str``, *optional*): + Additional data about the contact in the form of a `vCard `_, 0-2048 bytes. + + """ + + def __init__( + self, + phone_number: str, + first_name: str, + last_name: Optional[str] = None, + vcard: Optional[str] = None + ): + super().__init__() + + self.phone_number = phone_number + self.first_name = first_name + self.last_name = last_name + self.vcard = vcard + + async def write(self, client: "pyrogram.Client", reply_markup): + return raw.types.InputBotInlineMessageMediaContact( + phone_number=self.phone_number, + first_name=self.first_name, + last_name=self.last_name, + vcard=self.vcard, + reply_markup=await reply_markup.write(client) if reply_markup else None + ) diff --git a/pyrogram/types/input_message_content/input_invoice_message_content.py b/pyrogram/types/input_message_content/input_invoice_message_content.py new file mode 100644 index 0000000000..78bf61244c --- /dev/null +++ b/pyrogram/types/input_message_content/input_invoice_message_content.py @@ -0,0 +1,174 @@ +# 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 . + +import logging +from typing import Optional, List, Union + +import pyrogram +from pyrogram import raw, types +from .input_message_content import InputMessageContent + +log = logging.getLogger(__name__) + + +class InputInvoiceMessageContent(InputMessageContent): + """Content of an invoice message to be sent as the result of an inline query. + + Parameters: + title (``str``): + Product name, 1-32 characters. + + description (``str``): + Product description, 1-255 characters + + payload (``str`` | ``bytes``): + Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. + + currency (``str``): + Three-letter ISO 4217 currency code, see `more on currencies `_. Pass ``XTR`` for payments in `Telegram Stars `_. + + prices (List of :obj:`~pyrogram.types.LabeledPrice`): + Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_. + + provider_token (``str``, *optional*): + Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_. + + max_tip_amount (``int``, *optional*): + The maximum accepted amount for tips in the smallest units of the currency (integer, **not** float/double). For example, for a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_. + + suggested_tip_amounts (List of ``int``, *optional*): + An array of suggested amounts of tips in the smallest units of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed ``max_tip_amount``. + + provider_data (``str``, *optional*): + JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. + + photo_url (``str``, *optional*): + URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. + + photo_size (``int``, *optional*): + Photo size in bytes + + photo_width (``int``, *optional*): + Photo width + + photo_height (``int``, *optional*): + Photo height + + need_name (``bool``, *optional*): + Pass True if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_. + + need_phone_number (``bool``, *optional*): + Pass True if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_. + + need_email (``bool``, *optional*): + Pass True if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_. + + need_shipping_address (``bool``, *optional*): + Pass True if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_. + + send_phone_number_to_provider (``bool``, *optional*): + Pass True if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + send_email_to_provider (``bool``, *optional*): + Pass True if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_. + + is_flexible (``bool``, *optional*): + Pass True if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_. + + """ + + def __init__( + self, + title: str, + description: str, + payload: Union[str, bytes], + currency: str, + prices: List["types.LabeledPrice"], + provider_token: Optional[str] = None, + max_tip_amount: Optional[int] = None, + suggested_tip_amounts: List[int] = None, + provider_data: Optional[str] = None, + photo_url: Optional[str] = None, + photo_size: Optional[int] = None, + photo_width: Optional[int] = None, + photo_height: Optional[int] = None, + need_name: Optional[bool] = None, + need_phone_number: Optional[bool] = None, + need_email: Optional[bool] = None, + need_shipping_address: Optional[bool] = None, + send_phone_number_to_provider: Optional[bool] = None, + send_email_to_provider: Optional[bool] = None, + is_flexible: Optional[bool] = None + ): + super().__init__() + + self.title = title + self.description = description + self.payload = payload + self.currency = currency + self.prices = prices + self.provider_token = provider_token + self.max_tip_amount = max_tip_amount + self.suggested_tip_amounts = suggested_tip_amounts + self.provider_data = provider_data + self.photo_url = photo_url + self.photo_size = photo_size + self.photo_width = photo_width + self.photo_height = photo_height + self.need_name = need_name + self.need_phone_number = need_phone_number + self.need_email = need_email + self.need_shipping_address = need_shipping_address + self.send_phone_number_to_provider = send_phone_number_to_provider + self.send_email_to_provider = send_email_to_provider + self.is_flexible = is_flexible + + async def write(self, client: "pyrogram.Client", reply_markup): + return raw.types.InputBotInlineMessageMediaInvoice( + title=self.title, + description=self.description, + photo=raw.types.InputWebDocument( + url=self.photo_url, + mime_type="image/jpg", + size=self.photo_size, + attributes=[ + raw.types.DocumentAttributeImageSize( + w=self.photo_width, + h=self.photo_height + ) + ] + ) if self.photo_url else None, + invoice=raw.types.Invoice( + currency=self.currency, + prices=[i.write() for i in self.prices], + test=client.test_mode, + name_requested=self.need_name, + phone_requested=self.need_phone_number, + email_requested=self.need_email, + shipping_address_requested=self.need_shipping_address, + flexible=self.is_flexible, + phone_to_provider=self.send_phone_number_to_provider, + email_to_provider=self.send_email_to_provider + ), + payload=self.payload.encode() if isinstance(self.payload, str) else self.payload, + provider=self.provider_token, + provider_data=raw.types.DataJSON( + data=self.provider_data if self.provider_data else "{}" + ), + reply_markup=await reply_markup.write(client) if reply_markup else None + ) diff --git a/pyrogram/types/input_message_content/input_location_message_content.py b/pyrogram/types/input_message_content/input_location_message_content.py new file mode 100644 index 0000000000..b13381e317 --- /dev/null +++ b/pyrogram/types/input_message_content/input_location_message_content.py @@ -0,0 +1,82 @@ +# 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 . + +import logging +from typing import Optional + +import pyrogram +from pyrogram import raw +from .input_message_content import InputMessageContent + +log = logging.getLogger(__name__) + + +class InputLocationMessageContent(InputMessageContent): + """Content of a location message to be sent as the result of an inline query. + + Parameters: + latitude (``float``): + Latitude of the location. + + longitude (``float``): + Longitude of the location. + + horizontal_accuracy (``float``, *optional*): + The radius of uncertainty for the location, measured in meters; 0-1500. + + live_period (``int``, *optional*): + Period in seconds during which the location can be updated, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely. + + heading (``int``, *optional*): + For live locations, a direction in which the user is moving, in degrees. Must be between 1 and 360 if specified. + + proximity_alert_radius (``int``, *optional*): + For live locations, a maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified. + + """ + + def __init__( + self, + latitude: float, + longitude: float, + horizontal_accuracy: Optional[float] = None, + live_period: Optional[int] = None, + heading: Optional[int] = None, + proximity_alert_radius: Optional[int] = None + ): + super().__init__() + + self.latitude = latitude + self.longitude = longitude + self.horizontal_accuracy = horizontal_accuracy + self.live_period = live_period + self.heading = heading + self.proximity_alert_radius = proximity_alert_radius + + async def write(self, client: "pyrogram.Client", reply_markup): + return raw.types.InputBotInlineMessageMediaGeo( + geo_point=raw.types.InputGeoPoint( + lat=self.latitude, + long=self.longitude, + accuracy_radius=self.horizontal_accuracy + ), + heading=self.heading, + period=self.live_period, + proximity_notification_radius=self.proximity_alert_radius, + reply_markup=await reply_markup.write(client) if reply_markup else None + ) diff --git a/pyrogram/types/input_message_content/input_message_content.py b/pyrogram/types/input_message_content/input_message_content.py index 6ffe6cae24..2061067a78 100644 --- a/pyrogram/types/input_message_content/input_message_content.py +++ b/pyrogram/types/input_message_content/input_message_content.py @@ -20,20 +20,18 @@ from ..object import Object -""" - - :obj:`~pyrogram.types.InputLocationMessageContent` - - :obj:`~pyrogram.types.InputVenueMessageContent` - - :obj:`~pyrogram.types.InputContactMessageContent` - - :obj:`~pyrogram.types.InputInvoiceMessageContent` -""" - class InputMessageContent(Object): """Content of a message to be sent as a result of an inline query. - Pyrogram currently supports the following types: + Telegram clients currently support the following 5 types: - :obj:`~pyrogram.types.InputTextMessageContent` + - :obj:`~pyrogram.types.InputLocationMessageContent` + - :obj:`~pyrogram.types.InputVenueMessageContent` + - :obj:`~pyrogram.types.InputContactMessageContent` + - :obj:`~pyrogram.types.InputInvoiceMessageContent` + """ def __init__(self): diff --git a/pyrogram/types/input_message_content/input_text_message_content.py b/pyrogram/types/input_message_content/input_text_message_content.py index 8de943f429..88e140eb1f 100644 --- a/pyrogram/types/input_message_content/input_text_message_content.py +++ b/pyrogram/types/input_message_content/input_text_message_content.py @@ -41,7 +41,7 @@ class InputTextMessageContent(InputMessageContent): List of special entities that appear in message text, which can be specified instead of *parse_mode*. link_preview_options (:obj:`~pyrogram.types.LinkPreviewOptions`, *optional*): - Link preview generation options for the message + Link preview generation options for the message """ def __init__( diff --git a/pyrogram/types/input_message_content/input_venue_message_content.py b/pyrogram/types/input_message_content/input_venue_message_content.py new file mode 100644 index 0000000000..baf922ac45 --- /dev/null +++ b/pyrogram/types/input_message_content/input_venue_message_content.py @@ -0,0 +1,87 @@ +# 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 . + +import logging +from typing import Optional + +import pyrogram +from pyrogram import raw +from .input_message_content import InputMessageContent + +log = logging.getLogger(__name__) + + +class InputVenueMessageContent(InputMessageContent): + """Content of a venue message to be sent as the result of an inline query. + + Parameters: + latitude (``float``): + Latitude of the location. + + longitude (``float``): + Longitude of the location. + + title (``str``): + Name of the venue. + + address (``str``): + Address of the venue. + + foursquare_id (``str``, *optional*): + Foursquare identifier of the venue, if known. + + foursquare_type (``str``, *optional*): + Foursquare type of the venue, if known. (For example, “arts_entertainment/default”, “arts_entertainment/aquarium” or “food/icecream”.) + + """ + + def __init__( + self, + latitude: float, + longitude: float, + title: str, + address: str, + foursquare_id: Optional[str] = None, + foursquare_type: Optional[str] = None, + google_place_id: Optional[str] = None, + google_place_type: Optional[str] = None + ): + super().__init__() + + self.latitude = latitude + self.longitude = longitude + self.title = title + self.address = address + self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type + self.google_place_id = google_place_id + self.google_place_type = google_place_type + + async def write(self, client: "pyrogram.Client", reply_markup): + return raw.types.InputBotInlineMessageMediaVenue( + geo_point=raw.types.InputGeoPoint( + lat=self.latitude, + long=self.longitude + ), + title=self.title, + address=self.address, + provider="", # TODO + venue_id=self.foursquare_id, + venue_type=self.foursquare_type, + reply_markup=await reply_markup.write(client) if reply_markup else None + ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index f92c04d002..5dec64609c 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -2410,6 +2410,8 @@ async def reply_location( latitude: float, longitude: float, quote: bool = None, + horizontal_accuracy: float = None, + # TODO disable_notification: bool = None, message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, @@ -2452,6 +2454,9 @@ async def reply_location( If *reply_to_message_id* is passed, this parameter will be ignored. Defaults to ``True`` in group chats and ``False`` in private chats. + horizontal_accuracy (``float``, *optional*): + The radius of uncertainty for the location, measured in meters; 0-1500. + disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. @@ -2490,6 +2495,7 @@ async def reply_location( chat_id=self.chat.id, latitude=latitude, longitude=longitude, + horizontal_accuracy=horizontal_accuracy, disable_notification=disable_notification, message_effect_id=message_effect_id, reply_parameters=reply_parameters, @@ -3037,6 +3043,7 @@ async def reply_venue( quote: bool = None, foursquare_id: str = "", foursquare_type: str = "", + # TODO disable_notification: bool = None, message_effect_id: int = None, reply_parameters: "types.ReplyParameters" = None, From dce3099382fa06bcaf8e7015987d47c5e79798dd Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 18 Jun 2024 17:08:45 +0200 Subject: [PATCH 098/154] Update API Scheme to Layer 182 --- compiler/api/source/main_api.tl | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 4f9f9fcc5a..ce60b0f89a 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -464,6 +464,8 @@ updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages: updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueBalances = Update; updateStarsBalance#fb85198 balance:long = Update; +updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; +updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -841,7 +843,7 @@ contacts.topPeers#70b772a8 categories:Vector chats:Vector< contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#3fccf7ef flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int = DraftMessage; +draftMessage#2d65321f flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long = DraftMessage; messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; @@ -1652,14 +1654,15 @@ exportedStoryLink#3fc9053b link:string = ExportedStoryLink; storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; -mediaAreaCoordinates#3d1ea4e x:double y:double w:double h:double rotation:double = MediaAreaCoordinates; +mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#df8b3b22 coordinates:MediaAreaCoordinates geo:GeoPoint = MediaArea; +mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; +mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; @@ -1852,10 +1855,22 @@ starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; -starsTransaction#cc7079b2 flags:# refund:flags.3?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument = StarsTransaction; +starsTransaction#aa00c898 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string = StarsTransaction; payments.starsStatus#8cf4ee60 flags:# balance:long history:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; +foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; + +stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; + +geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; + +starsRevenueStatus#79342946 flags:# withdrawal_enabled:flags.0?true current_balance:long available_balance:long overall_revenue:long next_withdrawal_at:flags.1?int = StarsRevenueStatus; + +payments.starsRevenueStats#c92bb73b revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; + +payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2099,7 +2114,7 @@ messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_me messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#7ff3b806 flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia = Bool; +messages.saveDraft#d372c5ce flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; @@ -2398,9 +2413,11 @@ payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayI payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; payments.getStarsTopupOptions#c00ec7d3 = Vector; payments.getStarsStatus#104fcfa7 peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#673ac2f9 flags:# inbound:flags.0?true outbound:flags.1?true peer:InputPeer offset:string = payments.StarsStatus; +payments.getStarsTransactions#97938d5a flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true peer:InputPeer offset:string limit:int = payments.StarsStatus; payments.sendStarsForm#2bb731d flags:# form_id:long invoice:InputInvoice = payments.PaymentResult; payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; +payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true peer:InputPeer = payments.StarsRevenueStats; +payments.getStarsRevenueWithdrawalUrl#13bbe8b3 peer:InputPeer stars:long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; @@ -2502,6 +2519,7 @@ stories.getChatsToSend#a56a8b60 = messages.Chats; stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; +stories.searchPosts#6cea116a flags:# hashtag:flags.0?string area:flags.1?MediaArea offset:string limit:int = stories.FoundStories; premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; premium.getMyBoosts#be77b4a = premium.MyBoosts; @@ -2523,4 +2541,4 @@ test.useError = Error; test.useConfigSimple = help.ConfigSimple; test.parseInputAppEvent = InputAppEvent; -// LAYER 181 +// LAYER 182 From af1293cf08620744a04047f81413553c36b97aff Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 18 Jun 2024 17:19:28 +0200 Subject: [PATCH 099/154] Add UpdateBusinessBotCallbackQuery in callback_query handler --- docs/source/releases/changes-in-this-fork.rst | 6 +++++ pyrogram/dispatcher.py | 3 ++- .../bots_and_keyboards/callback_query.py | 24 ++++++++++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index ef4ec1a46f..ce4b27d36f 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -10,6 +10,12 @@ it can take advantage of new goodies! If you found any issue or have any suggestions, feel free to make `an issue `_ on github. ++------------------------+ +| Scheme layer used: 182 | ++------------------------+ + +- Added support for callback queries originating from a message sent on behalf of a business account. + +------------------------+ | Scheme layer used: 181 | +------------------------+ diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index bd7fef8407..e7758063d8 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -62,6 +62,7 @@ UpdateBotPrecheckoutQuery, UpdateBotShippingQuery, UpdateStory, + UpdateBusinessBotCallbackQuery, ) log = logging.getLogger(__name__) @@ -71,7 +72,7 @@ class Dispatcher: NEW_MESSAGE_UPDATES = (UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage, UpdateBotNewBusinessMessage) EDIT_MESSAGE_UPDATES = (UpdateEditMessage, UpdateEditChannelMessage, UpdateBotEditBusinessMessage) DELETE_MESSAGES_UPDATES = (UpdateDeleteMessages, UpdateDeleteChannelMessages, UpdateBotDeleteBusinessMessage) - CALLBACK_QUERY_UPDATES = (UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery) + CALLBACK_QUERY_UPDATES = (UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery, UpdateBusinessBotCallbackQuery) CHAT_MEMBER_UPDATES = (UpdateChatParticipant, UpdateChannelParticipant, UpdateBotStopped,) USER_STATUS_UPDATES = (UpdateUserStatus,) BOT_INLINE_QUERY_UPDATES = (UpdateBotInlineQuery,) diff --git a/pyrogram/types/bots_and_keyboards/callback_query.py b/pyrogram/types/bots_and_keyboards/callback_query.py index f101f88119..bde9a908bc 100644 --- a/pyrogram/types/bots_and_keyboards/callback_query.py +++ b/pyrogram/types/bots_and_keyboards/callback_query.py @@ -117,13 +117,25 @@ async def _parse(client: "pyrogram.Client", callback_query, users, chats) -> "Ca ) elif isinstance(callback_query, raw.types.UpdateInlineBotCallbackQuery): inline_message_id = utils.pack_inline_message_id(callback_query.msg_id) - + elif isinstance(callback_query, raw.types.UpdateBusinessBotCallbackQuery): + message = await types.Message._parse( + client, + callback_query.message, + users, + chats, + is_scheduled=False, + replies=0, + business_connection_id=callback_query.connection_id, + raw_reply_to_message=getattr(callback_query, "reply_to_message", None) + ) # Try to decode callback query data into string. If that fails, fallback to bytes instead of decoding by # ignoring/replacing errors, this way, button clicks will still work. - try: - data = callback_query.data.decode() - except (UnicodeDecodeError, AttributeError): - data = callback_query.data + data = getattr(callback_query, "data", None) + if data: + try: + data = data.decode() + except (UnicodeDecodeError, AttributeError): + data = data return CallbackQuery( id=str(callback_query.query_id), @@ -132,7 +144,7 @@ async def _parse(client: "pyrogram.Client", callback_query, users, chats) -> "Ca inline_message_id=inline_message_id, chat_instance=str(callback_query.chat_instance), data=data, - game_short_name=callback_query.game_short_name, + game_short_name=getattr(callback_query, "game_short_name", None), client=client ) From ec3a96bf0bfc3dcd11ccb5e926e6f9106e4f57a3 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 20 Jun 2024 05:44:42 +0200 Subject: [PATCH 100/154] Add business_connection_id parameter in edit_message_caption edit_message_media edit_message_reply_markup edit_message_text stop_poll Message.edit_text Message.edit_media Message.edit_reply_markup CallbackQuery.edit_message_text CallbackQuery.edit_message_media CallbackQuery.edit_message_reply_markup Poll.stop --- docs/source/releases/changes-in-this-fork.rst | 3 + .../methods/messages/edit_message_caption.py | 9 ++- .../methods/messages/edit_message_media.py | 63 +++++++++++++++---- .../messages/edit_message_reply_markup.py | 62 +++++++++++++++--- .../methods/messages/edit_message_text.py | 59 +++++++++++++---- pyrogram/methods/messages/stop_poll.py | 57 ++++++++++++----- .../bots_and_keyboards/callback_query.py | 9 ++- pyrogram/types/messages_and_media/message.py | 7 ++- pyrogram/types/messages_and_media/poll.py | 9 ++- 9 files changed, 220 insertions(+), 58 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index ce4b27d36f..07db90a029 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,9 @@ If you found any issue or have any suggestions, feel free to make `an issue "types.Message": """Edit the caption of media messages. @@ -67,6 +68,9 @@ async def edit_message_caption( schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Returns: :obj:`~pyrogram.types.Message`: On success, the edited message is returned. @@ -89,5 +93,6 @@ async def edit_message_caption( entities=caption_entities, reply_markup=reply_markup, link_preview_options=link_preview_options, - schedule_date=schedule_date + schedule_date=schedule_date, + business_connection_id=business_connection_id ) diff --git a/pyrogram/methods/messages/edit_message_media.py b/pyrogram/methods/messages/edit_message_media.py index f2fde50851..3a9086fcb4 100644 --- a/pyrogram/methods/messages/edit_message_media.py +++ b/pyrogram/methods/messages/edit_message_media.py @@ -26,6 +26,8 @@ from pyrogram import raw, types, utils from pyrogram.file_id import FileType +from .inline_session import get_session + class EditMessageMedia: async def edit_message_media( @@ -35,7 +37,8 @@ async def edit_message_media( media: "types.InputMedia", reply_markup: "types.InlineKeyboardMarkup" = None, file_name: str = None, - schedule_date: datetime = None + schedule_date: datetime = None, + business_connection_id: str = None ) -> "types.Message": """Edit animation, audio, document, photo or video messages. @@ -66,6 +69,9 @@ async def edit_message_media( schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Returns: :obj:`~pyrogram.types.Message`: On success, the edited message is returned. @@ -279,18 +285,36 @@ async def edit_message_media( else: media = utils.get_input_media_from_file_id(media.media, FileType.DOCUMENT) - r = await self.invoke( - raw.functions.messages.EditMessage( - peer=await self.resolve_peer(chat_id), - id=message_id, - media=media, - reply_markup=await reply_markup.write(self) if reply_markup else None, - message=message, - entities=entities, - # TODO - schedule_date=utils.datetime_to_timestamp(schedule_date) - ) + rpc = raw.functions.messages.EditMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + media=media, + reply_markup=await reply_markup.write(self) if reply_markup else None, + message=message, + entities=entities, + # TODO + schedule_date=utils.datetime_to_timestamp(schedule_date) ) + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) for i in r.updates: if isinstance( @@ -308,3 +332,18 @@ async def edit_message_media( is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), replies=self.fetch_replies ) + elif isinstance( + i, + ( + raw.types.UpdateBotEditBusinessMessage + ) + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + business_connection_id=getattr(i, "connection_id", business_connection_id), + raw_reply_to_message=i.reply_to_message, + replies=0 + ) diff --git a/pyrogram/methods/messages/edit_message_reply_markup.py b/pyrogram/methods/messages/edit_message_reply_markup.py index abbe5e686b..cb4a5e53b9 100644 --- a/pyrogram/methods/messages/edit_message_reply_markup.py +++ b/pyrogram/methods/messages/edit_message_reply_markup.py @@ -19,8 +19,9 @@ from typing import Union import pyrogram -from pyrogram import raw -from pyrogram import types +from pyrogram import raw, types + +from .inline_session import get_session class EditMessageReplyMarkup: @@ -29,6 +30,7 @@ async def edit_message_reply_markup( chat_id: Union[int, str], message_id: int, reply_markup: "types.InlineKeyboardMarkup" = None, + business_connection_id: str = None ) -> "types.Message": """Edit only the reply markup of messages sent by the bot. @@ -46,6 +48,9 @@ async def edit_message_reply_markup( reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Returns: :obj:`~pyrogram.types.Message`: On success, the edited message is returned. @@ -60,19 +65,58 @@ async def edit_message_reply_markup( InlineKeyboardMarkup([[ InlineKeyboardButton("New button", callback_data="new_data")]])) """ - r = await self.invoke( - raw.functions.messages.EditMessage( - peer=await self.resolve_peer(chat_id), - id=message_id, - reply_markup=await reply_markup.write(self) if reply_markup else None, - ) + rpc = raw.functions.messages.EditMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + reply_markup=await reply_markup.write(self) if reply_markup else None, ) + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) for i in r.updates: - if isinstance(i, (raw.types.UpdateEditMessage, raw.types.UpdateEditChannelMessage)): + if isinstance( + i, + ( + raw.types.UpdateEditMessage, + raw.types.UpdateEditChannelMessage + ) + ): return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, replies=self.fetch_replies ) + elif isinstance( + i, + ( + raw.types.UpdateBotEditBusinessMessage + ) + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + business_connection_id=getattr(i, "connection_id", business_connection_id), + raw_reply_to_message=i.reply_to_message, + replies=0 + ) diff --git a/pyrogram/methods/messages/edit_message_text.py b/pyrogram/methods/messages/edit_message_text.py index d46ea4665e..28847e0436 100644 --- a/pyrogram/methods/messages/edit_message_text.py +++ b/pyrogram/methods/messages/edit_message_text.py @@ -37,6 +37,7 @@ async def edit_message_text( link_preview_options: "types.LinkPreviewOptions" = None, reply_markup: "types.InlineKeyboardMarkup" = None, schedule_date: datetime = None, + business_connection_id: str = None, disable_web_page_preview: bool = None ) -> "types.Message": """Edit the text of messages. @@ -71,6 +72,9 @@ async def edit_message_text( schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Returns: :obj:`~pyrogram.types.Message`: On success, the edited message is returned. @@ -115,18 +119,36 @@ async def edit_message_text( optional=True ) - r = await self.invoke( - raw.functions.messages.EditMessage( - peer=await self.resolve_peer(chat_id), - id=message_id, - no_webpage=link_preview_options.is_disabled if link_preview_options else None, - invert_media=link_preview_options.show_above_text if link_preview_options else None, - media=media, - reply_markup=await reply_markup.write(self) if reply_markup else None, - schedule_date=utils.datetime_to_timestamp(schedule_date), - **await utils.parse_text_entities(self, text, parse_mode, entities) - ) + rpc = raw.functions.messages.EditMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + no_webpage=link_preview_options.is_disabled if link_preview_options else None, + invert_media=link_preview_options.show_above_text if link_preview_options else None, + media=media, + reply_markup=await reply_markup.write(self) if reply_markup else None, + schedule_date=utils.datetime_to_timestamp(schedule_date), + **await utils.parse_text_entities(self, text, parse_mode, entities) ) + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) for i in r.updates: if isinstance( @@ -144,3 +166,18 @@ async def edit_message_text( is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), replies=self.fetch_replies ) + elif isinstance( + i, + ( + raw.types.UpdateBotEditBusinessMessage + ) + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + business_connection_id=getattr(i, "connection_id", business_connection_id), + raw_reply_to_message=i.reply_to_message, + replies=0 + ) diff --git a/pyrogram/methods/messages/stop_poll.py b/pyrogram/methods/messages/stop_poll.py index 1ce6352641..65380e37ac 100644 --- a/pyrogram/methods/messages/stop_poll.py +++ b/pyrogram/methods/messages/stop_poll.py @@ -19,8 +19,9 @@ from typing import Union import pyrogram -from pyrogram import raw -from pyrogram import types +from pyrogram import raw, types + +from .inline_session import get_session class StopPoll: @@ -28,7 +29,8 @@ async def stop_poll( self: "pyrogram.Client", chat_id: Union[int, str], message_id: int, - reply_markup: "types.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None, + business_connection_id: str = None ) -> "types.Poll": """Stop a poll which was sent by you. @@ -48,6 +50,9 @@ async def stop_poll( reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Returns: :obj:`~pyrogram.types.Poll`: On success, the stopped poll with the final results is returned. @@ -61,20 +66,38 @@ async def stop_poll( message_ids=message_id )).poll # TODO - r = await self.invoke( - raw.functions.messages.EditMessage( - peer=await self.resolve_peer(chat_id), - id=message_id, - media=raw.types.InputMediaPoll( - poll=raw.types.Poll( - id=int(poll.id), - closed=True, - question=raw.types.TextWithEntities(text="", entities=[]), - answers=[] - ) - ), - reply_markup=await reply_markup.write(self) if reply_markup else None - ) + rpc = raw.functions.messages.EditMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + media=raw.types.InputMediaPoll( + poll=raw.types.Poll( + id=int(poll.id), + closed=True, + question=raw.types.TextWithEntities(text="", entities=[]), + answers=[] + ) + ), + reply_markup=await reply_markup.write(self) if reply_markup else None ) + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) return types.Poll._parse(self, r.updates[0]) diff --git a/pyrogram/types/bots_and_keyboards/callback_query.py b/pyrogram/types/bots_and_keyboards/callback_query.py index bde9a908bc..c745d99d4e 100644 --- a/pyrogram/types/bots_and_keyboards/callback_query.py +++ b/pyrogram/types/bots_and_keyboards/callback_query.py @@ -238,7 +238,8 @@ async def edit_message_text( entities=entities, link_preview_options=link_preview_options, reply_markup=reply_markup, - disable_web_page_preview=disable_web_page_preview + disable_web_page_preview=disable_web_page_preview, + business_connection_id=self.message.business_connection_id ) else: return await self._client.edit_inline_text( @@ -324,7 +325,8 @@ async def edit_message_media( message_id=self.message.id, media=media, reply_markup=reply_markup, - file_name=file_name + file_name=file_name, + business_connection_id=self.message.business_connection_id ) else: return await self._client.edit_inline_media( @@ -356,7 +358,8 @@ async def edit_message_reply_markup( return await self._client.edit_message_reply_markup( chat_id=self.message.chat.id, message_id=self.message.id, - reply_markup=reply_markup + reply_markup=reply_markup, + business_connection_id=self.message.business_connection_id, ) else: return await self._client.edit_inline_reply_markup( diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 5dec64609c..e302bad905 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -3922,6 +3922,7 @@ async def edit_text( entities=entities, link_preview_options=link_preview_options, reply_markup=reply_markup, + business_connection_id=self.business_connection_id, disable_web_page_preview=disable_web_page_preview ) @@ -4027,7 +4028,8 @@ async def edit_media( media=media, reply_markup=reply_markup, file_name=file_name, - schedule_date=self.date if self.scheduled else None + schedule_date=self.date if self.scheduled else None, + business_connection_id=self.business_connection_id ) async def edit_reply_markup(self, reply_markup: "types.InlineKeyboardMarkup" = None) -> "Message": @@ -4062,7 +4064,8 @@ async def edit_reply_markup(self, reply_markup: "types.InlineKeyboardMarkup" = N return await self._client.edit_message_reply_markup( chat_id=self.chat.id, message_id=self.id, - reply_markup=reply_markup + reply_markup=reply_markup, + business_connection_id=self.business_connection_id ) async def edit_cached_media( diff --git a/pyrogram/types/messages_and_media/poll.py b/pyrogram/types/messages_and_media/poll.py index 8d4d0d5e67..67617cbe01 100644 --- a/pyrogram/types/messages_and_media/poll.py +++ b/pyrogram/types/messages_and_media/poll.py @@ -233,7 +233,8 @@ def _parse_update(client, update: "raw.types.UpdateMessagePoll"): async def stop( self, - reply_markup: "types.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None, + business_connection_id: str = None ) -> "types.Poll": """Bound method *stop* of :obj:`~pyrogram.types.Poll`. @@ -250,6 +251,9 @@ async def stop( reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Example: .. code-block:: python @@ -265,5 +269,6 @@ async def stop( return await self._client.stop_poll( chat_id=self.chat.id, message_id=self.message_id, - reply_markup=reply_markup + reply_markup=reply_markup, + business_connection_id=business_connection_id ) From c74fcf5b5760e54cd06bed31119fc54b605e41e3 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 20 Jun 2024 06:59:16 +0200 Subject: [PATCH 101/154] Add unknown_errors Improve error messages. --- compiler/errors/source/400_BAD_REQUEST.tsv | 3 +++ pyrogram/errors/rpc_error.py | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index 01d0d9acfb..f16677a60b 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -76,6 +76,8 @@ CHANNEL_PARICIPANT_MISSING The current user is not in the channel. CHANNEL_PRIVATE You haven't joined this channel/supergroup. CHANNEL_TOO_BIG This channel has too many participants (>1000) to be deleted. CHANNEL_TOO_LARGE Channel is too large to be deleted; this error is issued when trying to delete channels with more than 1000 members (subject to change). +CHARGE_ALREADY_REFUNDED The charge id was already used for a refund. +CHARGE_NOT_FOUND The charge id was not found. CHATLIST_EXCLUDE_INVALID The specified `exclude_peers` are invalid. CHAT_ABOUT_NOT_MODIFIED About text has not changed. CHAT_ABOUT_TOO_LONG Chat about too long. @@ -171,6 +173,7 @@ FILTER_TITLE_EMPTY The title field of the filter is empty. FIRSTNAME_INVALID The first name is invalid. FOLDER_ID_EMPTY An empty folder ID was specified. FOLDER_ID_INVALID Invalid folder ID. +FORM_ID_EXPIRED The specified id has expired. FORUM_ENABLED You can't execute the specified action because the group is a [forum](https://core.telegram.org/api/forum), disable forum functionality to continue. FRESH_CHANGE_ADMINS_FORBIDDEN You were just elected admin, you can't add or modify other admins yet. FROM_MESSAGE_BOT_DISABLED Bots can't use fromMessage min constructors. diff --git a/pyrogram/errors/rpc_error.py b/pyrogram/errors/rpc_error.py index 0268e5a2a4..1ca3631627 100644 --- a/pyrogram/errors/rpc_error.py +++ b/pyrogram/errors/rpc_error.py @@ -22,7 +22,7 @@ from importlib import import_module from typing import Type, Union -from pyrogram import raw +from pyrogram import __version__, raw from pyrogram.raw.core import TLObject from .exceptions.all import exceptions @@ -50,12 +50,13 @@ def __init__( is_signed: bool = False, _raw = None ): - super().__init__("Telegram says: [{}{} {}] - {} {}".format( + super().__init__("Telegram says: [{}{} {}] {} Pyrogram {} thinks: {}".format( "-" if is_signed else "", self.CODE, self.ID or self.NAME, + f'(caused by "{rpc_name}")' if rpc_name else "", + __version__, self.MESSAGE.format(value=value), - f'(caused by "{rpc_name}")' if rpc_name else "" )) self._raw = _raw From e27726e1d17ef840f0f0525a35c41e1d6e9b54d2 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 20 Jun 2024 07:01:46 +0200 Subject: [PATCH 102/154] Update Pyrogram to v2.1.32.8 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index f4b42de9e2..ab398bfa4c 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.7" +__version__ = "2.1.32.8" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 9b30daaae10b24dbf696f3e12609472ae1ad6238 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Thu, 20 Jun 2024 09:09:15 +0200 Subject: [PATCH 103/154] Update Pyrogram to v2.1.32.9 --- docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/__init__.py | 2 +- pyrogram/methods/messages/edit_message_text.py | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 07db90a029..1a0445f2a3 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.8" +__version__ = "2.1.32.9" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " diff --git a/pyrogram/methods/messages/edit_message_text.py b/pyrogram/methods/messages/edit_message_text.py index 28847e0436..62ad47f507 100644 --- a/pyrogram/methods/messages/edit_message_text.py +++ b/pyrogram/methods/messages/edit_message_text.py @@ -23,6 +23,8 @@ import pyrogram from pyrogram import raw, enums, types, utils +from .inline_session import get_session + log = logging.getLogger(__name__) From 8fc35765d8c4509c980a28344771665fc512cba1 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 1 Jul 2024 15:42:15 +0200 Subject: [PATCH 104/154] Add unknown_error --- compiler/errors/source/400_BAD_REQUEST.tsv | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index f16677a60b..a7670107fe 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -146,6 +146,7 @@ ENTITY_MENTION_USER_INVALID You mentioned an invalid user. ERROR_TEXT_EMPTY The provided error message is empty. EXPIRE_DATE_INVALID The specified expiration date is invalid. EXPORT_CARD_INVALID Provided card is invalid. +EXTENDED_MEDIA_TYPE_INVALID The specified media type is invalid. EXTERNAL_URL_INVALID External URL invalid. FIELD_NAME_EMPTY The field with the name FIELD_NAME is missing FIELD_NAME_INVALID The field with the name FIELD_NAME is invalid From 15d92e6c5b705db7f6082ca888da752eb8dd71c2 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 1 Jul 2024 15:54:39 +0200 Subject: [PATCH 105/154] Update API schema to Layer 183 --- compiler/api/source/main_api.tl | 32 +++++++++++-------- docs/source/releases/changes-in-this-fork.rst | 10 ++++-- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index ce60b0f89a..ad53640dd8 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -1,4 +1,5 @@ // https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/SourceFiles/mtproto/scheme/api.tl +// https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl /////////////////////////////// /////////////////// Layer cons @@ -93,6 +94,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector s inputMediaDice#e66fbf7b emoticon:string = InputMedia; inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; +inputMediaPaidMedia#aa661fc3 stars_amount:long extended_media:Vector = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; @@ -150,7 +152,7 @@ channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5 channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#bbab348d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull; +channelFull#bbab348d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; @@ -182,6 +184,7 @@ messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia; messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:int prize_description:flags.1?string until_date:int = MessageMedia; +messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; @@ -433,7 +436,7 @@ updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; updateRecentEmojiStatuses#30f443db = Update; updateRecentReactions#6f7863f4 = Update; updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = Update; +updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; updateChannelPinnedTopic#192efbe3 flags:# pinned:flags.0?true channel_id:long topic_id:int = Update; updateChannelPinnedTopics#fe198602 flags:# channel_id:long order:flags.0?Vector = Update; updateUser#20529438 user_id:long = Update; @@ -810,7 +813,7 @@ auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeTyp auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#13c90f17 flags:# nonce:flags.0?bytes play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; +auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; @@ -1471,9 +1474,7 @@ attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; -webViewResultUrl#c14557c query_id:long url:string = WebViewResult; - -simpleWebViewResultUrl#882f76bb url:string = SimpleWebViewResult; +webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true query_id:flags.0?long url:string = WebViewResult; webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; @@ -1603,8 +1604,6 @@ botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; -appWebViewResultUrl#3c1b4f0d url:string = AppWebViewResult; - inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; @@ -1852,10 +1851,11 @@ starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; +starsTransactionPeerAds#60682812 = StarsTransactionPeer; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; -starsTransaction#aa00c898 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string = StarsTransaction; +starsTransaction#2db5418f flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector = StarsTransaction; payments.starsStatus#8cf4ee60 flags:# balance:long history:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; @@ -1871,6 +1871,10 @@ payments.starsRevenueStats#c92bb73b revenue_graph:StatsGraph status:StarsRevenue payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; +payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; + +inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2214,9 +2218,9 @@ messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = mes messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; +messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#1a46500a flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult; +messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; @@ -2238,7 +2242,7 @@ messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#8c5a3b3c flags:# write_allowed:flags.0?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = AppWebViewResult; +messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; messages.getSavedDialogs#5381d21a flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; @@ -2418,6 +2422,8 @@ payments.sendStarsForm#2bb731d flags:# form_id:long invoice:InputInvoice = payme payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true peer:InputPeer = payments.StarsRevenueStats; payments.getStarsRevenueWithdrawalUrl#13bbe8b3 peer:InputPeer stars:long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; +payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; +payments.getStarsTransactionsByID#27842d2e peer:InputPeer id:Vector = payments.StarsStatus; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; @@ -2541,4 +2547,4 @@ test.useError = Error; test.useConfigSimple = help.ConfigSimple; test.parseInputAppEvent = InputAppEvent; -// LAYER 182 +// LAYER 183 diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 1a0445f2a3..89e2751dd3 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -10,6 +10,12 @@ it can take advantage of new goodies! If you found any issue or have any suggestions, feel free to make `an issue `_ on github. ++------------------------+ +| Scheme layer used: 183 | ++------------------------+ + +- `View new and changed raw API methods `__. + +------------------------+ | Scheme layer used: 182 | +------------------------+ @@ -43,7 +49,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__. +- `View new and changed raw API methods `__. +------------------------+ | Scheme layer used: 179 | @@ -69,7 +75,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_, `a086b49 `_) -- `View new and changed raw API methods `__. +- `View new and changed raw API methods `__. +------------------------+ | Scheme layer used: 178 | From 7641d3958343bc9b8bbb20e23757235d80977dcb Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 2 Jul 2024 16:17:23 +0200 Subject: [PATCH 106/154] Add unknown_errors and fix a documentation mistake --- compiler/errors/source/400_BAD_REQUEST.tsv | 4 +++- pyrogram/types/messages_and_media/message.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index a7670107fe..5261ea3a65 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -146,7 +146,9 @@ ENTITY_MENTION_USER_INVALID You mentioned an invalid user. ERROR_TEXT_EMPTY The provided error message is empty. EXPIRE_DATE_INVALID The specified expiration date is invalid. EXPORT_CARD_INVALID Provided card is invalid. -EXTENDED_MEDIA_TYPE_INVALID The specified media type is invalid. +EXTENDED_MEDIA_AMOUNT_INVALID The maximum amount of `star_count` should be less than the `stars_paid_post_amount_max` [client configuration parameters](/api/config). +EXTENDED_MEDIA_PEER_INVALID The specified chat type is invalid. +EXTENDED_MEDIA_TYPE_INVALID The specified extended media type is unsupported. EXTERNAL_URL_INVALID External URL invalid. FIELD_NAME_EMPTY The field with the name FIELD_NAME is missing FIELD_NAME_INVALID The field with the name FIELD_NAME is invalid diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index e302bad905..c949bb3fe2 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -90,7 +90,7 @@ class Message(Object, Update): chat (:obj:`~pyrogram.types.Chat`, *optional*): Conversation the message belongs to. - forward_origin (:obj:`~pyrogram.types.User`, *optional*): + forward_origin (:obj:`~pyrogram.types.MessageOrigin`, *optional*): Information about the original message for forwarded messages is_topic_message (``bool``, *optional*): From 1936f094091597879cc6e65146587927184a18e5 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 2 Jul 2024 16:39:51 +0200 Subject: [PATCH 107/154] Added support for launching Web Apps via t.me link in the class MenuButtonWebApp. --- pyrogram/types/bots_and_keyboards/menu_button_web_app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyrogram/types/bots_and_keyboards/menu_button_web_app.py b/pyrogram/types/bots_and_keyboards/menu_button_web_app.py index 109088bbcf..39806216fb 100644 --- a/pyrogram/types/bots_and_keyboards/menu_button_web_app.py +++ b/pyrogram/types/bots_and_keyboards/menu_button_web_app.py @@ -32,6 +32,7 @@ class MenuButtonWebApp(MenuButton): Description of the Web App that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method :meth:`~pyrogram.Client.answer_web_app_query`. + Alternatively, a ``t.me`` link to a Web App of the bot can be specified in the object instead of the Web App's URL, in which case the Web App will be opened as if the user pressed the link. """ def __init__( From 78316b2740aae82998f1df5bec47fc5e734c7d42 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 2 Jul 2024 16:51:52 +0200 Subject: [PATCH 108/154] Added the field can_send_paid_media to the class Chat. --- pyrogram/types/user_and_chats/chat.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 9a1c1045ea..53350c7648 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -117,6 +117,9 @@ class Chat(Object): permissions (:obj:`~pyrogram.types.ChatPermissions` *optional*): Default chat member permissions, for groups and supergroups. + can_send_paid_media (``bool``, *optional*): + True, if paid media messages can be sent or forwarded to the channel chat. The field is available only for channel chats. + slowmode_next_send_date (:py:obj:`~datetime.datetime`, *optional*): Indicates when the user will be allowed to send another message in the chat. For supergroups only. @@ -268,6 +271,7 @@ def __init__( is_forum: bool = None, is_peak_preview: bool = None, max_reaction_count: int = None, + can_send_paid_media: bool = None, _raw: Union[ "raw.types.ChatInvite", "raw.types.Channel", @@ -332,6 +336,7 @@ def __init__( self.business_opening_hours = business_opening_hours self.active_usernames = active_usernames self.max_reaction_count = max_reaction_count + self.can_send_paid_media = can_send_paid_media self._raw = _raw @staticmethod @@ -599,6 +604,8 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. # TODO: Add EmojieStickerSet type parsed_chat.custom_emoji_sticker_set_name = getattr(full_chat.emojiset, "short_name", None) + parsed_chat.can_send_paid_media = getattr(full_chat, "paid_media_allowed", None) + parsed_chat.message_auto_delete_time = getattr(full_chat, "ttl_period") if full_chat.pinned_msg_id: From 14356b87856d62079cfc6a5ed849f0ca633453a5 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 2 Jul 2024 16:56:24 +0200 Subject: [PATCH 109/154] Update Pyrogram to 2.1.32.10 --- docs/source/releases/changes-in-this-fork.rst | 2 ++ pyrogram/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 89e2751dd3..e1b0de8c4c 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,8 @@ If you found any issue or have any suggestions, feel free to make `an issue `__. +------------------------+ diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index aa68f296f4..393c509182 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.9" +__version__ = "2.1.32.10" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 567609f2bbf8e7e337cddd3338b88dfb5899ad40 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 5 Jul 2024 18:56:20 +0200 Subject: [PATCH 110/154] Fix regex filter for PreCheckoutQuery handler --- pyrogram/filters.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index a90af94b9f..2b8f506ae0 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -18,7 +18,7 @@ import inspect import re -from typing import Any, Callable, Literal, Union, List, Pattern +from typing import Any, Callable, List, Literal, Optional, Pattern, Union import pyrogram from pyrogram import enums @@ -990,7 +990,7 @@ async def func(flt, _, update: Update) -> bool: elif isinstance(update, InlineQuery): value: str = update.query elif isinstance(update, PreCheckoutQuery): - value: str = update.payload + value: str = update.invoice_payload else: raise ValueError(f"Regex filter doesn't work with {type(update)}") @@ -1023,7 +1023,7 @@ class user(Filter, set): Defaults to None (no users). """ - def __init__(self, users: Union[int, str, List[Union[int, str]]] = None) -> None: + def __init__(self, users: Optional[Union[int, str, List[Union[int, str]]]] = None) -> None: users = [] if users is None else users if isinstance(users, list) else [users] super().__init__( @@ -1060,7 +1060,7 @@ class chat(Filter, set): Defaults to None (no chats). """ - def __init__(self, chats: Union[int, str, List[Union[int, str]]] = None) -> None: + def __init__(self, chats: Optional[Union[int, str, List[Union[int, str]]]] = None) -> None: chats = [] if chats is None else chats if isinstance(chats, list) else [chats] super().__init__( From f63b0c899da9a38884e350ea90ce716d7e907093 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 5 Jul 2024 19:04:35 +0200 Subject: [PATCH 111/154] Add message thread filter Git-Origin-Commit-Id: 0f52536 Co-authored-by: KurimuzonAkuma --- pyrogram/filters.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index 2b8f506ae0..b2a2990fdb 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -1107,3 +1107,26 @@ async def __call__(self, _, message: Message) -> bool: """Filter service messages for chat shared.""" # endregion + +# noinspection PyPep8Naming +class thread(Filter, set): + """Filter messages coming from one or more threads. + + You can use `set bound methods `_ to manipulate the + message_thread_ids container. + + Parameters: + message_thread_ids (``int`` | ``list``): + Pass one or more message thread ids to filter messages in specific threads. + Defaults to None (no threads). + """ + + def __init__(self, message_thread_ids: Optional[Union[int, List[int]]] = None): + message_thread_ids = [] if message_thread_ids is None else message_thread_ids if isinstance(message_thread_ids, list) else [message_thread_ids] + + super().__init__( + t for t in message_thread_ids + ) + + async def __call__(self, _, message: Message): + return message.message_thread_id and message.message_thread_id in self From 48152df9970ddd6e306e4475b10340521af29aa4 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 5 Jul 2024 19:18:01 +0200 Subject: [PATCH 112/154] Rename hashtag methods search_public_messages_by_tag count_public_messages_by_tag --- compiler/docs/compiler.py | 4 ++-- docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/methods/messages/__init__.py | 8 ++++---- ..._count.py => count_public_messages_by_tag.py} | 10 +++++----- ...sages.py => search_public_messages_by_tag.py} | 16 ++++++++-------- 5 files changed, 20 insertions(+), 20 deletions(-) rename pyrogram/methods/messages/{search_public_hashtag_messages_count.py => count_public_messages_by_tag.py} (89%) rename pyrogram/methods/messages/{search_public_hashtag_messages.py => search_public_messages_by_tag.py} (85%) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index a48b658bc0..3af783670f 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -311,8 +311,8 @@ def get_title_list(s: str) -> list: search_global_count search_messages search_messages_count - search_public_hashtag_messages - search_public_hashtag_messages_count + search_public_messages_by_tag + count_public_messages_by_tag send_animation send_audio send_cached_media diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index e1b0de8c4c..a6d7f8e4bc 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -42,7 +42,7 @@ If you found any issue or have any suggestions, feel free to make `an issue int: """Get the count of messages with the provided hashtag or cashtag. - If you want to get the actual messages, see :meth:`~pyrogram.Client.search_public_hashtag_messages`. + If you want to get the actual messages, see :meth:`~pyrogram.Client.search_public_messages_by_tag`. .. include:: /_includes/usable-by/users.rst @@ -41,7 +41,7 @@ async def search_public_hashtag_messages_count( """ r = await self.invoke( raw.functions.channels.SearchPosts( - hashtag=hashtag, + hashtag=tag, offset_rate=0, offset_peer=raw.types.InputPeerEmpty(), offset_id=0, diff --git a/pyrogram/methods/messages/search_public_hashtag_messages.py b/pyrogram/methods/messages/search_public_messages_by_tag.py similarity index 85% rename from pyrogram/methods/messages/search_public_hashtag_messages.py rename to pyrogram/methods/messages/search_public_messages_by_tag.py index fc512d4fc4..b42e8fdf23 100644 --- a/pyrogram/methods/messages/search_public_hashtag_messages.py +++ b/pyrogram/methods/messages/search_public_messages_by_tag.py @@ -23,22 +23,22 @@ from pyrogram import raw, types, utils -class SearchPublicHashtagMessages: - async def search_public_hashtag_messages( +class SearchPublicMessagesByTag: + async def search_public_messages_by_tag( self: "pyrogram.Client", - hashtag: str = "", + tag: str = "", offset_id: int = 0, offset_date: datetime = utils.zero_datetime(), limit: int = 0, ) -> AsyncGenerator["types.Message", None]: - """Searches for public channel posts with the given hashtag or cashtag. For optimal performance, the number of returned messages is chosen by Telegram Server and can be smaller than the specified limit. + """Searches for public channel posts containing the given hashtag or cashtag. For optimal performance, the number of returned messages is chosen by Telegram Server and can be smaller than the specified limit. - If you want to get the posts count only, see :meth:`~pyrogram.Client.search_public_hashtag_messages_count`. + If you want to get the posts count only, see :meth:`~pyrogram.Client.count_public_messages_by_tag`. .. include:: /_includes/usable-by/users.rst Parameters: - hashtag (``str``, *optional*): + tag (``str``, *optional*): Hashtag or cashtag to search for. offset_id (``int``, *optional*): @@ -58,7 +58,7 @@ async def search_public_hashtag_messages( .. code-block:: python # Search for "#pyrogram". Get the first 50 results - async for message in app.search_public_hashtag_messages("pyrogram", limit=50): + async for message in app.search_public_messages_by_tag("pyrogram", limit=50): print(message.text) """ @@ -73,7 +73,7 @@ async def search_public_hashtag_messages( self, await self.invoke( raw.functions.channels.SearchPosts( - hashtag=hashtag, + hashtag=tag, offset_rate=utils.datetime_to_timestamp(offset_date), offset_peer=offset_peer, offset_id=offset_id, From eecadbc6e5846d2cff5e8bb5c567120ba809ed17 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 5 Jul 2024 19:27:14 +0200 Subject: [PATCH 113/154] Add self_destruct filter Co-authored-by: KurimuzonAkuma --- pyrogram/filters.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index b2a2990fdb..1e551aebd8 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -1130,3 +1130,27 @@ def __init__(self, message_thread_ids: Optional[Union[int, List[int]]] = None): async def __call__(self, _, message: Message): return message.message_thread_id and message.message_thread_id in self + + +# region self_destruct_filter + +async def self_destruct_filter(_, __, m: Message): + return bool( + m.media and + getattr( + getattr( + m, + m.media.value, + None + ), + "ttl_seconds", + None + ) + ) + + +self_destruct = create(self_destruct_filter) +"""Filter self destruct media messages.""" + + +# endregion From 394792709c197e616d75efd3fe44375f67de041c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 5 Jul 2024 20:00:53 +0530 Subject: [PATCH 114/154] Add get_stories to get story information from identifiers (#47) --- compiler/docs/compiler.py | 4 + compiler/docs/template/methods.rst | 13 +++ docs/source/releases/changes-in-this-fork.rst | 2 + pyrogram/dispatcher.py | 3 +- pyrogram/methods/__init__.py | 2 + pyrogram/methods/stories/__init__.py | 25 ++++++ pyrogram/methods/stories/get_stories.py | 89 +++++++++++++++++++ .../external_reply_info.py | 2 +- pyrogram/types/messages_and_media/message.py | 4 +- pyrogram/types/messages_and_media/story.py | 31 ++++++- 10 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 pyrogram/methods/stories/__init__.py create mode 100644 pyrogram/methods/stories/get_stories.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 3af783670f..e3ffae3897 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -359,6 +359,10 @@ def get_title_list(s: str) -> list: get_message_effects get_stickers """, + stories=""" + Stories + get_stories + """, users=""" Users get_me diff --git a/compiler/docs/template/methods.rst b/compiler/docs/template/methods.rst index 05ccf463b0..460beae9e7 100644 --- a/compiler/docs/template/methods.rst +++ b/compiler/docs/template/methods.rst @@ -151,6 +151,19 @@ Stickers {stickers} +Stories +-------- + +.. autosummary:: + :nosignatures: + + {stories} + +.. toctree:: + :hidden: + + {stories} + Password -------- diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index a6d7f8e4bc..57a9e9038b 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,8 @@ If you found any issue or have any suggestions, feel free to make `an issue `__. diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py index e7758063d8..d461c0707d 100644 --- a/pyrogram/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -200,7 +200,8 @@ async def story_parser(update, users, chats): users, chats, None, None, - update + update, + None, None ), StoryHandler ) diff --git a/pyrogram/methods/__init__.py b/pyrogram/methods/__init__.py index c7a392df94..9f0f11b1f0 100644 --- a/pyrogram/methods/__init__.py +++ b/pyrogram/methods/__init__.py @@ -28,6 +28,7 @@ from .password import Password from .phone import Phone from .stickers import Stickers +from .stories import Stories from .users import Users from .utilities import Utilities from .business import TelegramBusiness @@ -46,6 +47,7 @@ class Methods( Password, Phone, Stickers, + Stories, TelegramBusiness, Users, Utilities, diff --git a/pyrogram/methods/stories/__init__.py b/pyrogram/methods/stories/__init__.py new file mode 100644 index 0000000000..b7c0c724a1 --- /dev/null +++ b/pyrogram/methods/stories/__init__.py @@ -0,0 +1,25 @@ +# 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 .get_stories import GetStories + +class Stories( + GetStories, +): + pass diff --git a/pyrogram/methods/stories/get_stories.py b/pyrogram/methods/stories/get_stories.py new file mode 100644 index 0000000000..88f6fa77a8 --- /dev/null +++ b/pyrogram/methods/stories/get_stories.py @@ -0,0 +1,89 @@ +# 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 Union, Iterable + +import pyrogram +from pyrogram import raw, types + + +class GetStories: + async def get_stories( + self: "pyrogram.Client", + story_sender_chat_id: Union[int, str], + story_ids: Union[int, Iterable[int]], + ) -> "types.Story": + """Get one or more stories from a chat by using stories identifiers. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + story_sender_chat_id (``int`` | ``str``): + Identifier of the chat that posted the story. + + story_ids (``int`` | Iterable of ``int``, *optional*): + Pass a single story identifier or an iterable of story ids (as integers) to get the content of the + story themselves. + + Returns: + :obj:`~pyrogram.types.Story` | List of :obj:`~pyrogram.types.Story`: In case *story_ids* was not + a list, a single story is returned, otherwise a list of stories is returned. + + Example: + .. code-block:: python + + # Get stories by id + stories = await app.get_stories( + story_sender_chat_id, + [1, 2, 3] + ) + + for story in stories: + print(story) + """ + is_iterable = not isinstance(story_ids, int) + ids = list(story_ids) if is_iterable else [story_ids] + + peer = await self.resolve_peer(story_sender_chat_id) + r = await self.invoke( + raw.functions.stories.GetStoriesByID( + peer=peer, + id=ids + ) + ) + + stories = [] + + users = {i.id: i for i in r.users} + chats = {i.id: i for i in r.chats} + + for story in r.stories: + stories.append( + await types.Story._parse( + self, + users, + chats, + None, None, None, + # TODO + story, + None, # + # TODO + ) + ) + + return types.List(stories) if is_iterable else stories[0] if stories else None diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index 5074a1ca49..8651dd0b4a 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -291,7 +291,7 @@ async def _parse( dice = types.Dice._parse(client, media) media_type = enums.MessageMediaType.DICE elif isinstance(media, raw.types.MessageMediaStory): - story = await types.Story._parse(client, users, chats, media, None, None) + story = await types.Story._parse(client, users, chats, media, None, None, None, None) media_type = enums.MessageMediaType.STORY elif isinstance(media, raw.types.MessageMediaGiveaway): giveaway = types.Giveaway._parse(client, chats, media) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index c949bb3fe2..aea8a46899 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1121,7 +1121,7 @@ async def _parse( dice = types.Dice._parse(client, media) media_type = enums.MessageMediaType.DICE elif isinstance(media, raw.types.MessageMediaStory): - story = await types.Story._parse(client, users, chats, media, None, None) + story = await types.Story._parse(client, users, chats, media, None, None, None, None) media_type = enums.MessageMediaType.STORY elif isinstance(media, raw.types.MessageMediaGiveaway): giveaway = types.Giveaway._parse(client, chats, media) @@ -1267,7 +1267,7 @@ async def _parse( ) if isinstance(message.reply_to, raw.types.MessageReplyStoryHeader): - parsed_message.reply_to_story = await types.Story._parse(client, users, chats, None, message.reply_to, None) + parsed_message.reply_to_story = await types.Story._parse(client, users, chats, None, message.reply_to, None, None, None) if replies: try: diff --git a/pyrogram/types/messages_and_media/story.py b/pyrogram/types/messages_and_media/story.py index 5aa3171972..3a44359c91 100644 --- a/pyrogram/types/messages_and_media/story.py +++ b/pyrogram/types/messages_and_media/story.py @@ -206,7 +206,9 @@ async def _parse( chats: dict, story_media: "raw.types.MessageMediaStory", reply_story: "raw.types.MessageReplyStoryHeader", - story_update: "raw.types.UpdateStory" + story_update: "raw.types.UpdateStory", + story_item: "raw.types.StoryItem", + peer: "raw.base.peer" ) -> "Story": story_id = None chat = None @@ -310,6 +312,33 @@ async def _parse( deleted ) = Story._parse_story_item(client, story_update.story) + if peer: + raw_peer_id = utils.get_raw_peer_id(peer) + if isinstance(peer, raw.types.PeerUser): + chat = types.Chat._parse_chat(client, users.get(raw_peer_id)) + else: + chat = types.Chat._parse_chat(client, chats.get(raw_peer_id)) + + if story_item: + story_id = getattr(story_item, "id", None) + ( + date, + expire_date, + media, + has_protected_content, + photo, + video, + edited, + pinned, + caption, + caption_entities, + views, + forwards, + reactions, + skipped, + deleted + ) = Story._parse_story_item(client, story_item) + return Story( client=client, _raw=rawupdate, From 2799992fe3207f701afa480ae4836e0b8d761d4f Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Sun, 7 Jul 2024 16:07:41 +0530 Subject: [PATCH 115/154] paid_media (#48) --- compiler/docs/compiler.py | 12 + compiler/docs/template/types.rst | 13 + docs/source/releases/changes-in-this-fork.rst | 3 + pyrogram/enums/message_media_type.py | 3 + pyrogram/methods/messages/__init__.py | 2 + pyrogram/methods/messages/copy_message.py | 2 + pyrogram/methods/messages/send_paid_media.py | 274 ++++++++++++++++++ pyrogram/types/__init__.py | 1 + .../external_reply_info.py | 10 + pyrogram/types/input_paid_media/__init__.py | 37 +++ .../input_paid_media/input_paid_media.py | 39 +++ .../input_paid_media_photo.py | 45 +++ .../input_paid_media_video.py | 73 +++++ pyrogram/types/input_paid_media/paid_media.py | 94 ++++++ .../types/input_paid_media/paid_media_info.py | 61 ++++ .../input_paid_media/paid_media_photo.py | 42 +++ .../input_paid_media/paid_media_preview.py | 57 ++++ .../input_paid_media/paid_media_video.py | 42 +++ pyrogram/types/messages_and_media/message.py | 12 +- pyrogram/types/object.py | 3 + pyrogram/types/user_and_chats/chat_photo.py | 1 + 21 files changed, 825 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/messages/send_paid_media.py create mode 100644 pyrogram/types/input_paid_media/__init__.py create mode 100644 pyrogram/types/input_paid_media/input_paid_media.py create mode 100644 pyrogram/types/input_paid_media/input_paid_media_photo.py create mode 100644 pyrogram/types/input_paid_media/input_paid_media_video.py create mode 100644 pyrogram/types/input_paid_media/paid_media.py create mode 100644 pyrogram/types/input_paid_media/paid_media_info.py create mode 100644 pyrogram/types/input_paid_media/paid_media_photo.py create mode 100644 pyrogram/types/input_paid_media/paid_media_preview.py create mode 100644 pyrogram/types/input_paid_media/paid_media_video.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index e3ffae3897..2416cfa767 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -321,6 +321,7 @@ def get_title_list(s: str) -> list: send_dice send_document send_location + send_paid_media send_media_group send_message send_photo @@ -515,6 +516,17 @@ def get_title_list(s: str) -> list: InputPhoneContact LinkPreviewOptions """, + input_paid_media=""" + Input Paid Media + InputPaidMedia + InputPaidMediaPhoto + InputPaidMediaVideo + PaidMediaInfo + PaidMedia + PaidMediaPreview + PaidMediaPhoto + PaidMediaVideo + """, input_message_content=""" InputMessageContent ExternalReplyInfo diff --git a/compiler/docs/template/types.rst b/compiler/docs/template/types.rst index ebebe0780d..7fe8f57d73 100644 --- a/compiler/docs/template/types.rst +++ b/compiler/docs/template/types.rst @@ -86,6 +86,19 @@ Input Media {input_media} +Input Paid Media +----------- + +.. autosummary:: + :nosignatures: + + {input_paid_media} + +.. toctree:: + :hidden: + + {input_paid_media} + Inline Mode ----------- diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 57a9e9038b..75d9ee0cae 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,9 @@ If you found any issue or have any suggestions, feel free to make `an issue "types.Message": """Copy messages of any kind. + Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field ``correct_option_id`` is known to the bot. + The method is analogous to the method :meth:`~Client.forward_messages`, but the copied message doesn't have a link to the original message. diff --git a/pyrogram/methods/messages/send_paid_media.py b/pyrogram/methods/messages/send_paid_media.py new file mode 100644 index 0000000000..f0f3134510 --- /dev/null +++ b/pyrogram/methods/messages/send_paid_media.py @@ -0,0 +1,274 @@ +# 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 . + +import os +import re + +from datetime import datetime +from typing import Union, List, Optional + +import pyrogram +from pyrogram import enums, raw, types, utils +from pyrogram.file_id import FileType + + +class SendPaidMedia: + async def send_paid_media( + self: "pyrogram.Client", + chat_id: Union[int, str], + star_count: int, + media: List[Union[ + "types.InputPaidMediaPhoto", + "types.InputPaidMediaVideo" + ]], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, + disable_notification: bool = None, + protect_content: bool = None, + reply_parameters: "types.ReplyParameters" = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + schedule_date: datetime = None + ) -> "types.Message": + """Use this method to send paid media to channel chats. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target channel (in the format @channelusername). + + star_count (``int``): + The number of Telegram Stars that must be paid to buy access to the media. + + media (List of :obj:`~pyrogram.types.InputPaidMedia`): + A list describing the media to be sent; up to 10 items. + + caption (``str``, *optional*): + Media caption, 0-1024 characters after entities parsing. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + + disable_notification (``bool``, *optional*): + Sends the message silently. Users will receive a notification with no sound. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): + Description of the message to reply to + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): + Additional interface options. An object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + + schedule_date (:obj:`~datetime.datetime`, *optional*): + Date when the message will be automatically sent. Pass a :obj:`~datetime.datetime` object. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent message is returned. + + """ + multi_media = [] + + peer = await self.resolve_peer(chat_id) + for i in media: + if isinstance(i, types.InputPaidMediaPhoto): + if isinstance(i.media, str): + if os.path.isfile(i.media): + media = await self.invoke( + raw.functions.messages.UploadMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaUploadedPhoto( + file=await self.save_file(i.media) + ) + ) + ) + + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.file_reference + ) + ) + elif re.match("^https?://", i.media): + media = await self.invoke( + raw.functions.messages.UploadMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaPhotoExternal( + url=i.media + ) + ) + ) + + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.file_reference + ) + ) + else: + media = utils.get_input_media_from_file_id(i.media, FileType.PHOTO) + else: + media = await self.invoke( + raw.functions.messages.UploadMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaUploadedPhoto( + file=await self.save_file(i.media) + ) + ) + ) + + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.file_reference + ) + ) + elif ( + isinstance(i, types.InputPaidMediaVideo) + ): + if isinstance(i.media, str): + if os.path.isfile(i.media): + attributes = [ + raw.types.DocumentAttributeVideo( + supports_streaming=i.supports_streaming or None, + duration=i.duration, + w=i.width, + h=i.height + ), + raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)) + ] + media = await self.invoke( + raw.functions.messages.UploadMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaUploadedDocument( + file=await self.save_file(i.media), + thumb=await self.save_file(i.thumbnail), + mime_type=self.guess_mime_type(i.media) or "video/mp4", + nosound_video=True, + attributes=attributes + ) + ) + ) + + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference + ) + ) + elif re.match("^https?://", i.media): + media = await self.invoke( + raw.functions.messages.UploadMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaDocumentExternal( + url=i.media + ) + ) + ) + + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference + ) + ) + else: + media = utils.get_input_media_from_file_id(i.media, FileType.VIDEO) + else: + media = await self.invoke( + raw.functions.messages.UploadMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaUploadedDocument( + file=await self.save_file(i.media), + thumb=await self.save_file(i.thumbnail), + mime_type=self.guess_mime_type(getattr(i.media, "name", "video.mp4")) or "video/mp4", + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=i.supports_streaming or None, + duration=i.duration, + w=i.width, + h=i.height + ), + raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "video.mp4")) + ] + ) + ) + ) + + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference + ) + ) + else: + raise ValueError(f"{i.__class__.__name__} is not a supported type for send_paid_media") + multi_media.append(media) + + rpc = raw.functions.messages.SendMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaPaidMedia( + stars_amount=star_count, + extended_media=multi_media + ), + silent=disable_notification or None, + random_id=self.rnd_id(), + schedule_date=utils.datetime_to_timestamp(schedule_date), + noforwards=protect_content, + invert_media=show_caption_above_media, + **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) + ) + r = await self.invoke(rpc, sleep_threshold=60) + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage + ) + ): + return await types.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies + ) diff --git a/pyrogram/types/__init__.py b/pyrogram/types/__init__.py index 059d37fb90..849e32528d 100644 --- a/pyrogram/types/__init__.py +++ b/pyrogram/types/__init__.py @@ -24,6 +24,7 @@ from .chat_topics import * from .inline_mode import * from .input_media import * +from .input_paid_media import * from .input_message_content import * from .messages_and_media import * from .message_origin import * diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index 8651dd0b4a..8a69f3270b 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -49,6 +49,9 @@ class ExternalReplyInfo(Object): document (:obj:`~pyrogram.types.Document`, *optional*): Message is a general file, information about the file. + paid_media (:obj:`~pyrogram.types.PaidMediaInfo`, *optional*): + Message contains paid media; information about the paid media. + photo (:obj:`~pyrogram.types.Photo`, *optional*): Message is a photo, information about the photo. @@ -109,6 +112,7 @@ def __init__( animation: "types.Animation" = None, audio: "types.Audio" = None, document: "types.Document" = None, + paid_media: "types.PaidMediaInfo" = None, photo: "types.Photo" = None, sticker: "types.Sticker" = None, story: "types.Story" = None, @@ -135,6 +139,7 @@ def __init__( self.animation = animation self.audio = audio self.document = document + self.paid_media = paid_media self.photo = photo self.sticker = sticker self.story = story @@ -183,6 +188,7 @@ async def _parse( animation = None audio = None document = None + paid_media = None photo = None sticker = None story = None @@ -302,6 +308,9 @@ async def _parse( elif isinstance(media, raw.types.MessageMediaInvoice): invoice = types.Invoice._parse(client, media) media_type = enums.MessageMediaType.INVOICE + elif isinstance(media, raw.types.MessageMediaPaidMedia): + paid_media = types.PaidMediaInfo._parse(client, media) + media_type = enums.MessageMediaType.PAID_MEDIA return ExternalReplyInfo( origin=origin, @@ -311,6 +320,7 @@ async def _parse( animation=animation, audio=audio, document=document, + paid_media=paid_media, photo=photo, sticker=sticker, story=story, diff --git a/pyrogram/types/input_paid_media/__init__.py b/pyrogram/types/input_paid_media/__init__.py new file mode 100644 index 0000000000..574b78f61c --- /dev/null +++ b/pyrogram/types/input_paid_media/__init__.py @@ -0,0 +1,37 @@ +# 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 .input_paid_media import InputPaidMedia +from .input_paid_media_photo import InputPaidMediaPhoto +from .input_paid_media_video import InputPaidMediaVideo +from .paid_media_info import PaidMediaInfo +from .paid_media import PaidMedia +from .paid_media_preview import PaidMediaPreview +from .paid_media_photo import PaidMediaPhoto +from .paid_media_video import PaidMediaVideo + +__all__ = [ + "InputPaidMedia", + "InputPaidMediaPhoto", + "InputPaidMediaVideo", + "PaidMediaInfo", + "PaidMedia", + "PaidMediaPreview", + "PaidMediaPhoto", + "PaidMediaVideo", +] diff --git a/pyrogram/types/input_paid_media/input_paid_media.py b/pyrogram/types/input_paid_media/input_paid_media.py new file mode 100644 index 0000000000..f25e64d926 --- /dev/null +++ b/pyrogram/types/input_paid_media/input_paid_media.py @@ -0,0 +1,39 @@ +# 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 Union, BinaryIO + +from ..object import Object + + +class InputPaidMedia(Object): + """This object describes the paid media to be sent. + + Currently, it can be one of: + + - :obj:`~pyrogram.types.InputMediaPhoto` + - :obj:`~pyrogram.types.InputMediaVideo` + """ + + def __init__( + self, + media: Union[str, BinaryIO] + ): + super().__init__() + + self.media = media diff --git a/pyrogram/types/input_paid_media/input_paid_media_photo.py b/pyrogram/types/input_paid_media/input_paid_media_photo.py new file mode 100644 index 0000000000..765fd13e26 --- /dev/null +++ b/pyrogram/types/input_paid_media/input_paid_media_photo.py @@ -0,0 +1,45 @@ +# 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 Optional, List, Union, BinaryIO + +from .input_paid_media import InputPaidMedia +from ... import enums + + +class InputPaidMediaPhoto(InputPaidMedia): + """The paid media to send is a photo. + + It is intended to be used with :obj:`~pyrogram.Client.send_paid_media`. + + Parameters: + media (``str`` | ``BinaryIO``): + Photo to send. + Pass a file_id as string to send a photo that exists on the Telegram servers or + pass a file path as string to upload a new photo that exists on your local machine or + pass a binary file-like object with its attribute “.name” set for in-memory uploads or + pass an HTTP URL as a string for Telegram to get a photo from the Internet. + + """ + + def __init__( + self, + media: Union[str, BinaryIO] + ): + super().__init__(media) + diff --git a/pyrogram/types/input_paid_media/input_paid_media_video.py b/pyrogram/types/input_paid_media/input_paid_media_video.py new file mode 100644 index 0000000000..a4e4bce77c --- /dev/null +++ b/pyrogram/types/input_paid_media/input_paid_media_video.py @@ -0,0 +1,73 @@ +# 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 Optional, List, Union, BinaryIO + +from .input_paid_media import InputPaidMedia +from ... import enums + + +class InputPaidMediaVideo(InputPaidMedia): + """The paid media to send is a video. + + It is intended to be used with :obj:`~pyrogram.Client.send_paid_media`. + + Parameters: + media (``str`` | ``BinaryIO``): + File to send. + Pass a file_id as string to send a video that exists on the Telegram servers or + pass a file path as string to upload a new video that exists on your local machine or + pass a binary file-like object with its attribute “.name” set for in-memory uploads or + pass an HTTP URL as a string for Telegram to get a video from the Internet. + + thumbnail (``str`` | ``BinaryIO``): + Thumbnail of the video sent. + The thumbnail should be in JPEG format and less than 200 KB in size. + A thumbnail's width and height should not exceed 320 pixels. + Thumbnails can't be reused and can be only uploaded as a new file. + + width (``int``, *optional*): + Video width. + + height (``int``, *optional*): + Video height. + + duration (``int``, *optional*): + Video duration. + + supports_streaming (``bool``, *optional*): + Pass True, if the uploaded video is suitable for streaming. + + """ + + def __init__( + self, + media: Union[str, BinaryIO], + thumbnail: Union[str, BinaryIO] = None, + width: int = 0, + height: int = 0, + duration: int = 0, + supports_streaming: bool = True + ): + super().__init__(media) + + self.thumbnail = thumbnail + self.width = width + self.height = height + self.duration = duration + self.supports_streaming = supports_streaming diff --git a/pyrogram/types/input_paid_media/paid_media.py b/pyrogram/types/input_paid_media/paid_media.py new file mode 100644 index 0000000000..f4e5c3b7bf --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media.py @@ -0,0 +1,94 @@ +# 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 Union + +import pyrogram +from pyrogram import raw, types + +from ..object import Object + + +class PaidMedia(Object): + """This object describes paid media. + + Currently, it can be one of: + + - :obj:`~pyrogram.types.PaidMediaPreview` + - :obj:`~pyrogram.types.PaidMediaPhoto` + - :obj:`~pyrogram.types.PaidMediaVideo` + """ + + def __init__( + self + ): + super().__init__() + + + @staticmethod + def _parse( + client: "pyrogram.Client", + extended_media: Union[ + "raw.types.MessageExtendedMediaPreview", + "raw.types.MessageExtendedMedia" + ] + ) -> "PaidMedia": + if isinstance(extended_media, raw.types.MessageExtendedMediaPreview): + return types.PaidMediaPreview( + width=getattr(extended_media, "w", None), + height=getattr(extended_media, "h", None), + duration=getattr(extended_media, "video_duration", None), + minithumbnail=types.StrippedThumbnail( + client=client, + data=extended_media.thumb + ) if getattr(extended_media, "thumb", None) else None + ) + if isinstance(extended_media, raw.types.MessageExtendedMedia): + media = extended_media.media + + has_media_spoiler = getattr(media, "spoiler", None) + ttl_seconds = getattr(media, "ttl_seconds", None) + + if isinstance(media, raw.types.MessageMediaPhoto): + photo = types.Photo._parse(client, media.photo, ttl_seconds, has_media_spoiler) + + return types.PaidMediaPhoto( + photo=photo + ) + + if isinstance(media, raw.types.MessageMediaDocument): + doc = media.document + + if isinstance(doc, raw.types.Document): + attributes = {type(i): i for i in doc.attributes} + + file_name = getattr( + attributes.get( + raw.types.DocumentAttributeFilename, None + ), "file_name", None + ) + + if raw.types.DocumentAttributeVideo in attributes: + video_attributes = attributes[raw.types.DocumentAttributeVideo] + + if not video_attributes.round_message: + video = types.Video._parse(client, doc, video_attributes, file_name, ttl_seconds) + + return types.PaidMediaVideo( + video=video + ) diff --git a/pyrogram/types/input_paid_media/paid_media_info.py b/pyrogram/types/input_paid_media/paid_media_info.py new file mode 100644 index 0000000000..ef2d9d537c --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_info.py @@ -0,0 +1,61 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import List + +import pyrogram +from pyrogram import raw, types +from ..object import Object + + +class PaidMediaInfo(Object): + """Describes the paid media added to a message. + + Parameters: + star_count (``int``): + The number of Telegram Stars that must be paid to buy access to the media. + + paid_media (List of :obj:`~pyrogram.types.PaidMedia`): + Information about the paid media. + + """ + + def __init__( + self, + *, + star_count: str, + paid_media: List["types.PaidMedia"] + ): + super().__init__() + + self.star_count = star_count + self.paid_media = paid_media + + + @staticmethod + def _parse( + client: "pyrogram.Client", + message_paid_media: "raw.types.MessageMediaPaidMedia" + ) -> "PaidMediaInfo": + return PaidMediaInfo( + star_count=message_paid_media.stars_amount, + paid_media=[ + types.PaidMedia._parse(client, em) + for em in message_paid_media.extended_media + ] + ) diff --git a/pyrogram/types/input_paid_media/paid_media_photo.py b/pyrogram/types/input_paid_media/paid_media_photo.py new file mode 100644 index 0000000000..0f06335743 --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_photo.py @@ -0,0 +1,42 @@ +# 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 . + +import pyrogram +from pyrogram import types + +from ..object import Object +from .paid_media import PaidMedia + + +class PaidMediaPhoto(PaidMedia): + """The paid media is a photo. + + Parameters: + photo (:obj:`~pyrogram.types.Photo`): + The photo. + + """ + + def __init__( + self, + *, + photo: "types.Photo" = None + ): + super().__init__() + + self.photo = photo diff --git a/pyrogram/types/input_paid_media/paid_media_preview.py b/pyrogram/types/input_paid_media/paid_media_preview.py new file mode 100644 index 0000000000..90cc878cc1 --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_preview.py @@ -0,0 +1,57 @@ +# 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 . + +import pyrogram +from pyrogram import types + +from ..object import Object +from .paid_media import PaidMedia + + +class PaidMediaPreview(PaidMedia): + """The paid media isn't available before the payment. + + Parameters: + width (``int``, *optional*): + Media width as defined by the sender. + + height (``int``, *optional*): + Media height as defined by the sender. + + duration (``int``, *optional*): + Duration of the media in seconds as defined by the sender. + + minithumbnail (:obj:`~pyrogram.types.StrippedThumbnail`, *optional*): + Media minithumbnail; may be None. + + """ + + def __init__( + self, + *, + width: int = None, + height: int = None, + duration: int = None, + minithumbnail: "types.StrippedThumbnail" = None + ): + super().__init__() + + self.width = width + self.height = height + self.duration = duration + self.minithumbnail = minithumbnail diff --git a/pyrogram/types/input_paid_media/paid_media_video.py b/pyrogram/types/input_paid_media/paid_media_video.py new file mode 100644 index 0000000000..cbdfbcf5c5 --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_video.py @@ -0,0 +1,42 @@ +# 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 . + +import pyrogram +from pyrogram import types + +from ..object import Object +from .paid_media import PaidMedia + + +class PaidMediaVideo(PaidMedia): + """The paid media is a video. + + Parameters: + video (:obj:`~pyrogram.types.Video`): + The video. + + """ + + def __init__( + self, + *, + video: "types.Video" = None + ): + super().__init__() + + self.video = video diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index aea8a46899..d69b1da2ee 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -158,6 +158,9 @@ class Message(Object, Update): document (:obj:`~pyrogram.types.Document`, *optional*): Message is a general file, information about the file. + paid_media (:obj:`~pyrogram.types.PaidMediaInfo`, *optional*): + Message contains paid media; information about the paid media. + photo (:obj:`~pyrogram.types.Photo`, *optional*): Message is a photo, information about the photo. @@ -432,6 +435,7 @@ def __init__( animation: "types.Animation" = None, audio: "types.Audio" = None, document: "types.Document" = None, + paid_media: "types.PaidMediaInfo" = None, photo: "types.Photo" = None, sticker: "types.Sticker" = None, story: "types.Story" = None, @@ -612,6 +616,7 @@ def __init__( self.sender_business_bot = sender_business_bot self.business_connection_id = business_connection_id self.successful_payment = successful_payment + self.paid_media = paid_media self._raw = _raw @staticmethod @@ -1015,6 +1020,7 @@ async def _parse( giveaway = None giveaway_winners = None invoice = None + paid_media = None media = message.media media_type = None @@ -1132,6 +1138,9 @@ async def _parse( elif isinstance(media, raw.types.MessageMediaInvoice): invoice = types.Invoice._parse(client, media) media_type = enums.MessageMediaType.INVOICE + elif isinstance(media, raw.types.MessageMediaPaidMedia): + paid_media = types.PaidMediaInfo._parse(client, media) + media_type = enums.MessageMediaType.PAID_MEDIA else: media = None @@ -1230,7 +1239,8 @@ async def _parse( client=client, link_preview_options=link_preview_options, effect_id=getattr(message, "effect", None), - show_caption_above_media=show_caption_above_media + show_caption_above_media=show_caption_above_media, + paid_media=paid_media ) parsed_message.external_reply = await types.ExternalReplyInfo._parse( diff --git a/pyrogram/types/object.py b/pyrogram/types/object.py index 3253c8ecff..8eaf6aeae3 100644 --- a/pyrogram/types/object.py +++ b/pyrogram/types/object.py @@ -60,6 +60,9 @@ def default(obj: "Object"): if isinstance(obj, datetime): return str(obj) + if not hasattr(obj, "__dict__"): + return obj.__class__.__name__ + return { "_": obj.__class__.__name__, **{ diff --git a/pyrogram/types/user_and_chats/chat_photo.py b/pyrogram/types/user_and_chats/chat_photo.py index 4234b9767b..7d805fc694 100644 --- a/pyrogram/types/user_and_chats/chat_photo.py +++ b/pyrogram/types/user_and_chats/chat_photo.py @@ -121,6 +121,7 @@ def _parse( has_animation=chat_photo.has_video, is_personal=getattr(chat_photo, "personal", False), minithumbnail=types.StrippedThumbnail( + client=client, data=chat_photo.stripped_thumb ) if chat_photo.stripped_thumb else None, client=client From 72ab93dab3284581ee5d153fe6396732fea93a3c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 7 Jul 2024 12:38:52 +0200 Subject: [PATCH 116/154] Update Pyrogram to 2.1.32.11 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 393c509182..2440329eca 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.10" +__version__ = "2.1.32.11" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 0d368028421d979af3ef477a943a38996cd6463e Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 7 Jul 2024 16:58:44 +0200 Subject: [PATCH 117/154] Fix spelling mistake in documentation --- pyrogram/types/input_paid_media/input_paid_media.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/input_paid_media/input_paid_media.py b/pyrogram/types/input_paid_media/input_paid_media.py index f25e64d926..79a627e99b 100644 --- a/pyrogram/types/input_paid_media/input_paid_media.py +++ b/pyrogram/types/input_paid_media/input_paid_media.py @@ -26,8 +26,8 @@ class InputPaidMedia(Object): Currently, it can be one of: - - :obj:`~pyrogram.types.InputMediaPhoto` - - :obj:`~pyrogram.types.InputMediaVideo` + - :obj:`~pyrogram.types.InputPaidMediaPhoto` + - :obj:`~pyrogram.types.InputPaidMediaVideo` """ def __init__( From 671f73a97e6ec96e5d1fcfd347ea26636f7f54bd Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 7 Jul 2024 17:15:56 +0200 Subject: [PATCH 118/154] Update API scheme to Layer 184 --- compiler/api/source/main_api.tl | 5 +++-- docs/source/releases/changes-in-this-fork.rst | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index ad53640dd8..091c13a65e 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -152,7 +152,7 @@ channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5 channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#bbab348d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull; +channelFull#bbab348d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; @@ -229,6 +229,7 @@ messageActionGiveawayLaunch#332ba9ed = MessageAction; messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; messageActionBoostApply#cc02aa6d boosts:int = MessageAction; messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; +messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -2547,4 +2548,4 @@ test.useError = Error; test.useConfigSimple = help.ConfigSimple; test.parseInputAppEvent = InputAppEvent; -// LAYER 183 +// LAYER 184 diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 75d9ee0cae..e198d17f8d 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -10,6 +10,13 @@ it can take advantage of new goodies! If you found any issue or have any suggestions, feel free to make `an issue `_ on github. ++------------------------+ +| Scheme layer used: 184 | ++------------------------+ + +- `View new and changed raw API methods `__. + + +------------------------+ | Scheme layer used: 183 | +------------------------+ From 5f73557ca502b7968eff3b071f1c80bc0344f790 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 7 Jul 2024 17:33:30 +0200 Subject: [PATCH 119/154] Add RefundedPayment --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 2 + pyrogram/enums/message_service_type.py | 3 + pyrogram/types/business/__init__.py | 2 + pyrogram/types/business/refunded_payment.py | 88 +++++++++++++++++++ pyrogram/types/business/successful_payment.py | 2 +- pyrogram/types/messages_and_media/message.py | 10 +++ 7 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 pyrogram/types/business/refunded_payment.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 2416cfa767..98e9c26a04 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -604,6 +604,7 @@ def get_title_list(s: str) -> list: ShippingOption ShippingQuery SuccessfulPayment + RefundedPayment """, users_chats=""" Users & Chats diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index e198d17f8d..013333a8b4 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,8 @@ If you found any issue or have any suggestions, feel free to make `an issue `__. diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index 57cae2f6c8..043ab4ead5 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -122,3 +122,6 @@ class MessageServiceType(AutoName): SUCCESSFUL_PAYMENT = auto() "Successful payment" + + REFUNDED_PAYMENT = auto() + "Refunded payment" diff --git a/pyrogram/types/business/__init__.py b/pyrogram/types/business/__init__.py index 3bc22e44a0..7f6ab511db 100644 --- a/pyrogram/types/business/__init__.py +++ b/pyrogram/types/business/__init__.py @@ -30,6 +30,7 @@ from .shipping_option import ShippingOption from .shipping_query import ShippingQuery from .successful_payment import SuccessfulPayment +from .refunded_payment import RefundedPayment __all__ = [ "BusinessConnection", @@ -46,4 +47,5 @@ "ShippingOption", "ShippingQuery", "SuccessfulPayment", + "RefundedPayment", ] diff --git a/pyrogram/types/business/refunded_payment.py b/pyrogram/types/business/refunded_payment.py new file mode 100644 index 0000000000..f25523f2d6 --- /dev/null +++ b/pyrogram/types/business/refunded_payment.py @@ -0,0 +1,88 @@ +# 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 Union + +import pyrogram +from pyrogram import raw, types + +from ..object import Object + + +class RefundedPayment(Object): + """This object contains basic information about a refunded payment. + + Parameters: + currency (``str``): + Three-letter ISO 4217 `currency `_ code, or ``XTR`` for payments in `Telegram Stars `_. + + total_amount (``int``): + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + invoice_payload (``str``): + Bot specified invoice payload. Only available to the bot that received the payment. + + telegram_payment_charge_id (``str``): + Telegram payment identifier. Only available to the bot that received the payment. + + provider_payment_charge_id (``str``): + Provider payment identifier. Only available to the bot that received the payment. + + """ + + def __init__( + self, + *, + currency: str, + total_amount: str, + invoice_payload: str, + telegram_payment_charge_id: str, + provider_payment_charge_id: str + ): + super().__init__() + + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.telegram_payment_charge_id = telegram_payment_charge_id + self.provider_payment_charge_id = provider_payment_charge_id + + @staticmethod + def _parse( + client: "pyrogram.Client", + refunded_payment: "raw.types.MessageActionPaymentRefunded" + ) -> "RefundedPayment": + invoice_payload = None + + # Try to decode invoice payload into string. If that fails, fallback to bytes instead of decoding by + # ignoring/replacing errors, this way, button clicks will still work. + try: + invoice_payload = refunded_payment.payload.decode() + except (UnicodeDecodeError, AttributeError): + invoice_payload = getattr(refunded_payment, "payload", None) + + telegram_payment_charge_id = refunded_payment.charge.id + provider_payment_charge_id = refunded_payment.charge.provider_charge_id + + return RefundedPayment( + currency=successful_payment.currency, + total_amount=successful_payment.total_amount, + invoice_payload=invoice_payload, + telegram_payment_charge_id=telegram_payment_charge_id, + provider_payment_charge_id=shipping_option_id + ) diff --git a/pyrogram/types/business/successful_payment.py b/pyrogram/types/business/successful_payment.py index 1cb1fc952b..9ab3bf5d7c 100644 --- a/pyrogram/types/business/successful_payment.py +++ b/pyrogram/types/business/successful_payment.py @@ -134,7 +134,7 @@ def _parse( total_amount=successful_payment.total_amount, invoice_payload=invoice_payload, telegram_payment_charge_id=telegram_payment_charge_id, - provider_payment_charge_id=shipping_option_id, + provider_payment_charge_id=provider_payment_charge_id, shipping_option_id=shipping_option_id, order_info=order_info, is_recurring=getattr(successful_payment, "recurring_used", None), diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index d69b1da2ee..2692e49744 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -269,6 +269,9 @@ class Message(Object, Update): successful_payment (:obj:`~pyrogram.types.SuccessfulPayment`, *optional*): Message is a service message about a successful payment, information about the payment. `More about payments »`_ + refunded_payment (:obj:`~pyrogram.types.RefundedPayment`, *optional*): + Message is a service message about a refunded payment, information about the payment. `More about payments »`_ + users_shared (:obj:`~pyrogram.types.UsersShared`, *optional*): Service message: users were shared with the bot @@ -466,6 +469,7 @@ def __init__( pinned_message: "Message" = None, invoice: "types.Invoice" = None, successful_payment: "types.SuccessfulPayment" = None, + refunded_payment: "types.RefundedPayment" = None, users_shared: "types.UsersShared" = None, chat_shared: "types.ChatShared" = None, @@ -617,6 +621,7 @@ def __init__( self.business_connection_id = business_connection_id self.successful_payment = successful_payment self.paid_media = paid_media + self.refunded_payment = refunded_payment self._raw = _raw @staticmethod @@ -699,6 +704,7 @@ async def _parse( general_forum_topic_hidden = None general_forum_topic_unhidden = None successful_payment = None + refunded_payment = None service_type = None @@ -891,6 +897,10 @@ async def _parse( elif isinstance(action, (raw.types.MessageActionPaymentSent, raw.types.MessageActionPaymentSentMe)): successful_payment = types.SuccessfulPayment._parse(client, action) service_type = enums.MessageServiceType.SUCCESSFUL_PAYMENT + + elif isinstance(action, raw.types.MessageActionPaymentRefunded): + refunded_payment = types.RefundedPayment._parse(client, action) + service_type = enums.MessageServiceType.REFUNDED_PAYMENT elif isinstance(action, raw.types.MessageActionTopicEdit): title = getattr(action, "title", None) From 7cd69266b38ce44385a06d9f175fb41130d1cd3f Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sun, 7 Jul 2024 17:33:52 +0200 Subject: [PATCH 120/154] Update Pyrogram to 2.1.32.12 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 2440329eca..11716186e5 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.11" +__version__ = "2.1.32.12" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 9d375f7523e34aa6058564ddf1c1fca71a85100f Mon Sep 17 00:00:00 2001 From: 2ei Date: Mon, 8 Jul 2024 08:31:17 +0300 Subject: [PATCH 121/154] Add new method `transfer_chat_ownership` (#49) --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/chats/__init__.py | 2 + .../methods/chats/transfer_chat_ownership.py | 82 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 pyrogram/methods/chats/transfer_chat_ownership.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 98e9c26a04..80e2f10265 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -239,6 +239,7 @@ def get_title_list(s: str) -> list: set_send_as_chat set_chat_protected_content get_created_chats + transfer_chat_ownership """, chat_topics=""" Chat Forum Topics diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 013333a8b4..07058cb9ea 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) - Added the class :obj:`~pyrogram.types.RefundedPayment`, containing information about a refunded payment. - Added the field ``refunded_payment`` to the class :obj:`~pyrogram.types.Message`, describing a service message about a refunded payment. - `View new and changed raw API methods `__. diff --git a/pyrogram/methods/chats/__init__.py b/pyrogram/methods/chats/__init__.py index f2d3025d58..347e7902d3 100644 --- a/pyrogram/methods/chats/__init__.py +++ b/pyrogram/methods/chats/__init__.py @@ -58,6 +58,7 @@ from .unpin_all_chat_messages import UnpinAllChatMessages from .unpin_chat_message import UnpinChatMessage from .get_created_chats import GetCreatedChats +from .transfer_chat_ownership import TransferChatOwnership class Chats( @@ -103,5 +104,6 @@ class Chats( SetSendAsChat, SetChatProtectedContent, GetCreatedChats, + TransferChatOwnership, ): pass diff --git a/pyrogram/methods/chats/transfer_chat_ownership.py b/pyrogram/methods/chats/transfer_chat_ownership.py new file mode 100644 index 0000000000..e61406c59e --- /dev/null +++ b/pyrogram/methods/chats/transfer_chat_ownership.py @@ -0,0 +1,82 @@ +# 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 Union + +import pyrogram +from pyrogram import raw +from pyrogram.utils import compute_password_check + + +class TransferChatOwnership: + async def transfer_chat_ownership( + self: "pyrogram.Client", + chat_id: Union[int, str], + user_id: Union[int, str], + password: str, + ) -> bool: + """Changes the owner of a chat. + + Requires owner privileges in the chat. Available only for supergroups and channel chats. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the new owner. + The ownership can't be transferred to a bot or to a deleted user. + + password (``str``): + The 2-step verification password of the current user. + + Returns: + ``bool``: True on success. + + Raises: + ValueError: In case of invalid parameters. + RPCError: In case of a Telegram RPC error. + + Example: + .. code-block:: python + + await app.transfer_chat_ownership(chat_id, user_id, "password") + """ + + peer_channel = await self.resolve_peer(chat_id) + peer_user = await self.resolve_peer(user_id) + + if not isinstance(peer_channel, raw.types.InputPeerChannel): + raise ValueError("The chat_id must belong to a channel/supergroup.") + + if not isinstance(peer_user, raw.types.InputPeerUser): + raise ValueError("The user_id must belong to a user.") + + r = await self.invoke( + raw.functions.channels.EditCreator( + channel=peer_channel, + user_id=peer_user, + password=compute_password_check( + await self.invoke(raw.functions.account.GetPassword()), password + ), + ) + ) + + return bool(r) From 3e33eec720419770ec28b99c8e4e1fd0e9765d7c Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Mon, 8 Jul 2024 12:07:14 +0530 Subject: [PATCH 122/154] Fix condition when parsing banned chats Regression was introduced in the c54ef83 --- pyrogram/types/user_and_chats/chat.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 53350c7648..073ded4493 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -382,6 +382,15 @@ def _parse_user_chat(client, user: raw.types.User) -> "Chat": def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat": peer_id = -chat.id + if isinstance(channel, raw.types.ChatForbidden): + return Chat( + id=peer_id, + type=enums.ChatType.GROUP, + title=chat.title, + client=client, + _raw=chat + ) + return Chat( id=peer_id, type=enums.ChatType.GROUP, @@ -400,15 +409,6 @@ def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat": def _parse_channel_chat(client, channel: raw.types.Channel) -> "Chat": peer_id = utils.get_channel_id(channel.id) - if isinstance(channel, raw.types.ChatForbidden): - return Chat( - id=peer_id, - type=enums.ChatType.GROUP, - title=channel.title, - client=client, - _raw=channel - ) - if isinstance(channel, raw.types.ChannelForbidden): return Chat( id=peer_id, From d0aad9d23e620cd05c7c272561d3719b346b8849 Mon Sep 17 00:00:00 2001 From: 2ei Date: Tue, 9 Jul 2024 03:53:35 +0300 Subject: [PATCH 123/154] add update_status, delete_account methods (#51) --- compiler/docs/compiler.py | 2 + docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/methods/users/__init__.py | 4 ++ pyrogram/methods/users/delete_account.py | 58 +++++++++++++++++++ pyrogram/methods/users/update_status.py | 46 +++++++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/users/delete_account.py create mode 100644 pyrogram/methods/users/update_status.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 80e2f10265..6b90806816 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -382,6 +382,8 @@ def get_title_list(s: str) -> list: set_emoji_status set_birthdate set_personal_chat + delete_account + update_status """, business=""" Telegram Business & Fragment diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 07058cb9ea..fa6c1d865e 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,7 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) +- Added the :meth:`~pyrogram.Client.delete_account`, :meth:`~pyrogram.Client.transfer_chat_ownership`, :meth:`~pyrogram.Client.update_status` (`#49 `__, `#51 `__) - Added the class :obj:`~pyrogram.types.RefundedPayment`, containing information about a refunded payment. - Added the field ``refunded_payment`` to the class :obj:`~pyrogram.types.Message`, describing a service message about a refunded payment. - `View new and changed raw API methods `__. diff --git a/pyrogram/methods/users/__init__.py b/pyrogram/methods/users/__init__.py index 9a5be5428a..d61faf20da 100644 --- a/pyrogram/methods/users/__init__.py +++ b/pyrogram/methods/users/__init__.py @@ -31,6 +31,8 @@ from .update_profile import UpdateProfile from .set_birthdate import SetBirthdate from .set_personal_chat import SetPersonalChat +from .update_status import UpdateStatus +from .delete_account import DeleteAccount class Users( @@ -49,5 +51,7 @@ class Users( SetUsername, UnblockUser, UpdateProfile, + UpdateStatus, + DeleteAccount, ): pass diff --git a/pyrogram/methods/users/delete_account.py b/pyrogram/methods/users/delete_account.py new file mode 100644 index 0000000000..692c6d42b3 --- /dev/null +++ b/pyrogram/methods/users/delete_account.py @@ -0,0 +1,58 @@ +# 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 . + +import pyrogram +from pyrogram import raw +from pyrogram.utils import compute_password_check + + +class DeleteAccount: + async def delete_account( + self: "pyrogram.Client", reason: str = "", password: str = None + ) -> bool: + """Deletes the account of the current user, deleting all information associated with the user from the server. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + reason (``str``, *optional*): + The reason why the account was deleted. + + password (``str``, *optional*): + The 2-step verification password of the current user. If the current user isn't authorized, then an empty string can be passed and account deletion can be canceled within one week. + + Returns: + `bool`: True On success. + + Example: + .. code-block:: python + + await app.delete_account(reason, password) + """ + r = await self.invoke( + raw.functions.account.DeleteAccount( + reason=reason, + password=compute_password_check( + await self.invoke(raw.functions.account.GetPassword()), password + ) + if password + else None, + ) + ) + + return bool(r) diff --git a/pyrogram/methods/users/update_status.py b/pyrogram/methods/users/update_status.py new file mode 100644 index 0000000000..841bee202c --- /dev/null +++ b/pyrogram/methods/users/update_status.py @@ -0,0 +1,46 @@ +# 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 . + +import pyrogram +from pyrogram import raw + + +class UpdateStatus: + async def update_status( + self: "pyrogram.Client", + offline: bool = False, + ) -> bool: + """Updates online user status. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + offline (``bool``): + If (True) is transmitted, user status will change to (UserStatusOffline), Otherwise user status will change to (UserStatusOnline). + + Returns: + `bool`: True On success. + + Example: + .. code-block:: python + + await app.update_status() + """ + r = await self.invoke(raw.functions.account.UpdateStatus(offline=offline)) + + return bool(r) From b6605d25982b2dd389924a86116b028dceb49995 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 16 Jul 2024 16:41:53 +0200 Subject: [PATCH 124/154] Fixes for error message scrapper (#53) --- compiler/errors/sort.py | 12 +++++++----- compiler/errors/source/400_BAD_REQUEST.tsv | 2 +- compiler/errors/source/403_FORBIDDEN.tsv | 4 ++-- compiler/errors/source/406_NOT_ACCEPTABLE.tsv | 2 +- compiler/errors/source/420_FLOOD.tsv | 2 +- compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/errors/sort.py b/compiler/errors/sort.py index 47bf0315bf..44713095ea 100644 --- a/compiler/errors/sort.py +++ b/compiler/errors/sort.py @@ -57,11 +57,6 @@ for h in e: dct = {} - for p in Path("source/").glob(f"{h}*.tsv"): - with open(p) as f: - reader = csv.reader(f, delimiter="\t") - dct = {k: v for k, v in reader if k != "id"} - j = d.get("errors").get(h) for k in j: if k.endswith("_*"): @@ -72,6 +67,13 @@ l = l.replace("%d", "{value}") dct[m] = l + for p in Path("source/").glob(f"{h}*.tsv"): + with open(p) as f: + reader = csv.reader(f, delimiter="\t") + for k, v in reader: + if k != "id": + dct[k] = v + keys = sorted(dct) for p in Path("source/").glob(f"{h}*.tsv"): diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index 5261ea3a65..5db312ab14 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -518,4 +518,4 @@ WEBPAGE_URL_INVALID The specified webpage `url` is invalid. WEBPUSH_AUTH_INVALID The specified web push authentication secret is invalid. WEBPUSH_KEY_INVALID The specified web push elliptic curve Diffie-Hellman public key is invalid. WEBPUSH_TOKEN_INVALID The specified web push token is invalid. -YOU_BLOCKED_USER You blocked this user. \ No newline at end of file +YOU_BLOCKED_USER You blocked this user. diff --git a/compiler/errors/source/403_FORBIDDEN.tsv b/compiler/errors/source/403_FORBIDDEN.tsv index 09d2240d40..e7a16b811e 100644 --- a/compiler/errors/source/403_FORBIDDEN.tsv +++ b/compiler/errors/source/403_FORBIDDEN.tsv @@ -25,7 +25,7 @@ GROUPCALL_ALREADY_STARTED The groupcall has already started, you can join direct GROUPCALL_FORBIDDEN The group call has already ended. INLINE_BOT_REQUIRED Only the inline bot can edit message. MESSAGE_AUTHOR_REQUIRED Message author required. -MESSAGE_DELETE_FORBIDDEN You can't delete one of the messages you tried to delete, most likely because it is a service message. +MESSAGE_DELETE_FORBIDDEN You can't delete one of the messages you tried to delete. NOT_ELIGIBLE You are not eligible to take part in Telegram's Premium for SMS initiative PARTICIPANT_JOIN_MISSING Trying to enable a presentation, when the user hasn't joined the Video Chat with [phone.joinGroupCall](https://core.telegram.org/method/phone.joinGroupCall). POLL_VOTE_REQUIRED Cast a vote in the poll before calling this method. @@ -43,4 +43,4 @@ USER_IS_BLOCKED You were blocked by this user. USER_NOT_MUTUAL_CONTACT The provided user is not a mutual contact. USER_PRIVACY_RESTRICTED The user's privacy settings do not allow you to do this. USER_RESTRICTED You're spamreported, you can't create channels or chats. -VOICE_MESSAGES_FORBIDDEN This user's privacy settings forbid you from sending voice messages. \ No newline at end of file +VOICE_MESSAGES_FORBIDDEN This user's privacy settings forbid you from sending voice messages. diff --git a/compiler/errors/source/406_NOT_ACCEPTABLE.tsv b/compiler/errors/source/406_NOT_ACCEPTABLE.tsv index 19dc3af52b..d12d409f8e 100644 --- a/compiler/errors/source/406_NOT_ACCEPTABLE.tsv +++ b/compiler/errors/source/406_NOT_ACCEPTABLE.tsv @@ -22,4 +22,4 @@ TOPIC_CLOSED This topic was closed, you can't send messages to it anymore. TOPIC_DELETED The specified topic was deleted. USERPIC_PRIVACY_REQUIRED You need to disable privacy settings for your profile picture in order to make your geolocation public. USERPIC_UPLOAD_REQUIRED You must have a profile picture to publish your geolocation. -USER_RESTRICTED You're spamreported, you can't create channels or chats. \ No newline at end of file +USER_RESTRICTED You're spamreported, you can't create channels or chats. diff --git a/compiler/errors/source/420_FLOOD.tsv b/compiler/errors/source/420_FLOOD.tsv index 9e17e5a3c7..8242c574f3 100644 --- a/compiler/errors/source/420_FLOOD.tsv +++ b/compiler/errors/source/420_FLOOD.tsv @@ -6,4 +6,4 @@ FLOOD_WAIT_X A wait of {value} seconds is required PREMIUM_SUB_ACTIVE_UNTIL_X You already have a premium subscription active until unixtime {value} . SLOWMODE_WAIT_X Slowmode is enabled in this chat: wait {value} seconds before sending another message to this chat. STORY_SEND_FLOOD_X A wait of {value} seconds is required to continue posting stories -TAKEOUT_INIT_DELAY_X Sorry, for security reasons, you will be able to begin downloading your data in {value} seconds. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not. \ No newline at end of file +TAKEOUT_INIT_DELAY_X Sorry, for security reasons, you will be able to begin downloading your data in {value} seconds. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not. diff --git a/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv b/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv index dac5110c40..608f7f569e 100644 --- a/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv +++ b/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv @@ -48,4 +48,4 @@ UNKNOWN_METHOD The method you tried to call cannot be called on non-CDN DCs UPLOAD_NO_VOLUME Telegram is having internal problems. Please try again later VOLUME_LOC_NOT_FOUND Telegram is having internal problems. Please try again later WORKER_BUSY_TOO_LONG_RETRY Server workers are too busy right now due to Telegram having internal problems. Please try again later -WP_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later \ No newline at end of file +WP_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later From 39fe8268b90261274bb7dcb545a223f69da0bb1c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 16 Jul 2024 17:02:18 +0200 Subject: [PATCH 125/154] Fix documentation mistakes --- docs/source/releases/changes-in-this-fork.rst | 2 +- .../methods/messages/edit_cached_media.py | 44 ++++++++++++++++++- pyrogram/methods/messages/set_reaction.py | 4 +- pyrogram/methods/users/set_personal_chat.py | 2 +- pyrogram/types/object.py | 1 + 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index fa6c1d865e..918747447c 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -38,7 +38,7 @@ If you found any issue or have any suggestions, feel free to make `an issue Optional["types.Message"]: """Edit a media stored on the Telegram servers using a file_id. @@ -83,6 +86,9 @@ async def edit_cached_media( reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message to be edited was sent + Returns: :obj:`~pyrogram.types.Message`: On success, the edited media message is returned. @@ -101,7 +107,26 @@ async def edit_cached_media( invert_media=show_caption_above_media, **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) ) - r = await self.invoke(rpc) + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) for i in r.updates: if isinstance( @@ -119,3 +144,18 @@ async def edit_cached_media( is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), replies=self.fetch_replies ) + elif isinstance( + i, + ( + raw.types.UpdateBotEditBusinessMessage + ) + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + business_connection_id=getattr(i, "connection_id", business_connection_id), + raw_reply_to_message=i.reply_to_message, + replies=0 + ) diff --git a/pyrogram/methods/messages/set_reaction.py b/pyrogram/methods/messages/set_reaction.py index c6cd91e3e3..b96661ebfc 100644 --- a/pyrogram/methods/messages/set_reaction.py +++ b/pyrogram/methods/messages/set_reaction.py @@ -42,9 +42,9 @@ async def set_reaction( a channel to its discussion group have the same available reactions as messages in the channel. - You must use exactly one of ``chat_id`` OR ``story_id``. + You must use exactly one of ``message_id`` OR ``story_id``. - If you specify, ``chat_id`` + If you specify, ``message_id`` .. include:: /_includes/usable-by/users-bots.rst diff --git a/pyrogram/methods/users/set_personal_chat.py b/pyrogram/methods/users/set_personal_chat.py index ce62687a78..7813916725 100644 --- a/pyrogram/methods/users/set_personal_chat.py +++ b/pyrogram/methods/users/set_personal_chat.py @@ -32,7 +32,7 @@ async def set_personal_chat( .. include:: /_includes/usable-by/users.rst Parameters: - chat_id (``int`` | ``str`, *optional*): + chat_id (``int`` | ``str``, *optional*): Identifier of the new personal chat; pass None to remove the chat. Use :meth:`~pyrogram.Client.get_created_chats` with ``is_suitable_for_my_personal_chat`` to get suitable chats Returns: diff --git a/pyrogram/types/object.py b/pyrogram/types/object.py index 8eaf6aeae3..2371babd33 100644 --- a/pyrogram/types/object.py +++ b/pyrogram/types/object.py @@ -60,6 +60,7 @@ def default(obj: "Object"): if isinstance(obj, datetime): return str(obj) + # TODO: #20 if not hasattr(obj, "__dict__"): return obj.__class__.__name__ From 2f95181467691a65606fc08a45d06a8b84d0bf9d Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Tue, 16 Jul 2024 20:37:54 +0530 Subject: [PATCH 126/154] Dynamic session ReStart + restart optimizations (#56) Co-authored-by: Marvin --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/session/session.py | 218 ++++++++++++++---- 2 files changed, 171 insertions(+), 48 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 918747447c..7044bdc327 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) - Added the :meth:`~pyrogram.Client.delete_account`, :meth:`~pyrogram.Client.transfer_chat_ownership`, :meth:`~pyrogram.Client.update_status` (`#49 `__, `#51 `__) - Added the class :obj:`~pyrogram.types.RefundedPayment`, containing information about a refunded payment. - Added the field ``refunded_payment`` to the class :obj:`~pyrogram.types.Message`, describing a service message about a refunded payment. diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 88c8b44694..cfd122c15e 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -20,7 +20,7 @@ import bisect import logging import os -from datetime import datetime, timedelta +from time import time from hashlib import sha1 from io import BytesIO from typing import Optional @@ -49,14 +49,15 @@ def __init__(self): class Session: - START_TIMEOUT = 2 + START_TIMEOUT = 5 WAIT_TIMEOUT = 15 + REART_TIMEOUT = 5 SLEEP_THRESHOLD = 10 MAX_RETRIES = 10 ACKS_THRESHOLD = 10 PING_INTERVAL = 5 STORED_MSG_IDS_MAX_SIZE = 1000 * 2 - RECONNECT_THRESHOLD = timedelta(seconds=10) + RECONNECT_THRESHOLD = 13 TRANSPORT_ERRORS = { 404: "auth key not found", @@ -110,10 +111,17 @@ def __init__( self.loop = asyncio.get_event_loop() + self.instant_stop = False # set internally self.last_reconnect_attempt = None + self.currently_restarting = False + self.currently_stopping = False async def start(self): while True: + if self.instant_stop: + log.info("session init stopped") + return # stop instantly + self.connection = self.client.connection_factory( dc_id=self.dc_id, test_mode=self.test_mode, @@ -173,46 +181,98 @@ async def start(self): log.info("Session started") - async def stop(self): - self.is_started.clear() - - self.stored_msg_ids.clear() - - self.ping_task_event.set() - - if self.ping_task is not None: - await self.ping_task - - self.ping_task_event.clear() + async def stop(self, restart: bool = False): + if self.currently_stopping: + return # don't stop twice + if self.instant_stop: + log.info("session stop process stopped") + return # stop doing anything instantly, client is manually handling - await self.connection.close() - - if self.recv_task: - await self.recv_task + try: + self.currently_stopping = True + self.is_started.clear() + self.stored_msg_ids.clear() + + if restart: + self.instant_stop = True # tell all funcs that we want to stop + + self.ping_task_event.set() + for _ in range(2): + try: + if self.ping_task is not None: + await asyncio.wait_for( + self.ping_task, timeout=self.REART_TIMEOUT + ) + break + except TimeoutError: + self.ping_task.cancel() + continue # next stage + self.ping_task_event.clear() - if not self.is_media and callable(self.client.disconnect_handler): try: - await self.client.disconnect_handler(self.client) + await asyncio.wait_for( + self.connection.close(), timeout=self.REART_TIMEOUT + ) except Exception as e: log.exception(e) - log.info("Session stopped") + for _ in range(2): + try: + if self.recv_task: + await asyncio.wait_for( + self.recv_task, timeout=self.REART_TIMEOUT + ) + break + except TimeoutError: + self.recv_task.cancel() + continue # next stage + + if not self.is_media and callable(self.client.disconnect_handler): + try: + await self.client.disconnect_handler(self.client) + except Exception as e: + log.exception(e) + + log.info("session stopped") + finally: + self.currently_stopping = False + if restart: + self.instant_stop = False # reset async def restart(self): - now = datetime.now() - if ( - self.last_reconnect_attempt - and now - self.last_reconnect_attempt < self.RECONNECT_THRESHOLD - ): - log.info("Reconnecting too frequently, sleeping for a while") - await asyncio.sleep(5) + if self.currently_restarting: + return # don't restart twice + if self.instant_stop: + return # stop instantly - self.last_reconnect_attempt = now + try: + self.currently_restarting = True + now = time() + if ( + self.last_reconnect_attempt + and (now - self.last_reconnect_attempt) < self.RECONNECT_THRESHOLD + ): + to_wait = int( + self.RECONNECT_THRESHOLD - (now - self.last_reconnect_attempt) + ) + log.warning( + "[pyrogram] Client [%s] is reconnecting too frequently, sleeping for %s seconds", + self.client.name, + to_wait + ) + await asyncio.sleep(to_wait) - await self.stop() - await self.start() + self.last_reconnect_attempt = now + await self.stop(restart=True) + await self.start() + finally: + self.currently_restarting = False async def handle_packet(self, packet): + if self.instant_stop: + log.info("Stopped packet handler") + return # stop instantly + data = await self.loop.run_in_executor( pyrogram.crypto_executor, mtproto.unpack, @@ -298,9 +358,17 @@ async def handle_packet(self, packet): self.pending_acks.clear() async def ping_worker(self): + if self.instant_stop: + log.info("PingTask force stopped") + return # stop instantly + log.info("PingTask started") while True: + if self.instant_stop: + log.info("PingTask force stopped (loop)") + return # stop instantly + try: await asyncio.wait_for(self.ping_task_event.wait(), self.PING_INTERVAL) except asyncio.TimeoutError: @@ -326,15 +394,27 @@ async def recv_worker(self): log.info("NetworkTask started") while True: + if self.instant_stop: + log.info("NetworkTask force stopped (loop)") + return # stop instantly + packet = await self.connection.recv() if packet is None or len(packet) == 4: if packet: error_code = -Int.read(BytesIO(packet)) + if error_code == 404: + raise Unauthorized( + "Auth key not found in the system. You must delete your session file " + "and log in again with your phone number or bot token." + ) + log.warning( - "Server sent transport error: %s (%s)", - error_code, Session.TRANSPORT_ERRORS.get(error_code, "unknown error") + "[%s] Server sent transport error: %s (%s)", + self.client.name, + error_code, + Session.TRANSPORT_ERRORS.get(error_code, "unknown error"), ) if self.is_started.is_set(): @@ -346,7 +426,15 @@ async def recv_worker(self): log.info("NetworkTask stopped") - async def send(self, data: TLObject, wait_response: bool = True, timeout: float = WAIT_TIMEOUT): + async def send( + self, + data: TLObject, + wait_response: bool = True, + timeout: float = WAIT_TIMEOUT, + ): + if self.instant_stop: + return # stop instantly + message = self.msg_factory(data) msg_id = message.msg_id @@ -404,10 +492,8 @@ async def invoke( timeout: float = WAIT_TIMEOUT, sleep_threshold: float = SLEEP_THRESHOLD ): - try: - await asyncio.wait_for(self.is_started.wait(), self.WAIT_TIMEOUT) - except asyncio.TimeoutError: - pass + if self.instant_stop: + return # stop instantly if isinstance(query, Session.CUR_ALWD_INNR_QRYS): inner_query = query.query @@ -417,6 +503,19 @@ async def invoke( query_name = ".".join(inner_query.QUALNAME.split(".")[1:]) while retries > 0: + if self.instant_stop: + return # stop instantly + + # sleep until the restart is performed + if self.currently_restarting: + while self.currently_restarting: + if self.instant_stop: + return # stop instantly + await asyncio.sleep(1) + + if not self.is_started.is_set(): + await self.is_started.wait() + try: return await self.send(query, timeout=timeout) except (FloodWait, FloodPremiumWait) as e: @@ -425,11 +524,21 @@ async def invoke( if amount > sleep_threshold >= 0: raise - log.warning('[%s] Waiting for %s seconds before continuing (required by "%s")', - self.client.name, amount, query_name) + log.warning( + '[%s] Waiting for %s seconds before continuing (required by "%s")', + self.client.name, + amount, + query_name, + ) await asyncio.sleep(amount) - except (OSError, InternalServerError, ServiceUnavailable) as e: + except ( + OSError, + RuntimeError, + InternalServerError, + ServiceUnavailable, + TimeoutError, + ) as e: retries -= 1 if ( retries == 0 or @@ -443,13 +552,26 @@ async def invoke( ): raise e from None - (log.warning if retries < 2 else log.info)( - '[%s] Retrying "%s" due to: %s', - Session.MAX_RETRIES - retries, - query_name, - str(e) or repr(e) - ) + if (isinstance(e, (OSError, RuntimeError)) and "handler" in str(e)) or ( + isinstance(e, TimeoutError) + ): + (log.warning if retries < 2 else log.info)( + '[%s] [%s] reconnecting session requesting "%s", due to: %s', + self.client.name, + Session.MAX_RETRIES - retries, + query_name, + str(e) or repr(e), + ) + self.loop.create_task(self.restart()) + else: + (log.warning if retries < 2 else log.info)( + '[%s] [%s] Retrying "%s" due to: %s', + self.client.name, + Session.MAX_RETRIES - retries, + query_name, + str(e) or repr(e), + ) - await asyncio.sleep(3) + await asyncio.sleep(1) raise TimeoutError("Exceeded maximum number of retries") From c77f096ab3bd7b08f6f1261bb967247dba774ab9 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 16 Jul 2024 17:10:06 +0200 Subject: [PATCH 127/154] Update Pyrogram to 2.1.32.13 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 11716186e5..97a129caeb 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.12" +__version__ = "2.1.32.13" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 3d2aa8b068f8ea768a5fca51288a8db40d922984 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 16 Jul 2024 18:36:34 +0200 Subject: [PATCH 128/154] Add missing parameters to search_messages and search_messages_count (#50) --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/messages/search_messages.py | 81 ++++++++++++++----- .../methods/messages/search_messages_count.py | 40 +++++++-- 3 files changed, 93 insertions(+), 29 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 7044bdc327..6eafd2e6e5 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) - Added the :meth:`~pyrogram.Client.delete_account`, :meth:`~pyrogram.Client.transfer_chat_ownership`, :meth:`~pyrogram.Client.update_status` (`#49 `__, `#51 `__) - Added the class :obj:`~pyrogram.types.RefundedPayment`, containing information about a refunded payment. diff --git a/pyrogram/methods/messages/search_messages.py b/pyrogram/methods/messages/search_messages.py index 99da7927d7..c4da6cf790 100644 --- a/pyrogram/methods/messages/search_messages.py +++ b/pyrogram/methods/messages/search_messages.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from datetime import datetime from typing import Union, List, AsyncGenerator, Optional import pyrogram @@ -27,31 +28,39 @@ async def get_chunk( client, chat_id: Union[int, str], query: str = "", - filter: "enums.MessagesFilter" = enums.MessagesFilter.EMPTY, offset: int = 0, + filter: "enums.MessagesFilter" = enums.MessagesFilter.EMPTY, limit: int = 100, from_user: Union[int, str] = None, - message_thread_id: int = None + message_thread_id: int = None, + offset_id: int = 0, + min_date: datetime = utils.zero_datetime(), + max_date: datetime = utils.zero_datetime(), + min_id: int = 0, + max_id: int = 0, + saved_messages_topic_id: Optional[Union[int, str]] = None ) -> List["types.Message"]: r = await client.invoke( raw.functions.messages.Search( peer=await client.resolve_peer(chat_id), q=query, filter=filter.value(), - min_date=0, - max_date=0, - offset_id=0, + min_date=utils.datetime_to_timestamp(min_date), + max_date= utils.datetime_to_timestamp(max_date), + offset_id=offset_id, add_offset=offset, limit=limit, - min_id=0, - max_id=0, + min_id=min_id, + max_id=max_id, from_id=( await client.resolve_peer(from_user) if from_user else None ), hash=0, - top_msg_id=message_thread_id + top_msg_id=message_thread_id, + saved_peer_id=await client.resolve_peer(saved_messages_topic_id) if saved_messages_topic_id else None + # saved_reaction:flags.3?Vector ), sleep_threshold=60 ) @@ -65,11 +74,17 @@ async def search_messages( self: "pyrogram.Client", chat_id: Union[int, str], query: str = "", - offset: int = 0, filter: "enums.MessagesFilter" = enums.MessagesFilter.EMPTY, - limit: int = 0, from_user: Union[int, str] = None, - message_thread_id: int = None + message_thread_id: int = None, + offset: int = 0, + limit: int = 0, + offset_id: int = 0, + min_date: datetime = utils.zero_datetime(), + max_date: datetime = utils.zero_datetime(), + min_id: int = 0, + max_id: int = 0, + saved_messages_topic_id: Optional[Union[int, str]] = None ) -> Optional[AsyncGenerator["types.Message", None]]: """Search for text and media messages inside a specific chat. @@ -89,24 +104,42 @@ async def search_messages( When passed while searching for media messages, the query will be applied to captions. Defaults to "" (empty string). - offset (``int``, *optional*): - Sequential number of the first message to be returned. - Defaults to 0. - filter (:obj:`~pyrogram.enums.MessagesFilter`, *optional*): Pass a filter in order to search for specific kind of messages only. Defaults to any message (no filter). - limit (``int``, *optional*): - Limits the number of messages to be retrieved. - By default, no limit is applied and all messages are returned. - from_user (``int`` | ``str``, *optional*): Unique identifier (int) or username (str) of the target user you want to search for messages from. message_thread_id (``int``, *optional*): Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + offset (``int``, *optional*): + Sequential number of the first message to be returned. + Defaults to 0. + + limit (``int``, *optional*): + Limits the number of messages to be retrieved. + By default, no limit is applied and all messages are returned. + + offset_id (``int``, *optional*): + Identifier of the first message to be returned. + + min_date (:py:obj:`~datetime.datetime`, *optional*): + Pass a date as offset to retrieve only older messages starting from that date. + + max_date (:py:obj:`~datetime.datetime`, *optional*): + Pass a date as offset to retrieve only newer messages starting from that date. + + min_id (``int``, *optional*): + If a positive value was provided, the method will return only messages with IDs more than min_id. + + max_id (``int``, *optional*): + If a positive value was provided, the method will return only messages with IDs less than max_id. + + saved_messages_topic_id (``int`` | ``str``, *optional*): + If not None, only messages in the specified Saved Messages topic will be returned; pass None to return all messages, or for chats other than Saved Messages. + Returns: ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. @@ -137,11 +170,17 @@ async def search_messages( client=self, chat_id=chat_id, query=query, - filter=filter, offset=offset, + filter=filter, limit=limit, from_user=from_user, - message_thread_id=message_thread_id + message_thread_id=message_thread_id, + offset_id=offset_id, + min_date=min_date, + max_date=max_date, + min_id=min_id, + max_id=max_id, + saved_messages_topic_id=saved_messages_topic_id ) if not messages: diff --git a/pyrogram/methods/messages/search_messages_count.py b/pyrogram/methods/messages/search_messages_count.py index 9cea46cb2a..e4a19113eb 100644 --- a/pyrogram/methods/messages/search_messages_count.py +++ b/pyrogram/methods/messages/search_messages_count.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union +from datetime import datetime +from typing import Optional, Union import pyrogram -from pyrogram import raw, enums +from pyrogram import enums, raw, utils class SearchMessagesCount: @@ -29,7 +30,12 @@ async def search_messages_count( query: str = "", filter: "enums.MessagesFilter" = enums.MessagesFilter.EMPTY, from_user: Union[int, str] = None, - message_thread_id: int = None + message_thread_id: int = None, + min_date: datetime = utils.zero_datetime(), + max_date: datetime = utils.zero_datetime(), + min_id: int = 0, + max_id: int = 0, + saved_messages_topic_id: Optional[Union[int, str]] = None ) -> int: """Get the count of messages resulting from a search inside a chat. @@ -58,28 +64,46 @@ async def search_messages_count( message_thread_id (``int``, *optional*): Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + min_date (:py:obj:`~datetime.datetime`, *optional*): + Pass a date as offset to retrieve only older messages starting from that date. + + max_date (:py:obj:`~datetime.datetime`, *optional*): + Pass a date as offset to retrieve only newer messages starting from that date. + + min_id (``int``, *optional*): + If a positive value was provided, the method will return only messages with IDs more than min_id. + + max_id (``int``, *optional*): + If a positive value was provided, the method will return only messages with IDs less than max_id. + + saved_messages_topic_id (``int`` | ``str``, *optional*): + If not None, only messages in the specified Saved Messages topic will be returned; pass None to return all messages, or for chats other than Saved Messages. + Returns: ``int``: On success, the messages count is returned. + """ r = await self.invoke( raw.functions.messages.Search( peer=await self.resolve_peer(chat_id), q=query, filter=filter.value(), - min_date=0, - max_date=0, + min_date=utils.datetime_to_timestamp(min_date), + max_date= utils.datetime_to_timestamp(max_date), offset_id=0, add_offset=0, limit=1, - min_id=0, - max_id=0, + min_id=min_id, + max_id=max_id, from_id=( await self.resolve_peer(from_user) if from_user else None ), hash=0, - top_msg_id=message_thread_id + top_msg_id=message_thread_id, + saved_peer_id=await self.resolve_peer(saved_messages_topic_id) if saved_messages_topic_id else None + # saved_reaction:flags.3?Vector ) ) From 7097e0d2c87ec0cffef697d83ed46334be398fea Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 16 Jul 2024 18:46:14 +0200 Subject: [PATCH 129/154] Attempt to patch off an inconsistent behaviour (#52) --- pyrogram/methods/messages/send_message.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index a550078717..e574e21ee1 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -313,19 +313,21 @@ async def send_message( return types.Message( id=r.id, + outgoing=r.out, + date=utils.timestamp_to_datetime(r.date), + entities=[ + types.MessageEntity._parse(None, entity, {}) + for entity in r.entities + ] if r.entities else None, + chat_ttl_period=getattr(r, "ttl_period", None), + # TODO: #52 fix inconsistency chat=types.Chat( id=peer_id, type=enums.ChatType.PRIVATE, client=self ), text=message, - date=utils.timestamp_to_datetime(r.date), - outgoing=r.out, reply_markup=reply_markup, - entities=[ - types.MessageEntity._parse(None, entity, {}) - for entity in entities - ] if entities else None, client=self ) From 0595b3229a49dbd4eaae959d2847fcaf918d3890 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 16 Jul 2024 19:04:08 +0200 Subject: [PATCH 130/154] Add is_automatic_forward to Message (#54) Reference: https://t.me/pyrogramchat/620063 --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/types/messages_and_media/message.py | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 6eafd2e6e5..b7e2b42475 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) - Added the :meth:`~pyrogram.Client.delete_account`, :meth:`~pyrogram.Client.transfer_chat_ownership`, :meth:`~pyrogram.Client.update_status` (`#49 `__, `#51 `__) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 2692e49744..f8c6b8a6fe 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -418,8 +418,7 @@ def __init__( chat: "types.Chat" = None, forward_origin: "types.MessageOrigin" = None, is_topic_message: bool = None, - - + is_automatic_forward: bool = None, reply_to_message_id: int = None, reply_to_message: "Message" = None, external_reply: "types.ExternalReplyInfo" = None, @@ -597,6 +596,7 @@ def __init__( self.effect_id = effect_id self.external_reply = external_reply self.is_topic_message = is_topic_message + self.is_automatic_forward = is_automatic_forward self.sender_boost_count = sender_boost_count self.boost_added = boost_added self.quote = quote @@ -1266,6 +1266,20 @@ async def _parse( parsed_message.is_from_offline = getattr(message, "offline", None) + is_automatic_forward = None + if ( + forward_header and + forward_header.saved_from_peer and + forward_header.saved_from_msg_id + ): + saved_from_peer_id = utils.get_raw_peer_id(forward_header.saved_from_peer) + saved_from_peer_chat = chats.get(saved_from_peer_id) + if ( + isinstance(saved_from_peer_chat, raw.types.Channel) and + not saved_from_peer_chat.megagroup + ): + parsed_message.is_automatic_forward = True + if getattr(message, "reply_to", None): parsed_message.reply_to_message_id = None parsed_message.message_thread_id = None From 98ec926847a0aeedfb601dc2026d75be42bb6278 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 17 Jul 2024 15:20:12 +0200 Subject: [PATCH 131/154] Fix documentation mistake --- pyrogram/methods/messages/send_poll.py | 2 +- pyrogram/types/messages_and_media/message.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index 0ea8e2c10e..617809fc38 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -86,7 +86,7 @@ async def send_poll( True, if the poll needs to be anonymous. Defaults to True. - type (:obj`~pyrogram.enums.PollType`, *optional*): + type (:obj:`~pyrogram.enums.PollType`, *optional*): Poll type, :obj:`~pyrogram.enums.PollType.QUIZ` or :obj:`~pyrogram.enums.PollType.REGULAR`. Defaults to :obj:`~pyrogram.enums.PollType.REGULAR`. diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index f8c6b8a6fe..798f5c1198 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -244,8 +244,6 @@ class Message(Object, Update): channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel. - message_auto_delete_timer_changed - migrate_to_chat_id (``int``, *optional*): The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects @@ -267,10 +265,10 @@ class Message(Object, Update): Message is an invoice for a `payment `_, information about the invoice. `More about payments » `_ successful_payment (:obj:`~pyrogram.types.SuccessfulPayment`, *optional*): - Message is a service message about a successful payment, information about the payment. `More about payments »`_ + Message is a service message about a successful payment, information about the payment. `More about payments `_ refunded_payment (:obj:`~pyrogram.types.RefundedPayment`, *optional*): - Message is a service message about a refunded payment, information about the payment. `More about payments »`_ + Message is a service message about a refunded payment, information about the payment. `More about payments `_ users_shared (:obj:`~pyrogram.types.UsersShared`, *optional*): Service message: users were shared with the bot @@ -1266,7 +1264,6 @@ async def _parse( parsed_message.is_from_offline = getattr(message, "offline", None) - is_automatic_forward = None if ( forward_header and forward_header.saved_from_peer and @@ -2847,7 +2844,7 @@ async def reply_poll( True, if the poll needs to be anonymous. Defaults to True. - type (:obj`~pyrogram.enums.PollType`, *optional*): + type (:obj:`~pyrogram.enums.PollType`, *optional*): Poll type, :obj:`~pyrogram.enums.PollType.QUIZ` or :obj:`~pyrogram.enums.PollType.REGULAR`. Defaults to :obj:`~pyrogram.enums.PollType.REGULAR`. From 8bdfea37285c75d8474c16fc6420dcacc1bef07a Mon Sep 17 00:00:00 2001 From: Ben S George <73480087+AlbertEinsteinTG@users.noreply.github.com> Date: Wed, 17 Jul 2024 18:50:43 +0530 Subject: [PATCH 132/154] Fix NameError (#59) --- pyrogram/types/user_and_chats/chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 073ded4493..001dfae0d2 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -382,7 +382,7 @@ def _parse_user_chat(client, user: raw.types.User) -> "Chat": def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat": peer_id = -chat.id - if isinstance(channel, raw.types.ChatForbidden): + if isinstance(chat, raw.types.ChatForbidden): return Chat( id=peer_id, type=enums.ChatType.GROUP, From 033bf9262cd449193aab8762e3f1798d0998718f Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 17 Jul 2024 15:26:40 +0200 Subject: [PATCH 133/154] steal fixes from pyroblack Co-authored-by: eyMarv --- pyrogram/session/session.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index cfd122c15e..b2b7acf74a 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -33,7 +33,8 @@ RPCError, InternalServerError, AuthKeyDuplicated, FloodWait, FloodPremiumWait, ServiceUnavailable, BadMsgNotification, - SecurityCheckMismatch + SecurityCheckMismatch, + Unauthorized ) from pyrogram.raw.all import layer from pyrogram.raw.core import TLObject, MsgContainer, Int, FutureSalts @@ -58,6 +59,7 @@ class Session: PING_INTERVAL = 5 STORED_MSG_IDS_MAX_SIZE = 1000 * 2 RECONNECT_THRESHOLD = 13 + STOP_RANGE = range(2) TRANSPORT_ERRORS = { 404: "auth key not found", @@ -197,7 +199,7 @@ async def stop(self, restart: bool = False): self.instant_stop = True # tell all funcs that we want to stop self.ping_task_event.set() - for _ in range(2): + for _ in self.STOP_RANGE: try: if self.ping_task is not None: await asyncio.wait_for( @@ -216,7 +218,7 @@ async def stop(self, restart: bool = False): except Exception as e: log.exception(e) - for _ in range(2): + for _ in self.STOP_RANGE: try: if self.recv_task: await asyncio.wait_for( @@ -252,7 +254,7 @@ async def restart(self): self.last_reconnect_attempt and (now - self.last_reconnect_attempt) < self.RECONNECT_THRESHOLD ): - to_wait = int( + to_wait = self.RECONNECT_THRESHOLD + int( self.RECONNECT_THRESHOLD - (now - self.last_reconnect_attempt) ) log.warning( From 08f32293a0a5187b24814d293c6066d50a5b4416 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 17 Jul 2024 16:07:06 +0200 Subject: [PATCH 134/154] Rename chat_ttl to message_auto_delete_time, according to BOT API --- compiler/docs/compiler.py | 4 +- pyrogram/enums/message_service_type.py | 4 +- pyrogram/methods/chats/__init__.py | 4 +- ...y => set_chat_message_auto_delete_time.py} | 32 ++++++------- pyrogram/methods/messages/send_message.py | 4 +- pyrogram/types/messages_and_media/__init__.py | 2 + pyrogram/types/messages_and_media/message.py | 31 +++++-------- .../message_auto_delete_timer_changed.py | 46 +++++++++++++++++++ pyrogram/types/user_and_chats/chat.py | 19 +++++--- 9 files changed, 98 insertions(+), 48 deletions(-) rename pyrogram/methods/chats/{set_chat_ttl.py => set_chat_message_auto_delete_time.py} (63%) create mode 100644 pyrogram/types/messages_and_media/message_auto_delete_timer_changed.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 6b90806816..88767d9e8c 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -231,7 +231,7 @@ def get_title_list(s: str) -> list: delete_supergroup delete_user_history set_slow_mode - set_chat_ttl + set_chat_message_auto_delete_time mark_chat_unread get_chat_event_log get_chat_online_count @@ -559,6 +559,7 @@ def get_title_list(s: str) -> list: GiveawayWinners Location Message + MessageAutoDeleteTimerChanged MessageEffect MessageEntity MessageImportInfo @@ -732,6 +733,7 @@ def get_title_list(s: str) -> list: Chat.mark_unread Chat.set_protected_content Chat.unpin_all_messages + Chat.set_message_auto_delete_time """, user=""" User diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index 043ab4ead5..d31d0bb89d 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -93,8 +93,8 @@ class MessageServiceType(AutoName): CHAT_SHARED = auto() "Chat Shared" - CHAT_TTL_CHANGED = auto() - "Chat TTL changed" + AUTO_DELETE_TIMER_CHANGED = auto() + "Message Auto Delete Timer changed" CHAT_BOOST_ADDED = auto() "Chat Boost Added" diff --git a/pyrogram/methods/chats/__init__.py b/pyrogram/methods/chats/__init__.py index 347e7902d3..39750d2a26 100644 --- a/pyrogram/methods/chats/__init__.py +++ b/pyrogram/methods/chats/__init__.py @@ -49,7 +49,7 @@ from .set_chat_photo import SetChatPhoto from .set_chat_protected_content import SetChatProtectedContent from .set_chat_title import SetChatTitle -from .set_chat_ttl import SetChatTTL +from .set_chat_message_auto_delete_time import SetChatMessageAutoDeleteTime from .set_chat_username import SetChatUsername from .set_send_as_chat import SetSendAsChat from .set_slow_mode import SetSlowMode @@ -76,7 +76,7 @@ class Chats( DeleteChatPhoto, SetChatTitle, SetChatDescription, - SetChatTTL, + SetChatMessageAutoDeleteTime, PinChatMessage, UnpinChatMessage, GetDialogs, diff --git a/pyrogram/methods/chats/set_chat_ttl.py b/pyrogram/methods/chats/set_chat_message_auto_delete_time.py similarity index 63% rename from pyrogram/methods/chats/set_chat_ttl.py rename to pyrogram/methods/chats/set_chat_message_auto_delete_time.py index 87ae52bb3f..50d434a123 100644 --- a/pyrogram/methods/chats/set_chat_ttl.py +++ b/pyrogram/methods/chats/set_chat_message_auto_delete_time.py @@ -19,25 +19,25 @@ from typing import Union import pyrogram -from pyrogram import raw -from pyrogram import types +from pyrogram import raw, types -class SetChatTTL: - async def set_chat_ttl( +class SetChatMessageAutoDeleteTime: + async def set_chat_message_auto_delete_time( self: "pyrogram.Client", chat_id: Union[int, str], - ttl_seconds: int + message_auto_delete_time: int ) -> "types.Message": - """Set the time-to-live for the chat. + """Changes the message auto-delete or self-destruct (for secret chats) time in a chat. + + Requires change_info administrator right in basic groups, supergroups and channels. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. - ttl_seconds (``int``): - The time-to-live for the chat. - Either 86000 for 1 day, 604800 for 1 week or 0 (zero) to disable it. + message_auto_delete_time (``int``): + New time value, in seconds; unless the chat is secret, it must be from 0 up to 365 * 86400 and be divisible by 86400. If 0, then messages aren't deleted automatically. Returns: ``bool``: True on success. @@ -45,19 +45,19 @@ async def set_chat_ttl( Example: .. code-block:: python - # Set TTL for a chat to 1 day - app.set_chat_ttl(chat_id, 86400) + # Set message auto delete for a chat to 1 day + app.set_chat_message_auto_delete_time(chat_id, 86400) - # Set TTL for a chat to 1 week - app.set_chat_ttl(chat_id, 604800) + # Set message auto delete for a chat to 1 week + app.set_chat_message_auto_delete_time(chat_id, 604800) - # Disable TTL for this chat - app.set_chat_ttl(chat_id, 0) + # Disable message auto delete for this chat + app.set_chat_message_auto_delete_time(chat_id, 0) """ r = await self.invoke( raw.functions.messages.SetHistoryTTL( peer=await self.resolve_peer(chat_id), - period=ttl_seconds, + period=message_auto_delete_time, ) ) diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index e574e21ee1..f23185b6cc 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -319,7 +319,9 @@ async def send_message( types.MessageEntity._parse(None, entity, {}) for entity in r.entities ] if r.entities else None, - chat_ttl_period=getattr(r, "ttl_period", None), + message_auto_delete_timer_changed=types.MessageAutoDeleteTimerChanged( + message_auto_delete_time=getattr(r, "ttl_period", None) + ), # TODO: #52 fix inconsistency chat=types.Chat( id=peer_id, diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index c1851cd41c..5c613c5fc8 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -57,6 +57,7 @@ from .gifted_premium import GiftedPremium from .message_effect import MessageEffect from .translated_text import TranslatedText +from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged __all__ = [ "Animation", @@ -73,6 +74,7 @@ "GiveawayWinners", "Location", "Message", + "MessageAutoDeleteTimerChanged", "MessageEffect", "MessageEntity", "MessageReactionCountUpdated", diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 798f5c1198..dc7e138b76 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -244,6 +244,9 @@ class Message(Object, Update): channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel. + message_auto_delete_timer_changed (:obj:`~pyrogram.types.MessageAutoDeleteTimerChanged`, *optional*): + Service message: auto-delete timer settings changed in the chat. + migrate_to_chat_id (``int``, *optional*): The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects @@ -378,13 +381,6 @@ class Message(Object, Update): reactions (List of :obj:`~pyrogram.types.Reaction`): List of the reactions to this message. - chat_ttl_period (``int``, *optional*): - New Time-To-Live of all messages sent in this chat. - if 0, autodeletion was disabled. - - chat_ttl_setting_from (:obj:`~pyrogram.types.User`, *optional*): - if set, the chat TTL setting was set not due to a manual change by one of participants, but automatically because one of the participants has the default TTL settings enabled. - custom_action (``str``, *optional*): Custom action (most likely not supported by the current layer, an upgrade might be needed) @@ -460,7 +456,7 @@ def __init__( group_chat_created: bool = None, supergroup_chat_created: bool = None, channel_chat_created: bool = None, - + message_auto_delete_timer_changed: "types.MessageAutoDeleteTimerChanged" = None, migrate_to_chat_id: int = None, migrate_from_chat_id: int = None, pinned_message: "Message" = None, @@ -499,8 +495,6 @@ def __init__( gift_code: "types.GiftCode" = None, gifted_premium: "types.GiftedPremium" = None, - chat_ttl_period: int = None, - chat_ttl_setting_from: "types.User" = None, empty: bool = None, mentioned: bool = None, service: "enums.MessageServiceType" = None, @@ -570,6 +564,7 @@ def __init__( self.group_chat_created = group_chat_created self.supergroup_chat_created = supergroup_chat_created self.channel_chat_created = channel_chat_created + self.message_auto_delete_timer_changed = message_auto_delete_timer_changed self.migrate_to_chat_id = migrate_to_chat_id self.migrate_from_chat_id = migrate_from_chat_id self.pinned_message = pinned_message @@ -588,8 +583,6 @@ def __init__( self.video_chat_participants_invited = video_chat_participants_invited self.web_app_data = web_app_data self.reactions = reactions - self.chat_ttl_period = chat_ttl_period - self.chat_ttl_setting_from = chat_ttl_setting_from self.link_preview_options = link_preview_options self.effect_id = effect_id self.external_reply = external_reply @@ -689,8 +682,7 @@ async def _parse( giveaway_created = None users_shared = None chat_shared = None - chat_ttl_period = None - chat_ttl_setting_from = None + message_auto_delete_timer_changed = None boost_added = None giveaway_completed = None custom_action = None @@ -850,11 +842,13 @@ async def _parse( ) elif isinstance(action, raw.types.MessageActionSetMessagesTTL): - chat_ttl_period = action.period - service_type = enums.MessageServiceType.CHAT_TTL_CHANGED + message_auto_delete_timer_changed = types.MessageAutoDeleteTimerChanged( + message_auto_delete_time=action.period + ) + service_type = enums.MessageServiceType.AUTO_DELETE_TIMER_CHANGED auto_setting_from = getattr(action, "auto_setting_from", None) if auto_setting_from: - chat_ttl_setting_from = types.User._parse( + message_auto_delete_timer_changed.from_user = types.User._parse( client, users[auto_setting_from] ) @@ -955,8 +949,7 @@ async def _parse( users_shared=users_shared, chat_shared=chat_shared, successful_payment=successful_payment, - chat_ttl_period=chat_ttl_period, - chat_ttl_setting_from=chat_ttl_setting_from, + message_auto_delete_timer_changed=message_auto_delete_timer_changed, boost_added=boost_added, forum_topic_created=forum_topic_created, forum_topic_edited=forum_topic_edited, diff --git a/pyrogram/types/messages_and_media/message_auto_delete_timer_changed.py b/pyrogram/types/messages_and_media/message_auto_delete_timer_changed.py new file mode 100644 index 0000000000..e7c9e27d5f --- /dev/null +++ b/pyrogram/types/messages_and_media/message_auto_delete_timer_changed.py @@ -0,0 +1,46 @@ +# 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 . + +import pyrogram + +from pyrogram import types +from ..object import Object + + +class MessageAutoDeleteTimerChanged(Object): + """This object represents a service message about a change in auto-delete timer settings. + + Parameters: + message_auto_delete_time (``int``): + New auto-delete time for messages in the chat; in seconds. + + from_user (:obj:`~pyrogram.types.User`, *optional*): + If set, the chat TTL setting was set not due to a manual change by one of participants, but automatically because one of the participants has the default TTL settings enabled. + + """ + + def __init__( + self, + *, + message_auto_delete_time: int = None, + from_user: "types.User" = None + ): + super().__init__() + + self.message_auto_delete_time = message_auto_delete_time + self.from_user = from_user diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 001dfae0d2..0b18ebf518 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -869,29 +869,34 @@ async def set_photo( video_start_ts=video_start_ts ) - async def set_ttl(self, ttl_seconds: int) -> "types.Message": - """Bound method *set_ttl* of :obj:`~pyrogram.types.Chat`. + async def set_message_auto_delete_time(self, message_auto_delete_time: int) -> "types.Message": + """Bound method *set_message_auto_delete_time* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: .. code-block:: python - await client.set_chat_ttl( + await client.set_chat_message_auto_delete_time( chat_id=chat_id, - ttl_seconds=ttl_seconds + message_auto_delete_time=ttl_seconds ) + Parameters: + message_auto_delete_time (``int``): + New time value, in seconds; unless the chat is secret, it must be from 0 up to 365 * 86400 and be divisible by 86400. If 0, then messages aren't deleted automatically. + Example: .. code-block:: python - await chat.set_ttl(86400) + await chat.set_message_auto_delete_time(86400) Returns: :obj:`~pyrogram.types.Message`: On success, the generated service message is returned. + """ - return await self._client.set_chat_ttl( + return await self._client.set_chat_message_auto_delete_time( chat_id=self.id, - ttl_seconds=ttl_seconds + message_auto_delete_time=message_auto_delete_time ) async def ban_member( From 00e7765c6422c9bfdaba23b90bd4dc44eb8dfe54 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 17 Jul 2024 16:12:00 +0200 Subject: [PATCH 135/154] Update Pyrogram to 2.1.32.14 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 97a129caeb..3c1efd2bbb 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.13" +__version__ = "2.1.32.14" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From 961243f1dc5b430678d03723896e66c9a51b205b Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Thu, 18 Jul 2024 08:52:13 +0530 Subject: [PATCH 136/154] fix: no response after re-connect / while re-connecting Co-authored-by: eyMarv --- pyrogram/session/session.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index b2b7acf74a..4c456d1423 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -494,9 +494,6 @@ async def invoke( timeout: float = WAIT_TIMEOUT, sleep_threshold: float = SLEEP_THRESHOLD ): - if self.instant_stop: - return # stop instantly - if isinstance(query, Session.CUR_ALWD_INNR_QRYS): inner_query = query.query else: @@ -505,9 +502,6 @@ async def invoke( query_name = ".".join(inner_query.QUALNAME.split(".")[1:]) while retries > 0: - if self.instant_stop: - return # stop instantly - # sleep until the restart is performed if self.currently_restarting: while self.currently_restarting: @@ -515,6 +509,9 @@ async def invoke( return # stop instantly await asyncio.sleep(1) + if self.instant_stop: + return # stop instantly + if not self.is_started.is_set(): await self.is_started.wait() From 1636e377c512ee2a75c3b6d14a8a9e9c867ac565 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 19 Jul 2024 18:22:29 +0200 Subject: [PATCH 137/154] Fix condition for parsing chats, in on_chat_member_updated Follow-Up: 3e33eec --- pyrogram/types/user_and_chats/chat.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 0b18ebf518..ff4bbcc1fe 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -343,6 +343,13 @@ def __init__( def _parse_user_chat(client, user: raw.types.User) -> "Chat": peer_id = user.id + if isinstance(user, raw.types.UserEmpty): + return Chat( + id=peer_id, + client=client, + _raw=user + ) + active_usernames = types.List( [ types.Username._parse(u) @@ -382,6 +389,14 @@ def _parse_user_chat(client, user: raw.types.User) -> "Chat": def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat": peer_id = -chat.id + if isinstance(chat, raw.types.ChatEmpty): + return Chat( + id=peer_id, + type=enums.ChatType.GROUP, + client=client, + _raw=chat + ) + if isinstance(chat, raw.types.ChatForbidden): return Chat( id=peer_id, @@ -642,9 +657,16 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. @staticmethod def _parse_chat(client, chat: Union[raw.types.Chat, raw.types.User, raw.types.Channel]) -> "Chat": - if isinstance(chat, raw.types.Chat): + if ( + isinstance(chat, raw.types.Chat) or + isinstance(chat, raw.types.ChatForbidden) or + isinstance(chat, raw.types.ChatEmpty) + ): return Chat._parse_chat_chat(client, chat) - elif isinstance(chat, raw.types.User): + elif ( + isinstance(chat, raw.types.User) or + isinstance(chat, raw.types.UserEmpty) + ): return Chat._parse_user_chat(client, chat) else: return Chat._parse_channel_chat(client, chat) From e82e8381e0c33d6fe866c9c0a61419355f59a7f4 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Sat, 20 Jul 2024 15:51:01 +0530 Subject: [PATCH 138/154] Fix documentation mistakes and MReBrand (#63) --- .github/workflows/build-docs.yml | 4 ++- README.md | 9 ++++++ compiler/docs/template/types.rst | 8 ++--- compiler/errors/source/400_BAD_REQUEST.tsv | 2 +- compiler/errors/source/403_FORBIDDEN.tsv | 2 +- compiler/errors/source/406_NOT_ACCEPTABLE.tsv | 2 +- compiler/errors/source/420_FLOOD.tsv | 2 +- .../source/500_INTERNAL_SERVER_ERROR.tsv | 2 +- docs/source/api/storage/Storage.rst | 2 +- docs/source/api/storage/index.rst | 32 ++++++++++++++++++- docs/source/index.rst | 4 ++- docs/source/releases/changes-in-this-fork.rst | 8 ++--- docs/source/start/errors.rst | 10 ++++++ docs/source/static/css/custom.css | 2 +- pyproject.toml | 4 +-- pyrogram/methods/business/__init__.py | 1 + .../methods/business/answer_shipping_query.py | 2 +- .../methods/chat_topics/create_forum_topic.py | 2 +- .../methods/chat_topics/edit_forum_topic.py | 2 +- 19 files changed, 77 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index c6bd18ea2b..fc8524a9ec 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -15,10 +15,12 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' - name: Install dependencies run: | + pip install httpx==0.27.0 lxml==5.2.2 + curl -sL https://github.com/hydrogram/hydrogram/raw/013268c/dev_tools/generate_docs_json.py | python make rm -rf .github compiler Pyrogram* pyrogram* tests .gitignore COPYING* rm -f MANIFEST* Makefile NOTICE README.md diff --git a/README.md b/README.md index 6b904e2987..f029a419da 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +## [Fork Documentation](https://telegramplayground.github.io/pyrogram/) + +## Installing this Fork + +```bash +pip install PyroTGFork +``` + +

Pyrogram diff --git a/compiler/docs/template/types.rst b/compiler/docs/template/types.rst index 7fe8f57d73..a58ad9aa24 100644 --- a/compiler/docs/template/types.rst +++ b/compiler/docs/template/types.rst @@ -87,7 +87,7 @@ Input Media {input_media} Input Paid Media ------------ +----------------- .. autosummary:: :nosignatures: @@ -100,7 +100,7 @@ Input Paid Media {input_paid_media} Inline Mode ------------ +------------ .. autosummary:: :nosignatures: @@ -139,7 +139,7 @@ Authorization {authorization} Chat Forum Topics -------------- +------------------ .. autosummary:: :nosignatures: @@ -152,7 +152,7 @@ Chat Forum Topics {chat_topics} Telegram Business -------------- +------------------ .. autosummary:: :nosignatures: diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index 5db312ab14..5261ea3a65 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -518,4 +518,4 @@ WEBPAGE_URL_INVALID The specified webpage `url` is invalid. WEBPUSH_AUTH_INVALID The specified web push authentication secret is invalid. WEBPUSH_KEY_INVALID The specified web push elliptic curve Diffie-Hellman public key is invalid. WEBPUSH_TOKEN_INVALID The specified web push token is invalid. -YOU_BLOCKED_USER You blocked this user. +YOU_BLOCKED_USER You blocked this user. \ No newline at end of file diff --git a/compiler/errors/source/403_FORBIDDEN.tsv b/compiler/errors/source/403_FORBIDDEN.tsv index e7a16b811e..557f5416b8 100644 --- a/compiler/errors/source/403_FORBIDDEN.tsv +++ b/compiler/errors/source/403_FORBIDDEN.tsv @@ -43,4 +43,4 @@ USER_IS_BLOCKED You were blocked by this user. USER_NOT_MUTUAL_CONTACT The provided user is not a mutual contact. USER_PRIVACY_RESTRICTED The user's privacy settings do not allow you to do this. USER_RESTRICTED You're spamreported, you can't create channels or chats. -VOICE_MESSAGES_FORBIDDEN This user's privacy settings forbid you from sending voice messages. +VOICE_MESSAGES_FORBIDDEN This user's privacy settings forbid you from sending voice messages. \ No newline at end of file diff --git a/compiler/errors/source/406_NOT_ACCEPTABLE.tsv b/compiler/errors/source/406_NOT_ACCEPTABLE.tsv index d12d409f8e..19dc3af52b 100644 --- a/compiler/errors/source/406_NOT_ACCEPTABLE.tsv +++ b/compiler/errors/source/406_NOT_ACCEPTABLE.tsv @@ -22,4 +22,4 @@ TOPIC_CLOSED This topic was closed, you can't send messages to it anymore. TOPIC_DELETED The specified topic was deleted. USERPIC_PRIVACY_REQUIRED You need to disable privacy settings for your profile picture in order to make your geolocation public. USERPIC_UPLOAD_REQUIRED You must have a profile picture to publish your geolocation. -USER_RESTRICTED You're spamreported, you can't create channels or chats. +USER_RESTRICTED You're spamreported, you can't create channels or chats. \ No newline at end of file diff --git a/compiler/errors/source/420_FLOOD.tsv b/compiler/errors/source/420_FLOOD.tsv index 8242c574f3..9e17e5a3c7 100644 --- a/compiler/errors/source/420_FLOOD.tsv +++ b/compiler/errors/source/420_FLOOD.tsv @@ -6,4 +6,4 @@ FLOOD_WAIT_X A wait of {value} seconds is required PREMIUM_SUB_ACTIVE_UNTIL_X You already have a premium subscription active until unixtime {value} . SLOWMODE_WAIT_X Slowmode is enabled in this chat: wait {value} seconds before sending another message to this chat. STORY_SEND_FLOOD_X A wait of {value} seconds is required to continue posting stories -TAKEOUT_INIT_DELAY_X Sorry, for security reasons, you will be able to begin downloading your data in {value} seconds. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not. +TAKEOUT_INIT_DELAY_X Sorry, for security reasons, you will be able to begin downloading your data in {value} seconds. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not. \ No newline at end of file diff --git a/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv b/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv index 608f7f569e..dac5110c40 100644 --- a/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv +++ b/compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv @@ -48,4 +48,4 @@ UNKNOWN_METHOD The method you tried to call cannot be called on non-CDN DCs UPLOAD_NO_VOLUME Telegram is having internal problems. Please try again later VOLUME_LOC_NOT_FOUND Telegram is having internal problems. Please try again later WORKER_BUSY_TOO_LONG_RETRY Server workers are too busy right now due to Telegram having internal problems. Please try again later -WP_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later +WP_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later \ No newline at end of file diff --git a/docs/source/api/storage/Storage.rst b/docs/source/api/storage/Storage.rst index 56b0f391f2..4682131487 100644 --- a/docs/source/api/storage/Storage.rst +++ b/docs/source/api/storage/Storage.rst @@ -1,5 +1,5 @@ Storage -========= +======== .. autoclass:: pyrogram.storage.Storage() :members: diff --git a/docs/source/api/storage/index.rst b/docs/source/api/storage/index.rst index 52f898bbd5..3ea50bf3d4 100644 --- a/docs/source/api/storage/index.rst +++ b/docs/source/api/storage/index.rst @@ -1,5 +1,5 @@ Pyrogram Storage Engines -=============== +========================= Storage Engines =============== @@ -88,6 +88,36 @@ login using the same session; the storage used will still be in-memory: Session strings are useful when you want to run authorized Pyrogram clients on platforms where their ephemeral filesystems makes it harder for a file-based storage engine to properly work as intended. +Custom Storages +---------------- + +If you want to use a custom storage engine, you can do so by implementing the :obj:`~pyrogram.storage.Storage` class. This class is an base class that defines the interface that all storage engines must implement. + +This class is a class that cannot be instantiated, but can be used to define a common interface for its subclasses. In this case, the :obj:`~pyrogram.storage.Storage` class defines the interface that all storage engines must implement. + +Custom Storage can be defined in :obj:`~pyrogram.Client` by passing ``storage_engine`` parameter with a :obj:`~pyrogram.storage.Storage` subclass. + +How to use the ``AioSQLiteStorage`` Storage Engine is shown below +^^^^^^^^^^^^^^ + +``/path/to/your/file.session`` will be created if does not exist. + +.. code-block:: python + import asyncio + from pyrogram import Client + from pyrogram.storage.aio_sqlite_storage import AioSQLiteStorage + api_id = 12345 + api_hash = "0123456789abcdef0123456789abcdef" + async def main(): + async with Client( + "my_account", + api_id, + api_hash, + storage_engine=AioSQLiteStorage("/path/to/your/file.session") + ) as app: + await app.send_message(chat_id="me", text="Greetings from **Pyrogram**!") + asyncio.run(main()) + Details ------- diff --git a/docs/source/index.rst b/docs/source/index.rst index a860edcd2b..c81072852c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,4 +1,4 @@ -Welcome to Pyrogram +Welcome to ``PyroTGFork`` =================== .. admonition :: A Word of Warning @@ -180,6 +180,8 @@ Meta :hidden: :caption: Telegram Raw API + TL Schema Explorer + TL Diff telegram/functions/index telegram/types/index telegram/base/index diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index b7e2b42475..6ccde75579 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -1,5 +1,5 @@ Changes in this Fork -========= +===================== This page lists all the documented changes of this fork, in reverse chronological order. You should read this when upgrading @@ -31,7 +31,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__. @@ -253,7 +253,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_). - Add `waveform` parameter to :meth:`~pyrogram.Client.send_voice`. - Added `view_once` parameter to :meth:`~pyrogram.Client.send_photo`, :meth:`~pyrogram.Client.send_video`, :meth:`~pyrogram.Client.send_video_note`, :meth:`~pyrogram.Client.send_voice`. -- Add missing parameters to :obj:`~pyrogram.types.Message.reply_photo`, :obj:`~pyrogram.types.Message.reply_video`, :obj:`~pyrogram.types.Message.reply_video_note`, :obj:`~pyrogram.types.Message.reply_voice`. +- Add missing parameters to :meth:`~pyrogram.types.Message.reply_photo`, :meth:`~pyrogram.types.Message.reply_video`, :meth:`~pyrogram.types.Message.reply_video_note`, :meth:`~pyrogram.types.Message.reply_voice`. +------------------------+ | Scheme layer used: 170 | @@ -276,7 +276,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ diff --git a/docs/source/start/errors.rst b/docs/source/start/errors.rst index 4a86fbbe5f..f6346fd1b8 100644 --- a/docs/source/start/errors.rst +++ b/docs/source/start/errors.rst @@ -77,6 +77,16 @@ In case Pyrogram does not know anything about a specific error yet, it raises a for example, an unknown error with error code ``400``, will be raised as a ``BadRequest``. This way you can catch the whole category of errors and be sure to also handle these unknown errors. +.. admonition :: RPC Errors + :class: tip + + There isn't any official list of all possible RPC errors, so the list of known errors is provided on a best-effort basis. When new methods are available, the list may be lacking since we simply don't know what errors can raise from them. Pyrogram creates an `unknown_errors.txt` file in the root directory from where the `Client` is run. + +.. admonition :: `... `__ + + If you want the file to be created in a different location, set the ``PYROGRAM_LOG_UNKNOWN_ERRORS_FILENAME`` to an absolute file path of your choice. + + Errors with Values ------------------ diff --git a/docs/source/static/css/custom.css b/docs/source/static/css/custom.css index ce751ec73f..d101d69f21 100644 --- a/docs/source/static/css/custom.css +++ b/docs/source/static/css/custom.css @@ -7,7 +7,7 @@ border: 1px ; border-radius: .2em; padding: 2px 5px; - background-color: #1a1c1e; + /* background-color: #1a1c1e; */ } .sidebar-logo { diff --git a/pyproject.toml b/pyproject.toml index 7f61cb154a..098feed1fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,10 +40,10 @@ path = "pyrogram/__init__.py" [tool.hatch.build.hooks.custom] [project.urls] -Homepage = "https://telegramplayground.github.io/pyrogram/releases/" +Homepage = "https://telegramplayground.github.io/pyrogram/" Tracker = "https://github.com/TelegramPlayGround/Pyrogram/issues" Source = "https://github.com/TelegramPlayGround/Pyrogram" -Documentation = "https://telegramplayground.github.io/pyrogram/" +Documentation = "https://telegramplayground.github.io/pyrogram/releases/changes-in-this-fork.html" [build-system] requires = ["hatchling"] diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index b205ed97bb..287b8588e4 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -27,6 +27,7 @@ class TelegramBusiness( AnswerPreCheckoutQuery, + AnswerShippingQuery, CreateInvoiceLink, GetBusinessConnection, GetCollectibleItemInfo, diff --git a/pyrogram/methods/business/answer_shipping_query.py b/pyrogram/methods/business/answer_shipping_query.py index ab41200bd3..a5a5161587 100644 --- a/pyrogram/methods/business/answer_shipping_query.py +++ b/pyrogram/methods/business/answer_shipping_query.py @@ -30,7 +30,7 @@ async def answer_shipping_query( shipping_options: List["types.ShippingOptions"] = None, error_message: str = None ): - """If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the API sends the confirmation in the form of an :obj:`~pyrogram.handlers.ShippingQueryHandler`. + """If you sent an invoice requesting a shipping address and the parameter ``is_flexible`` was specified, the API sends the confirmation in the form of an :obj:`~pyrogram.handlers.ShippingQueryHandler`. Use this method to reply to shipping queries. diff --git a/pyrogram/methods/chat_topics/create_forum_topic.py b/pyrogram/methods/chat_topics/create_forum_topic.py index 41283c3660..4f8113558a 100644 --- a/pyrogram/methods/chat_topics/create_forum_topic.py +++ b/pyrogram/methods/chat_topics/create_forum_topic.py @@ -51,7 +51,7 @@ async def create_forum_topic( Currently, must be one of 7322096 (0x6FB9F0), 16766590 (0xFFD67E), 13338331 (0xCB86DB), 9367192 (0x8EEE98), 16749490 (0xFF93B2), or 16478047 (0xFB6F5F) icon_custom_emoji_id (``str``, *optional*): - Unique identifier of the custom emoji shown as the topic icon. Use :meth:`~pyrogram.Client.getForumTopicIconStickers` to get all allowed custom emoji identifiers. + Unique identifier of the custom emoji shown as the topic icon. Use :meth:`~pyrogram.Client.get_forum_topic_icon_stickers` to get all allowed custom emoji identifiers. send_as (``int`` | ``str``, *optional*): Unique identifier (int) or username (str) of the as chat. diff --git a/pyrogram/methods/chat_topics/edit_forum_topic.py b/pyrogram/methods/chat_topics/edit_forum_topic.py index 060e05a5f6..82e229d9b1 100644 --- a/pyrogram/methods/chat_topics/edit_forum_topic.py +++ b/pyrogram/methods/chat_topics/edit_forum_topic.py @@ -49,7 +49,7 @@ async def edit_forum_topic( New topic name, 0-128 characters. If not specified or empty, the current name of the topic will be kept icon_custom_emoji_id (``str``, *optional*): - New unique identifier of the custom emoji shown as the topic icon. Use :meth:`~pyrogram.Client.getForumTopicIconStickers` to get all allowed custom emoji identifiers. Pass an empty string to remove the icon. If not specified, the current icon will be kept + New unique identifier of the custom emoji shown as the topic icon. Use :meth:`~pyrogram.Client.get_forum_topic_icon_stickers` to get all allowed custom emoji identifiers. Pass an empty string to remove the icon. If not specified, the current icon will be kept Returns: :obj:`~pyrogram.types.Message`: On success, the edited message is returned. From 898288ad05bd780b3a4cf9157bcb4a479cb52a75 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Sat, 20 Jul 2024 13:11:35 +0200 Subject: [PATCH 139/154] Add get_active_sessions Stealing IDEA from hydrogram/hydrogram#41 --- compiler/docs/compiler.py | 3 + docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/auth/__init__.py | 2 + pyrogram/methods/auth/get_active_sessions.py | 40 +++++ pyrogram/types/authorization/__init__.py | 4 + .../types/authorization/active_session.py | 150 ++++++++++++++++++ .../types/authorization/active_sessions.py | 58 +++++++ 7 files changed, 258 insertions(+) create mode 100644 pyrogram/methods/auth/get_active_sessions.py create mode 100644 pyrogram/types/authorization/active_session.py create mode 100644 pyrogram/types/authorization/active_sessions.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 88767d9e8c..fc829b02bf 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -168,6 +168,7 @@ def get_title_list(s: str) -> list: recover_password accept_terms_of_service log_out + get_active_sessions """, bots=""" Bots @@ -435,6 +436,8 @@ def get_title_list(s: str) -> list: categories = dict( authorization=""" Authorization + ActiveSession + ActiveSessions SentCode TermsOfService """, diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 6ccde75579..c761e63a0b 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) diff --git a/pyrogram/methods/auth/__init__.py b/pyrogram/methods/auth/__init__.py index ce585648da..48640cd4a6 100644 --- a/pyrogram/methods/auth/__init__.py +++ b/pyrogram/methods/auth/__init__.py @@ -20,6 +20,7 @@ from .check_password import CheckPassword from .connect import Connect from .disconnect import Disconnect +from .get_active_sessions import GetActiveSessions from .get_password_hint import GetPasswordHint from .initialize import Initialize from .log_out import LogOut @@ -38,6 +39,7 @@ class Auth( CheckPassword, Connect, Disconnect, + GetActiveSessions, GetPasswordHint, Initialize, LogOut, diff --git a/pyrogram/methods/auth/get_active_sessions.py b/pyrogram/methods/auth/get_active_sessions.py new file mode 100644 index 0000000000..d8c906b860 --- /dev/null +++ b/pyrogram/methods/auth/get_active_sessions.py @@ -0,0 +1,40 @@ +# 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 List + +import pyrogram +from pyrogram import raw, types + + +class GetActiveSessions: + async def get_active_sessions( + self: "pyrogram.Client" + ) -> "types.ActiveSessions": + """Returns all active sessions of the current user. + + .. include:: /_includes/usable-by/users.rst + + Returns: + :obj:`~pyrogram.types.ActiveSessions`: On success, all the active sessions of the current user is returned. + + """ + r = await self.invoke( + raw.functions.account.GetAuthorizations() + ) + return types.ActiveSessions._parse(r) diff --git a/pyrogram/types/authorization/__init__.py b/pyrogram/types/authorization/__init__.py index 382e161092..04a34f2a48 100644 --- a/pyrogram/types/authorization/__init__.py +++ b/pyrogram/types/authorization/__init__.py @@ -16,10 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from .active_session import ActiveSession +from .active_sessions import ActiveSessions from .sent_code import SentCode from .terms_of_service import TermsOfService __all__ = [ + "ActiveSession", + "ActiveSessions", "SentCode", "TermsOfService", ] diff --git a/pyrogram/types/authorization/active_session.py b/pyrogram/types/authorization/active_session.py new file mode 100644 index 0000000000..f338d74cdf --- /dev/null +++ b/pyrogram/types/authorization/active_session.py @@ -0,0 +1,150 @@ +# 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 datetime import datetime + +from pyrogram import raw, utils + +from ..object import Object + + +class ActiveSession(Object): + """Contains information about one session in a Telegram application used by the current user. Sessions must be shown to the user in the returned order. + + Parameters: + id (``int``): + Session identifier. + + device_model (``str``): + Model of the device the application has been run or is running on, as provided by the application. + + platform (``str``): + Operating system the application has been run or is running on, as provided by the application. + + system_version (``str``): + Version of the operating system the application has been run or is running on, as provided by the application. + + api_id (``int``): + Telegram API identifier, as provided by the application. + + application_name (``str``): + Name of the application, as provided by the application. + + application_version (``str``): + The version of the application, as provided by the application. + + log_in_date (:py:obj:`~datetime.datetime`, *optional*): + Point in time (Unix timestamp) when the user has logged in. + + last_active_date (:py:obj:`~datetime.datetime`, *optional*): + Point in time (Unix timestamp) when the session was last used. + + ip_address (``str``): + IP address from which the session was created, in human-readable format. + + location (``str``): + A human-readable description of the location from which the session was created, based on the IP address. + + country (``str``): + Country. + + is_current (``bool``): + True, if this session is the current session. + + is_password_pending (``bool``): + True, if a 2-step verification password is needed to complete authorization of the session. + + is_unconfirmed (``bool``): + True, if the session wasn't confirmed from another session. + + can_accept_secret_chats (``bool``): + True, if incoming secret chats can be accepted by the session. + + can_accept_calls (``bool``): + True, if incoming calls can be accepted by the session. + + is_official_application (``bool``): + True, if the application is an official application or uses the api_id of an official application. + + """ + + def __init__( + self, + *, + id: int = None, + device_model: str = None, + platform: str = None, + system_version: str = None, + api_id: int = None, + application_name: str = None, + application_version: str = None, + log_in_date: datetime = None, + last_active_date: datetime = None, + ip_address: str = None, + location: str = None, + country: str = None, + is_current: bool = None, + is_password_pending: bool = None, + is_unconfirmed: bool = None, + can_accept_secret_chats: bool = None, + can_accept_calls: bool = None, + is_official_application: bool = None + ): + super().__init__() + + self.id = id + self.device_model = device_model + self.platform = platform + self.system_version = system_version + self.api_id = api_id + self.application_name = application_name + self.application_version = application_version + self.log_in_date = log_in_date + self.last_active_date = last_active_date + self.ip_address = ip_address + self.location = location + self.country = country + self.is_current = is_current + self.is_password_pending = is_password_pending + self.is_unconfirmed = is_unconfirmed + self.can_accept_secret_chats = can_accept_secret_chats + self.can_accept_calls = can_accept_calls + self.is_official_application = is_official_application + + @staticmethod + def _parse(session: "raw.types.Authorization") -> "ActiveSession": + return ActiveSession( + id=session.hash, + device_model=session.device_model, + platform=session.platform, + system_version=session.system_version, + api_id=session.api_id, + application_name=session.app_name, + application_version=session.app_version, + log_in_date=utils.timestamp_to_datetime(session.date_created), + last_active_date=utils.timestamp_to_datetime(session.date_active), + ip_address=session.ip, + location=session.region, + country=session.country, + is_current=getattr(session, "current", None), + is_password_pending=getattr(session, "password_pending", None), + is_unconfirmed=getattr(session, "unconfirmed", None), + can_accept_secret_chats=not getattr(session, "encrypted_requests_disabled", False), + can_accept_calls=not getattr(session, "call_requests_disabled", False), + is_official_application=getattr(session, "official_app", None) + ) diff --git a/pyrogram/types/authorization/active_sessions.py b/pyrogram/types/authorization/active_sessions.py new file mode 100644 index 0000000000..414e3e70b7 --- /dev/null +++ b/pyrogram/types/authorization/active_sessions.py @@ -0,0 +1,58 @@ +# 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 List + +import pyrogram +from pyrogram import raw, types, utils + +from ..object import Object + + +class ActiveSessions(Object): + """Contains a list of sessions + + Parameters: + inactive_session_ttl_days (``int``): + Number of days of inactivity before sessions will automatically be terminated; 1-366 days. + + active_sessions (List of :obj:`~pyrogram.types.ActiveSession`): + List of sessions. + + """ + + def __init__( + self, + *, + inactive_session_ttl_days: int = None, + active_sessions: List["types.ActiveSession"] = None + ): + super().__init__() + + self.inactive_session_ttl_days = inactive_session_ttl_days + self.active_sessions = active_sessions + + @staticmethod + def _parse(authorizations: "raw.types.account.Authorizations") -> "ActiveSessions": + return ActiveSessions( + inactive_session_ttl_days=authorizations.authorization_ttl_days, + active_sessions=types.List([ + types.ActiveSession._parse(active) + for active in authorizations.authorizations + ]) + ) From cdf9040d8a52401179a201ddb711fa8af4e84687 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Wed, 24 Jul 2024 11:05:48 +0530 Subject: [PATCH 140/154] Fix documentation mistake Adapt to https://core.telegram.org/api/bots/ids --- pyrogram/session/session.py | 13 ++++++------- pyrogram/utils.py | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 4c456d1423..5ad6ad1af7 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -121,7 +121,7 @@ def __init__( async def start(self): while True: if self.instant_stop: - log.info("session init stopped") + log.info("session init force stopped (loop)") return # stop instantly self.connection = self.client.connection_factory( @@ -406,12 +406,11 @@ async def recv_worker(self): if packet: error_code = -Int.read(BytesIO(packet)) - if error_code == 404: - raise Unauthorized( - "Auth key not found in the system. You must delete your session file " - "and log in again with your phone number or bot token." - ) - + # if error_code == 404: + # raise Unauthorized( + # "Auth key not found in the system. You must delete your session file " + # "and log in again with your phone number or bot token." + # ) log.warning( "[%s] Server sent transport error: %s (%s)", self.client.name, diff --git a/pyrogram/utils.py b/pyrogram/utils.py index 18a45ce483..34ba51d2b9 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -238,7 +238,7 @@ def unpack_inline_message_id(inline_message_id: str) -> "raw.base.InputBotInline MIN_CHANNEL_ID_OLD = -1002147483647 -MIN_CHANNEL_ID = -1007852516352 +MIN_CHANNEL_ID = -100997852516352 MAX_CHANNEL_ID = -1000000000000 MIN_CHAT_ID_OLD = -2147483647 MIN_CHAT_ID = -999999999999 From 5af68c35ca090c05059c99c2ef1b0bb319a7d6cf Mon Sep 17 00:00:00 2001 From: Harsh <65716674+Harsh-br0@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:49:23 +0200 Subject: [PATCH 141/154] Update filters.via_bot Credits: https://t.me/c/1220993104/1379725 https://t.me/c/1220993104/1379819 --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/filters.py | 32 ++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index c761e63a0b..4ac5be47e1 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue bool: # region via_bot_filter -async def via_bot_filter(_, __, m: Message) -> bool: - return bool(m.via_bot) +def via_bot_filter(flt, *args): + # https://t.me/c/1220993104/1379819 + if isinstance(args[0], pyrogram.Client): + _, m, *__ = args + return bool(m.via_bot) and ( + len(flt) == 0 + or ( + m.via_bot.id in flt or ( + m.via_bot.username and m.via_bot.username.lower() in flt + ) + ) + ) + bots = args[0] if isinstance(args[0], list) else [args[0]] + flt = type(flt)(u.lower().lstrip("@") if isinstance(u, str) else u for u in bots) + return flt +via_bot: Filter = type( + via_bot_filter.__name__, + (Filter, set), + dict(__call__=via_bot_filter), +)() +"""Filter messages sent via inline bots -via_bot: Filter = create(via_bot_filter) -"""Filter messages sent via inline bots""" + Parameters: + user_ids (``int`` | ``str`` | Iterable of ``int`` | Iterable of ``str``, *optional*): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + Defaults to None (all bots). +""" # endregion From c0db4cbc490a549a17b130ce36f44e60f8d066b8 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Wed, 24 Jul 2024 22:19:18 +0530 Subject: [PATCH 142/154] Documentation Improvements (#66) --- compiler/docs/compiler.py | 560 ++++++++++--------- compiler/docs/template/bound-methods.rst | 2 +- compiler/docs/template/methods.rst | 84 +-- compiler/docs/template/types.rst | 50 +- docs/source/.readthedocs.yaml | 53 ++ docs/source/conf.py | 9 + docs/source/requirements.txt | 5 + docs/source/static/css/all.min.css | 2 +- pyrogram/enums/message_service_type.py | 2 +- pyrogram/types/messages_and_media/message.py | 2 +- 10 files changed, 419 insertions(+), 350 deletions(-) create mode 100644 docs/source/.readthedocs.yaml create mode 100644 docs/source/requirements.txt diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index fc829b02bf..da17bc2cba 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -135,89 +135,116 @@ def get_title_list(s: str) -> list: categories = dict( utilities=""" Utilities + run start stop restart - run + export_session_string add_handler remove_handler - export_session_string stop_transmission set_parse_mode """, - advanced=""" - Advanced - invoke - resolve_peer - save_file - """, authorization=""" Authorization - connect - disconnect initialize - terminate - send_code - resend_code + sign_up + accept_terms_of_service sign_in sign_in_bot - sign_up + connect + send_code + resend_code + recover_password + send_recovery_code get_password_hint check_password - send_recovery_code - recover_password - accept_terms_of_service log_out + disconnect + terminate + get_me get_active_sessions """, - bots=""" - Bots - get_inline_bot_results - send_inline_bot_result - answer_callback_query - answer_inline_query - request_callback_answer - send_game - set_game_score - get_game_high_scores - set_bot_commands - get_bot_commands - delete_bot_commands - set_bot_default_privileges - get_bot_default_privileges - set_chat_menu_button - get_chat_menu_button - answer_web_app_query - send_web_app_custom_request - set_bot_name - get_bot_name - set_bot_info_description - get_bot_info_description - set_bot_info_short_description - get_bot_info_short_description + messages=""" + Messages + send_message + forward_messages + copy_message + send_photo + send_audio + send_document + send_video + send_animation + send_voice + send_video_note + send_cached_media + send_paid_media + send_media_group + get_media_group + copy_media_group + send_location + send_venue + send_contact + send_poll + send_dice + send_chat_action + set_reaction + download_media + stream_media + edit_message_text + edit_inline_text + edit_message_caption + edit_inline_caption + edit_message_media + edit_inline_media + edit_message_reply_markup + edit_inline_reply_markup + edit_cached_media + stop_poll + delete_messages + get_chat_sponsored_messages + get_chat_history + get_chat_history_count + read_chat_history + get_messages + view_messages + get_discussion_message + get_discussion_replies + get_discussion_replies_count + search_global + search_global_count + search_messages + search_messages_count + search_public_messages_by_tag + count_public_messages_by_tag + vote_poll + retract_vote + translate_text + translate_message_text """, chats=""" Chats - join_chat - leave_chat - search_chats ban_chat_member unban_chat_member restrict_chat_member promote_chat_member set_administrator_title + set_chat_permissions set_chat_photo delete_chat_photo set_chat_title set_chat_description - set_chat_permissions pin_chat_message unpin_chat_message unpin_all_chat_messages + search_chats + join_chat + leave_chat get_chat - get_chat_member get_chat_members get_chat_members_count + get_chat_member + get_dialogs get_dialogs_count set_chat_username @@ -242,136 +269,45 @@ def get_title_list(s: str) -> list: get_created_chats transfer_chat_ownership """, - chat_topics=""" - Chat Forum Topics - close_forum_topic - create_forum_topic - delete_forum_topic - edit_forum_topic - get_forum_topic_icon_stickers - hide_forum_topic - reopen_forum_topic - unhide_forum_topic - get_forum_topics - get_forum_topic - """, - contacts=""" - Contacts - add_contact - delete_contacts - import_contacts - get_contacts - get_contacts_count - """, invite_links=""" Invite Links - get_chat_invite_link export_chat_invite_link create_chat_invite_link edit_chat_invite_link revoke_chat_invite_link - delete_chat_invite_link - get_chat_invite_link_joiners - get_chat_invite_link_joiners_count get_chat_admin_invite_links get_chat_admin_invite_links_count get_chat_admins_with_invite_links - get_chat_join_requests + get_chat_invite_link + get_chat_invite_link_joiners + get_chat_invite_link_joiners_count + delete_chat_invite_link delete_chat_admin_invite_links + get_chat_join_requests approve_chat_join_request approve_all_chat_join_requests decline_chat_join_request - decline_all_chat_join_requests - """, - messages=""" - Messages - copy_media_group - copy_message - delete_messages - download_media - edit_cached_media - edit_inline_caption - edit_inline_media - edit_inline_reply_markup - edit_inline_text - edit_message_caption - edit_message_media - edit_message_reply_markup - edit_message_text - forward_messages - get_chat_history - get_chat_history_count - get_custom_emoji_stickers - get_discussion_message - get_discussion_replies - get_discussion_replies_count - get_media_group - get_messages - read_chat_history - retract_vote - search_global - search_global_count - search_messages - search_messages_count - search_public_messages_by_tag - count_public_messages_by_tag - send_animation - send_audio - send_cached_media - send_chat_action - send_contact - send_dice - send_document - send_location - send_paid_media - send_media_group - send_message - send_photo - send_poll - send_sticker - send_venue - send_video - send_video_note - send_voice - set_reaction - stop_poll - stream_media - view_messages - vote_poll - get_chat_sponsored_messages - translate_text - translate_message_text - """, - password=""" - Password - enable_cloud_password - change_cloud_password - remove_cloud_password + decline_all_chat_join_requests """, - phone=""" - Phone - create_video_chat - discard_group_call - get_video_chat_rtmp_url - invite_group_call_participants - load_group_call_participants - - """, - stickers=""" - Stickers - get_message_effects - get_stickers - """, - stories=""" - Stories - get_stories + chat_topics=""" + Chat Forum Topics + get_forum_topic_icon_stickers + create_forum_topic + edit_forum_topic + close_forum_topic + reopen_forum_topic + delete_forum_topic + hide_forum_topic + unhide_forum_topic + get_forum_topics + get_forum_topic """, users=""" Users - get_me - get_users get_chat_photos get_chat_photos_count + get_users + set_profile_photo delete_profile_photos set_username @@ -386,16 +322,82 @@ def get_title_list(s: str) -> list: delete_account update_status """, - business=""" - Telegram Business & Fragment - answer_pre_checkout_query - answer_shipping_query + contacts=""" + Contacts + add_contact + delete_contacts + import_contacts + get_contacts + get_contacts_count + """, + password=""" + Password + enable_cloud_password + change_cloud_password + remove_cloud_password + """, + bots=""" + Bots + answer_callback_query + request_callback_answer + set_bot_commands + delete_bot_commands + get_bot_commands + set_bot_name + get_bot_name + set_bot_info_description + get_bot_info_description + set_bot_info_short_description + get_bot_info_short_description + set_chat_menu_button + get_chat_menu_button + set_bot_default_privileges + get_bot_default_privileges + send_game + set_game_score + get_game_high_scores + answer_inline_query + get_inline_bot_results + send_inline_bot_result + answer_web_app_query + send_web_app_custom_request + """, + phone=""" + Phone + create_video_chat + discard_group_call + get_video_chat_rtmp_url + invite_group_call_participants + load_group_call_participants + """, + stickers=""" + Stickers + send_sticker + get_custom_emoji_stickers + get_message_effects + get_stickers + """, + stories=""" + Stories + get_stories + """, + payments=""" + Payments + send_invoice create_invoice_link + answer_shipping_query + answer_pre_checkout_query + refund_star_payment get_business_connection get_collectible_item_info - refund_star_payment - send_invoice - """, + """, + advanced=""" + Advanced + invoke + resolve_peer + get_file + save_file + """ ) root = PYROGRAM_API_DEST + "/methods" @@ -434,12 +436,106 @@ def get_title_list(s: str) -> list: # Types categories = dict( - authorization=""" - Authorization - ActiveSession - ActiveSessions - SentCode - TermsOfService + users_chats=""" + Users & Chats + Birthdate + User + Chat + Username + ChatShared + UsersShared + ChatAdminWithInviteLinks + ChatColor + ChatEvent + ChatEventFilter + ChatInviteLink + ChatJoiner + ChatJoinRequest + ChatMember + ChatMemberUpdated + ChatPermissions + ChatPhoto + ChatPrivileges + ChatReactions + VideoChatScheduled + VideoChatStarted + VideoChatEnded + VideoChatParticipantsInvited + Dialog + EmojiStatus + GroupCallParticipant + InviteLinkImporter + Restriction + RtmpUrl + """, + messages_media=""" + Messages & Media + Message + MessageEntity + TextQuote + ExternalReplyInfo + ReplyParameters + MessageOrigin + MessageOriginUser + MessageOriginHiddenUser + MessageOriginChat + MessageOriginChannel + MessageImportInfo + Photo + Animation + Audio + Document + Story + Video + VideoNote + Voice + PaidMediaInfo + PaidMedia + PaidMediaPreview + PaidMediaPhoto + PaidMediaVideo + Contact + Dice + PollOption + InputPollOption + Poll + Location + Venue + WebAppData + MessageAutoDeleteTimerChanged + ChatBoostAdded + ChatBackground + Game + GiftCode + GiftedPremium + Giveaway + GiveawayCompleted + GiveawayWinners + MessageEffect + MessageReactionCountUpdated + MessageReactionUpdated + MessageReactions + Reaction + ReactionCount + ReactionType + ReactionTypeEmoji + ReactionTypeCustomEmoji + Thumbnail + TranslatedText + StrippedThumbnail + SponsoredMessage + Sticker + WebPage + """, + chat_topics=""" + Chat Forum Topics + ForumTopic + ForumTopicCreated + ForumTopicClosed + ForumTopicEdited + ForumTopicReopened + GeneralForumTopicHidden + GeneralForumTopicUnhidden """, bot_commands=""" Bot Commands @@ -478,16 +574,6 @@ def get_title_list(s: str) -> list: SentWebAppMessage SwitchInlineQueryChosenChat """, - chat_topics=""" - Chat Forum Topics - ForumTopic - ForumTopicClosed - ForumTopicCreated - ForumTopicEdited - ForumTopicReopened - GeneralForumTopicHidden - GeneralForumTopicUnhidden - """, inline_mode=""" Inline Mode ChosenInlineResult @@ -511,6 +597,13 @@ def get_title_list(s: str) -> list: InlineQueryResultLocation InlineQueryResultVenue """, + authorization=""" + Authorization + ActiveSession + ActiveSessions + SentCode + TermsOfService + """, input_media=""" Input Media InputMedia @@ -527,125 +620,34 @@ def get_title_list(s: str) -> list: InputPaidMedia InputPaidMediaPhoto InputPaidMediaVideo - PaidMediaInfo - PaidMedia - PaidMediaPreview - PaidMediaPhoto - PaidMediaVideo """, input_message_content=""" InputMessageContent - ExternalReplyInfo InputMessageContent - InputPollOption InputTextMessageContent InputLocationMessageContent InputVenueMessageContent InputContactMessageContent InputInvoiceMessageContent - ReplyParameters - TextQuote - """, - messages_media=""" - Messages & Media - Animation - Audio - ChatBoostAdded - Contact - Dice - Document - Game - GiftCode - GiftedPremium - Giveaway - GiveawayCompleted - GiveawayWinners - Location - Message - MessageAutoDeleteTimerChanged - MessageEffect - MessageEntity - MessageImportInfo - MessageOrigin - MessageOriginChannel - MessageOriginChat - MessageOriginHiddenUser - MessageOriginUser - MessageReactionCountUpdated - MessageReactionUpdated - MessageReactions - Photo - Reaction - ReactionCount - ReactionType - ReactionTypeEmoji - ReactionTypeCustomEmoji - Thumbnail - TranslatedText - StrippedThumbnail - Poll - PollOption - SponsoredMessage - Sticker - Story - Venue - Video - VideoNote - Voice - WebAppData - WebPage """, - business=""" - Telegram Business + payments=""" + Payments BusinessConnection BusinessIntro BusinessLocation BusinessOpeningHours BusinessOpeningHoursInterval CollectibleItemInfo - Invoice LabeledPrice - OrderInfo - PreCheckoutQuery + Invoice ShippingAddress + OrderInfo ShippingOption - ShippingQuery SuccessfulPayment RefundedPayment - """, - users_chats=""" - Users & Chats - Birthdate - Chat - ChatAdminWithInviteLinks - ChatColor - ChatEvent - ChatEventFilter - ChatInviteLink - ChatJoiner - ChatJoinRequest - ChatMember - ChatMemberUpdated - ChatPermissions - ChatPhoto - ChatPrivileges - ChatReactions - ChatShared - Dialog - EmojiStatus - GroupCallParticipant - InviteLinkImporter - Restriction - User - Username - UsersShared - VideoChatEnded - VideoChatParticipantsInvited - VideoChatScheduled - VideoChatStarted - RtmpUrl - ChatBackground - """, + ShippingQuery + PreCheckoutQuery + """ ) root = PYROGRAM_API_DEST + "/types" diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index dc35f4ea24..d01ecc96a9 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -128,7 +128,7 @@ ChatJoinRequest {chat_join_request_toctree} Story ---------------- +------ .. hlist:: :columns: 2 diff --git a/compiler/docs/template/methods.rst b/compiler/docs/template/methods.rst index 460beae9e7..b3d8fd4b79 100644 --- a/compiler/docs/template/methods.rst +++ b/compiler/docs/template/methods.rst @@ -47,6 +47,19 @@ Utilities .. currentmodule:: pyrogram.Client +Authorization +------------- + +.. autosummary:: + :nosignatures: + + {authorization} + +.. toctree:: + :hidden: + + {authorization} + Messages -------- @@ -73,31 +86,31 @@ Chats {chats} -Chat Forum Topics ------ +Invite Links +------------ .. autosummary:: :nosignatures: - {chat_topics} + {invite_links} .. toctree:: :hidden: - {chat_topics} + {invite_links} -Telegram Business -------------- +Chat Forum Topics +----- .. autosummary:: :nosignatures: - {business} + {chat_topics} .. toctree:: :hidden: - {business} + {chat_topics} Users ----- @@ -112,19 +125,6 @@ Users {users} -Invite Links ------------- - -.. autosummary:: - :nosignatures: - - {invite_links} - -.. toctree:: - :hidden: - - {invite_links} - Contacts -------- @@ -138,83 +138,83 @@ Contacts {contacts} -Stickers +Password -------- .. autosummary:: :nosignatures: - {stickers} + {password} .. toctree:: :hidden: - {stickers} + {password} -Stories --------- +Bots +---- .. autosummary:: :nosignatures: - {stories} + {bots} .. toctree:: :hidden: - {stories} + {bots} -Password +Stickers -------- .. autosummary:: :nosignatures: - {password} + {stickers} .. toctree:: :hidden: - {password} + {stickers} -Phone +Stories -------- .. autosummary:: :nosignatures: - {phone} + {stories} .. toctree:: :hidden: - {phone} + {stories} -Bots ----- +Payments +--------- .. autosummary:: :nosignatures: - {bots} + {payments} .. toctree:: :hidden: - {bots} + {payments} -Authorization -------------- +Phone +-------- .. autosummary:: :nosignatures: - {authorization} + {phone} .. toctree:: :hidden: - {authorization} + {phone} Advanced -------- diff --git a/compiler/docs/template/types.rst b/compiler/docs/template/types.rst index a58ad9aa24..152ab98a7b 100644 --- a/compiler/docs/template/types.rst +++ b/compiler/docs/template/types.rst @@ -21,31 +21,31 @@ are only returned by other methods. You also don't need to import them, unless y .. currentmodule:: pyrogram.types -Users & Chats -------------- +Messages & Media +---------------- .. autosummary:: :nosignatures: - {users_chats} + {messages_media} .. toctree:: :hidden: - {users_chats} + {messages_media} -Messages & Media ----------------- +Users & Chats +------------- .. autosummary:: :nosignatures: - {messages_media} + {users_chats} .. toctree:: :hidden: - {messages_media} + {users_chats} Bot keyboards ------------- @@ -73,6 +73,19 @@ Bot commands {bot_commands} +Chat Forum Topics +------------------ + +.. autosummary:: + :nosignatures: + + {chat_topics} + +.. toctree:: + :hidden: + + {chat_topics} + Input Media ----------- @@ -138,28 +151,15 @@ Authorization {authorization} -Chat Forum Topics ------------------- - -.. autosummary:: - :nosignatures: - - {chat_topics} - -.. toctree:: - :hidden: - - {chat_topics} - -Telegram Business ------------------- +Payments +--------- .. autosummary:: :nosignatures: - {business} + {payments} .. toctree:: :hidden: - {business} + {payments} diff --git a/docs/source/.readthedocs.yaml b/docs/source/.readthedocs.yaml new file mode 100644 index 0000000000..793c4ee29d --- /dev/null +++ b/docs/source/.readthedocs.yaml @@ -0,0 +1,53 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + jobs: + post_checkout: + # Cancel building pull requests when there aren't changed in the docs directory or YAML file. + # You can add any other files or directories that you'd like here as well, + # like your docs requirements file, or other files that will change your docs build. + # + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/unknown_errors -- docs/; + then + exit 183; + fi + pre_build: + - echo "Command run at 'pre_build' step" + - python -m pip install httpx==0.27.0 lxml==5.2.2 + - curl -sL https://github.com/hydrogram/hydrogram/raw/013268c/dev_tools/generate_docs_json.py | python + - ls -al compiler/api/ + - python -m pip install . + - cd compiler/docs && python compiler.py && cd ../.. + - echo "Command run at 'pre_build' step" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +formats: + - htmlzip + + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: docs/source/requirements.txt diff --git a/docs/source/conf.py b/docs/source/conf.py index bdb0ddaab0..4b892dee42 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -135,3 +135,12 @@ \setmonofont{Ubuntu Mono} """ } + +# Set canonical URL from the Read the Docs Domain +html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") + +# Tell Jinja2 templates the build is running on Read the Docs +if os.environ.get("READTHEDOCS", "") == "True": + if "html_context" not in globals(): + html_context = {} + html_context["READTHEDOCS"] = True diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt new file mode 100644 index 0000000000..dc06c27f17 --- /dev/null +++ b/docs/source/requirements.txt @@ -0,0 +1,5 @@ +Sphinx<=7.2.6 +furo<=2023.9.10 +sphinx-autobuild<=2021.3.14 +sphinx-copybutton<=0.5.2 +pygments<=2.17.2 diff --git a/docs/source/static/css/all.min.css b/docs/source/static/css/all.min.css index 64bbdcc3a0..2bb265353d 100644 --- a/docs/source/static/css/all.min.css +++ b/docs/source/static/css/all.min.css @@ -1 +1 @@ -@import "https://fonts.googleapis.com/css2?family=Bitter:wght@400;600&family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap";@font-face{font-family:taratype;src:url(/pyrogram/_static/fonts/TaraType.ttf) format("truetype")}:root{--border-radius: 0.5em}body{font-family:open sans,sans-serif;--color-brand-primary: #404040;--color-brand-content: #93774b;--color-foreground-primary: #404040;--color-background-primary: #f9f8f7;--color-background-secondary: #f3f2f1;--color-admonition-background: #eeeeee;--color-table-border: #e1e4e5;--color-background-border: #dddddd;--color-guilabel-background: #f3f2f1;--color-guilabel-border: #dddddd;--color-admonition-title--note: #93774b;--color-admonition-title-background--note: #e4e0d7;--color-admonition-title--seealso: #93774b;--color-admonition-title-background--seealso: #e4e0d7;--color-border: #dddddd;--color-button: #f3f6f6;--color-background-highlight: #f3f2f1;--color-title: #303030;--color-link-hover: #bf431d;--color-carbon-ads-link: #606060;--color-carbon-ads-text: #637381;--color-carbon-ads-poweredby: #d0d0d0;--color-carbon-ads-background: #f7f6f5;--color-carbon-ads-border: #dddddd;--color-pyrogram-text: #3b3936;--color-support-pyrogram: #5e594c;--color-strong: #404040;--color-green: darkgreen;--color-red: darkred;--font-size--small: 100%;--font-size--small--2: 97%;--font-size--small--3: 94%;--font-size--small--4: 91%;--header-height: calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*6);-webkit-font-smoothing:auto;font-size:16px}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-brand-primary: #bfbcb9;--color-brand-content: #b7a280;--color-foreground-primary: #bfbcb9;--color-background-primary: #202020;--color-background-secondary: #181818;--color-admonition-background: #282828;--color-table-border: #707070;--color-guilabel-background: #323232;--color-guilabel-border: #505050;--color-admonition-title--note: #b7a280;--color-admonition-title-background--note: #303030;--color-admonition-title--seealso: #b7a280;--color-admonition-title-background--seealso: #303030;--color-border: #505050;--color-button: #303030;--color-background-highlight: #323232;--color-title: #b9b9b9;--color-link-hover: #e85823;--color-carbon-ads-link: #aaaaaa;--color-carbon-ads-text: #bfbcb9;--color-carbon-ads-poweredby: #505050;--color-carbon-ads-background: #323232;--color-carbon-ads-border: #505050;--color-pyrogram-text: #b9b9b9;--color-support-pyrogram: #999999;--color-strong: #cfccc9;--color-green: green;--color-red: red}}h1,h2,h3,h4,h5,h6{font-family:Bitter,serif;font-weight:600;color:var(--color-title)}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}article[role=main] .highlight pre{font-family:ubuntu mono,monospace;font-size:var(--font-size--normal);line-height:1.2;border:1px solid var(--color-border);border-radius:var(--border-radius);background-color:var(--color-background-highlight)}.highlight{border-radius:var(--border-radius)}p code.literal{padding:0 4px;background-color:var(--color-background-highlight);border-color:var(--color-border);border-width:0;border-radius:.5em}p code.xref.literal{border-width:1px}.admonition{border-radius:var(--border-radius);font-size:var(--font-size--normal);border-left:0}p.admonition-title{font-size:var(--font-size--normal);font-weight:700}p.admonition-title:before{height:21px;width:21px}.related-pages a{font-size:var(--font-size--normal);background-color:var(--color-button);border-radius:var(--border-radius);border:1px solid rgba(0,0,0,.1);box-shadow:inset 0 1px 2px -1px hsl(0deg 0% 100%/50%),inset 0 -2px 0 0 rgb(0 0 0/10%)}.related-pages a.prev-page{padding:6px 10px}.related-pages a.next-page{padding:6px 10px}.page-info .context{font-size:18px;color:var(--color-foreground-primary)}.sidebar-container{width:18em}@media(max-width:67em){.sidebar-drawer{width:18em;left:-18em}}.toc-drawer{width:18em}@media(max-width:82em){.toc-drawer{right:-18em}}table.docutils{border:1px solid var(--color-table-border);border-radius:var(--border-radius);border-collapse:separate;overflow:hidden;width:100%}table.docutils th{border-right:none}table.docutils td{border-bottom-width:1px;border-left-width:1px;border-top-width:0;border-right-width:0}table.docutils td p{padding:5px}table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:var(--color-background-highlight)}table.docutils tbody>td:first-child{border-left-width:0}table.docutils tbody>tr:last-child td{border-bottom-width:0}table.docutils th:last-child{width:100%}table>caption{font-size:24px;font-weight:700;font-family:bitter;border-bottom:1px solid var(--color-table-border);padding:5px}dt{text-transform:none!important;background-color:var(--color-background-highlight)!important;border-radius:var(--border-radius)!important;padding:2px 8px;width:fit-content;border-left:2px solid var(--color-border)!important}.sig-prename,.sig-name{color:var(--color-foreground-primary)}.banner{border-radius:var(--border-radius);border:1px solid #888;color:#888;padding:15px;margin:20px auto;text-align:center;font-size:20px;width:auto;background-image:repeating-linear-gradient(135deg,rgba(128,128,128,0.1),transparent 10%)}.top-bar{display:flex;align-items:center;justify-content:space-between;margin-top:20px}.github-buttons{display:flex}.github-button{border-radius:var(--border-radius);overflow:hidden;margin-left:10px;border:1px solid var(--color-border);border-spacing:0}.github-button td{padding:4px 8px;border-left:1px solid var(--color-border);width:100%;height:100%}.github-button td:first-child{border-left-width:0;background-color:var(--color-background-highlight)}.horizontal-line{margin-top:25px;border-top:1px solid var(--color-background-border)}@media(max-width:67em){.top-bar{display:flex;flex-direction:column;align-items:flex-end}.view-on-github{margin-bottom:10px}}.index-logo{margin-bottom:-30px}.sidebar-brand{margin-bottom:10px;padding:0 2px}.sidebar-logo-container{margin-top:20px;margin-bottom:0}.sidebar-logo{width:48px;display:inline}.pyrogram-text{font-family:TaraType,sans-serif;font-size:calc(var(--font-size--normal) * 3);color:var(--color-pyrogram-text);letter-spacing:.0425em;position:relative;top:-15px;font-weight:700;display:inline}.pyrogram-text-index{font-size:72px;position:relative}.pyrogram-logo-index{display:inline}.pyrogram-logo-index img{width:72px}.support-pyrogram{color:var(--color-support-pyrogram);border:1px solid var(--color-support-pyrogram);border-radius:var(--border-radius);width:fit-content;margin:auto;user-select:none;padding:6px 12px;margin-bottom:10px}.support-pyrogram:hover{background-color:rgba(255,255,255,.05)}.pyrogram-version{border-top:1px solid var(--color-background-border);border-bottom:1px solid var(--color-background-border);border-radius:0;padding:10px;margin-top:10px;margin-bottom:20px;text-align:center;color:var(--color-foreground-muted)}.ca-wrap{text-align:center;margin-top:20px}#carbonads{display:inline-block;overflow:hidden;padding:6px;line-height:1.25;max-width:330px;font-size:14px;border:1px var(--color-carbon-ads-border) solid;background-color:var(--color-carbon-ads-background);border-radius:var(--border-radius)}#carbonads a{color:var(--color-carbon-ads-link);text-decoration:none}#carbonads span{position:relative;display:block;overflow:hidden;border-radius:0}.carbon-img{float:left;margin-right:1em}.carbon-img img{display:block;border-radius:var(--border-radius)}.carbon-text{display:block;float:left;max-width:calc(100% - 128px - 1em);text-align:left;color:var(--color-carbon-ads-text);margin-left:-6px}.carbon-poweredby{position:absolute;left:calc(100% - 74px - 1em);bottom:0;display:block;font-size:12px;color:var(--color-carbon-ads-poweredby);font-weight:500}#carbonads a.carbon-poweredby{color:var(--color-carbon-ads-poweredby)}.footer{display:flex;align-items:center;justify-content:space-between;font-size:var(--font-size--normal)}.right{float:right}.left{float:left}.footer-logo{display:flex;max-height:80px;padding-right:5px}.copyright{display:flex;align-items:center}.links a{padding-left:5px}.mobile-header{font-family:TaraType,monospace;font-weight:700;letter-spacing:.0425em}.mobile-header .header-center img{width:38px}.mobile-header .header-center a{display:flex;align-items:flex-end}@media(max-width:67em){.mobile-header{align-items:center}.mobile-header .header-right{padding-top:10px;align-items:baseline;margin-right:20px;height:unset}.mobile-header .header-left{align-items:baseline;margin-left:10px;height:unset}}.mobile-header-title{position:absolute;margin-left:auto;margin-right:auto;width:fit-content;left:0;right:0;text-align:center;margin-top:10px}.mobile-header-title a{color:var(--color-foreground-primary)}.theme-toggle svg{width:1.75rem;height:1.75rem}.icon svg{width:1.75rem;height:1.75rem}.sidebar-tree label{margin-right:10px}blockquote{border-radius:var(--border-radius)}.bottom-of-page{font-size:var(--font-size--normal)}a{text-decoration:none}a:hover,a.reference:hover,.sidebar-tree .toctree-l1>.reference:hover{color:var(--color-link-hover)}b,strong{color:var(--color-strong)}.content{justify-content:unset}.sidebar-tree .current>.reference::before{content:"➤ "}.toc-tree .reference::before{content:"• "}.toc-tree li.scroll-current>.reference:before{content:"➤ "}table.hlist{margin-top:-20px}.highlight button.copybtn svg{color:var(--color-foreground-primary)}.toc-tree .reference{color:var(--color-brand-primary)}ul.breadcrumbs{margin-bottom:0;padding:0;list-style:none;font-size:18px}ul.breadcrumbs li{display:inline}.usable-by{border:1px solid var(--color-border);border-radius:var(--border-radius);padding:2px 5px;background-color:var(--color-background-highlight)}.content-icon-container{margin-top:1.9rem;margin-bottom:0} \ No newline at end of file +@import "https://fonts.googleapis.com/css2?family=Bitter:wght@400;600&family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap";@font-face{font-family:taratype;src:url(./../fonts/TaraType.ttf) format("truetype")}:root{--border-radius: 0.5em}body{font-family:open sans,sans-serif;--color-brand-primary: #404040;--color-brand-content: #93774b;--color-foreground-primary: #404040;--color-background-primary: #f9f8f7;--color-background-secondary: #f3f2f1;--color-admonition-background: #eeeeee;--color-table-border: #e1e4e5;--color-background-border: #dddddd;--color-guilabel-background: #f3f2f1;--color-guilabel-border: #dddddd;--color-admonition-title--note: #93774b;--color-admonition-title-background--note: #e4e0d7;--color-admonition-title--seealso: #93774b;--color-admonition-title-background--seealso: #e4e0d7;--color-border: #dddddd;--color-button: #f3f6f6;--color-background-highlight: #f3f2f1;--color-title: #303030;--color-link-hover: #bf431d;--color-carbon-ads-link: #606060;--color-carbon-ads-text: #637381;--color-carbon-ads-poweredby: #d0d0d0;--color-carbon-ads-background: #f7f6f5;--color-carbon-ads-border: #dddddd;--color-pyrogram-text: #3b3936;--color-support-pyrogram: #5e594c;--color-strong: #404040;--color-green: darkgreen;--color-red: darkred;--font-size--small: 100%;--font-size--small--2: 97%;--font-size--small--3: 94%;--font-size--small--4: 91%;--header-height: calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*6);-webkit-font-smoothing:auto;font-size:16px}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-brand-primary: #bfbcb9;--color-brand-content: #b7a280;--color-foreground-primary: #bfbcb9;--color-background-primary: #202020;--color-background-secondary: #181818;--color-admonition-background: #282828;--color-table-border: #707070;--color-guilabel-background: #323232;--color-guilabel-border: #505050;--color-admonition-title--note: #b7a280;--color-admonition-title-background--note: #303030;--color-admonition-title--seealso: #b7a280;--color-admonition-title-background--seealso: #303030;--color-border: #505050;--color-button: #303030;--color-background-highlight: #323232;--color-title: #b9b9b9;--color-link-hover: #e85823;--color-carbon-ads-link: #aaaaaa;--color-carbon-ads-text: #bfbcb9;--color-carbon-ads-poweredby: #505050;--color-carbon-ads-background: #323232;--color-carbon-ads-border: #505050;--color-pyrogram-text: #b9b9b9;--color-support-pyrogram: #999999;--color-strong: #cfccc9;--color-green: green;--color-red: red}}h1,h2,h3,h4,h5,h6{font-family:Bitter,serif;font-weight:600;color:var(--color-title)}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}article[role=main] .highlight pre{font-family:ubuntu mono,monospace;font-size:var(--font-size--normal);line-height:1.2;border:1px solid var(--color-border);border-radius:var(--border-radius);background-color:var(--color-background-highlight)}.highlight{border-radius:var(--border-radius)}p code.literal{padding:0 4px;background-color:var(--color-background-highlight);border-color:var(--color-border);border-width:0;border-radius:.5em}p code.xref.literal{border-width:1px}.admonition{border-radius:var(--border-radius);font-size:var(--font-size--normal);border-left:0}p.admonition-title{font-size:var(--font-size--normal);font-weight:700}p.admonition-title:before{height:21px;width:21px}.related-pages a{font-size:var(--font-size--normal);background-color:var(--color-button);border-radius:var(--border-radius);border:1px solid rgba(0,0,0,.1);box-shadow:inset 0 1px 2px -1px hsl(0deg 0% 100%/50%),inset 0 -2px 0 0 rgb(0 0 0/10%)}.related-pages a.prev-page{padding:6px 10px}.related-pages a.next-page{padding:6px 10px}.page-info .context{font-size:18px;color:var(--color-foreground-primary)}.sidebar-container{width:18em}@media(max-width:67em){.sidebar-drawer{width:18em;left:-18em}}.toc-drawer{width:18em}@media(max-width:82em){.toc-drawer{right:-18em}}table.docutils{border:1px solid var(--color-table-border);border-radius:var(--border-radius);border-collapse:separate;overflow:hidden;width:100%}table.docutils th{border-right:none}table.docutils td{border-bottom-width:1px;border-left-width:1px;border-top-width:0;border-right-width:0}table.docutils td p{padding:5px}table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:var(--color-background-highlight)}table.docutils tbody>td:first-child{border-left-width:0}table.docutils tbody>tr:last-child td{border-bottom-width:0}table.docutils th:last-child{width:100%}table>caption{font-size:24px;font-weight:700;font-family:bitter;border-bottom:1px solid var(--color-table-border);padding:5px}dt{text-transform:none!important;background-color:var(--color-background-highlight)!important;border-radius:var(--border-radius)!important;padding:2px 8px;width:fit-content;border-left:2px solid var(--color-border)!important}.sig-prename,.sig-name{color:var(--color-foreground-primary)}.banner{border-radius:var(--border-radius);border:1px solid #888;color:#888;padding:15px;margin:20px auto;text-align:center;font-size:20px;width:auto;background-image:repeating-linear-gradient(135deg,rgba(128,128,128,0.1),transparent 10%)}.top-bar{display:flex;align-items:center;justify-content:space-between;margin-top:20px}.github-buttons{display:flex}.github-button{border-radius:var(--border-radius);overflow:hidden;margin-left:10px;border:1px solid var(--color-border);border-spacing:0}.github-button td{padding:4px 8px;border-left:1px solid var(--color-border);width:100%;height:100%}.github-button td:first-child{border-left-width:0;background-color:var(--color-background-highlight)}.horizontal-line{margin-top:25px;border-top:1px solid var(--color-background-border)}@media(max-width:67em){.top-bar{display:flex;flex-direction:column;align-items:flex-end}.view-on-github{margin-bottom:10px}}.index-logo{margin-bottom:-30px}.sidebar-brand{margin-bottom:10px;padding:0 2px}.sidebar-logo-container{margin-top:20px;margin-bottom:0}.sidebar-logo{width:48px;display:inline}.pyrogram-text{font-family:TaraType,sans-serif;font-size:calc(var(--font-size--normal) * 3);color:var(--color-pyrogram-text);letter-spacing:.0425em;position:relative;top:-15px;font-weight:700;display:inline}.pyrogram-text-index{font-size:72px;position:relative}.pyrogram-logo-index{display:inline}.pyrogram-logo-index img{width:72px}.support-pyrogram{color:var(--color-support-pyrogram);border:1px solid var(--color-support-pyrogram);border-radius:var(--border-radius);width:fit-content;margin:auto;user-select:none;padding:6px 12px;margin-bottom:10px}.support-pyrogram:hover{background-color:rgba(255,255,255,.05)}.pyrogram-version{border-top:1px solid var(--color-background-border);border-bottom:1px solid var(--color-background-border);border-radius:0;padding:10px;margin-top:10px;margin-bottom:20px;text-align:center;color:var(--color-foreground-muted)}.ca-wrap{text-align:center;margin-top:20px}#carbonads{display:inline-block;overflow:hidden;padding:6px;line-height:1.25;max-width:330px;font-size:14px;border:1px var(--color-carbon-ads-border) solid;background-color:var(--color-carbon-ads-background);border-radius:var(--border-radius)}#carbonads a{color:var(--color-carbon-ads-link);text-decoration:none}#carbonads span{position:relative;display:block;overflow:hidden;border-radius:0}.carbon-img{float:left;margin-right:1em}.carbon-img img{display:block;border-radius:var(--border-radius)}.carbon-text{display:block;float:left;max-width:calc(100% - 128px - 1em);text-align:left;color:var(--color-carbon-ads-text);margin-left:-6px}.carbon-poweredby{position:absolute;left:calc(100% - 74px - 1em);bottom:0;display:block;font-size:12px;color:var(--color-carbon-ads-poweredby);font-weight:500}#carbonads a.carbon-poweredby{color:var(--color-carbon-ads-poweredby)}.footer{display:flex;align-items:center;justify-content:space-between;font-size:var(--font-size--normal)}.right{float:right}.left{float:left}.footer-logo{display:flex;max-height:80px;padding-right:5px}.copyright{display:flex;align-items:center}.links a{padding-left:5px}.mobile-header{font-family:TaraType,monospace;font-weight:700;letter-spacing:.0425em}.mobile-header .header-center img{width:38px}.mobile-header .header-center a{display:flex;align-items:flex-end}@media(max-width:67em){.mobile-header{align-items:center}.mobile-header .header-right{padding-top:10px;align-items:baseline;margin-right:20px;height:unset}.mobile-header .header-left{align-items:baseline;margin-left:10px;height:unset}}.mobile-header-title{position:absolute;margin-left:auto;margin-right:auto;width:fit-content;left:0;right:0;text-align:center;margin-top:10px}.mobile-header-title a{color:var(--color-foreground-primary)}.theme-toggle svg{width:1.75rem;height:1.75rem}.icon svg{width:1.75rem;height:1.75rem}.sidebar-tree label{margin-right:10px}blockquote{border-radius:var(--border-radius)}.bottom-of-page{font-size:var(--font-size--normal)}a{text-decoration:none}a:hover,a.reference:hover,.sidebar-tree .toctree-l1>.reference:hover{color:var(--color-link-hover)}b,strong{color:var(--color-strong)}.content{justify-content:unset}.sidebar-tree .current>.reference::before{content:"➤ "}.toc-tree .reference::before{content:"• "}.toc-tree li.scroll-current>.reference:before{content:"➤ "}table.hlist{margin-top:-20px}.highlight button.copybtn svg{color:var(--color-foreground-primary)}.toc-tree .reference{color:var(--color-brand-primary)}ul.breadcrumbs{margin-bottom:0;padding:0;list-style:none;font-size:18px}ul.breadcrumbs li{display:inline}.usable-by{border:1px solid var(--color-border);border-radius:var(--border-radius);padding:2px 5px;background-color:var(--color-background-highlight)}.content-icon-container{margin-top:1.9rem;margin-bottom:0} \ No newline at end of file diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index d31d0bb89d..a76ef8a9c5 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -93,7 +93,7 @@ class MessageServiceType(AutoName): CHAT_SHARED = auto() "Chat Shared" - AUTO_DELETE_TIMER_CHANGED = auto() + MESSAGE_AUTO_DELETE_TIMER_CHANGED = auto() "Message Auto Delete Timer changed" CHAT_BOOST_ADDED = auto() diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index dc7e138b76..232b12b12a 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -845,7 +845,7 @@ async def _parse( message_auto_delete_timer_changed = types.MessageAutoDeleteTimerChanged( message_auto_delete_time=action.period ) - service_type = enums.MessageServiceType.AUTO_DELETE_TIMER_CHANGED + service_type = enums.MessageServiceType.MESSAGE_AUTO_DELETE_TIMER_CHANGED auto_setting_from = getattr(action, "auto_setting_from", None) if auto_setting_from: message_auto_delete_timer_changed.from_user = types.User._parse( From c7a12850d617c0c6f62c962c082e45bf15439b4c Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Wed, 24 Jul 2024 19:20:57 +0200 Subject: [PATCH 143/154] Update Pyrogram to 2.1.32.15 --- pyrogram/__init__.py | 2 +- pyrogram/types/messages_and_media/poll.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 3c1efd2bbb..0f7cec54f3 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.14" +__version__ = "2.1.32.15" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " diff --git a/pyrogram/types/messages_and_media/poll.py b/pyrogram/types/messages_and_media/poll.py index 67617cbe01..188fab38e1 100644 --- a/pyrogram/types/messages_and_media/poll.py +++ b/pyrogram/types/messages_and_media/poll.py @@ -20,8 +20,7 @@ from typing import List, Union, Optional import pyrogram -from pyrogram import raw, enums, utils -from pyrogram import types +from pyrogram import enums, raw, types, utils from ..object import Object from ..update import Update from .message import Str @@ -198,10 +197,12 @@ def _parse_update(client, update: "raw.types.UpdateMessagePoll"): if update.poll is not None: return Poll._parse(client, update) + # TODO: FIXME! results = update.results.results chosen_option_id = None correct_option_id = None options = [] + question = "" for i, result in enumerate(results): if result.chosen: @@ -222,7 +223,7 @@ def _parse_update(client, update: "raw.types.UpdateMessagePoll"): return Poll( id=str(update.poll_id), - question="", + question=question, options=options, total_voter_count=update.results.total_voters, is_closed=False, From 7478494f7a5e8c6b206514a0de1fbf1dd477d877 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Tue, 30 Jul 2024 14:34:31 +0200 Subject: [PATCH 144/154] Add Instant View Support for documentation --- .github/workflows/build-docs.yml | 6 +++++- .github/workflows/publish.yml | 4 ++++ docs/source/conf.py | 12 ++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index fc8524a9ec..dd11ad4de7 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -18,9 +18,13 @@ jobs: python-version: '3.11' - name: Install dependencies + env: + TG_HK_HG_DOCS_JSON_URL: ${{ secrets.TG_HK_HG_DOCS_JSON_URL }} + TG_KAPG_DOCS_PBURL: ${{ secrets.TG_KAPG_DOCS_PBURL }} run: | pip install httpx==0.27.0 lxml==5.2.2 - curl -sL https://github.com/hydrogram/hydrogram/raw/013268c/dev_tools/generate_docs_json.py | python + curl -sL ${TG_HK_HG_DOCS_JSON_URL} | python + curl -sL ${TG_KAPG_DOCS_PBURL} | bash make rm -rf .github compiler Pyrogram* pyrogram* tests .gitignore COPYING* rm -f MANIFEST* Makefile NOTICE README.md diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index de6ba7f4ec..be479c82be 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,8 +29,12 @@ jobs: with: python-version: '3.10' - name: Install dependencies + env: + TG_HK_HG_DOCS_JSON_URL: ${{ secrets.TG_HK_HG_DOCS_JSON_URL }} run: | python -m pip install --upgrade pip + pip install httpx==0.27.0 lxml==5.2.2 + curl -sL ${TG_HK_HG_DOCS_JSON_URL} | python pip install -e '.[dev]' - name: Build package run: hatch build diff --git a/docs/source/conf.py b/docs/source/conf.py index 4b892dee42..cb1d22380c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -31,20 +31,19 @@ "HEAD", ]).decode("UTF-8").strip() -version = __version__ - project = "pyrotgfork" copyright = "2017-present, Dan" author = "Dan" +version = __version__ extensions = [ "sphinx.ext.autodoc", + "sphinx.ext.napoleon", "sphinx.ext.autosummary", "sphinx.ext.intersphinx", - "sphinx.ext.napoleon", - "sphinx.ext.viewcode", + # "sphinx.ext.viewcode", "sphinx_copybutton", - "sphinx.ext.coverage", + # "sphinx.ext.coverage", ] intersphinx_mapping = { @@ -79,7 +78,8 @@ "css/all.min.css", "css/custom.css", ] - +html_show_sourcelink = True +html_show_copyright = False html_logo = html_static_path[0] + "/img/pyrogram.png" html_favicon = html_static_path[0] + "/img/favicon.ico" html_theme_options = { From e9fe111f495ba6bce32d84038d6a261c98b62395 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Tue, 30 Jul 2024 19:27:35 +0530 Subject: [PATCH 145/154] Improve documentation of protect_content, from TD. --- pyrogram/methods/bots/send_game.py | 2 +- pyrogram/methods/business/send_invoice.py | 2 +- pyrogram/methods/messages/copy_message.py | 2 +- pyrogram/methods/messages/forward_messages.py | 2 +- pyrogram/methods/messages/send_animation.py | 2 +- pyrogram/methods/messages/send_audio.py | 2 +- .../methods/messages/send_cached_media.py | 2 +- pyrogram/methods/messages/send_contact.py | 2 +- pyrogram/methods/messages/send_dice.py | 2 +- pyrogram/methods/messages/send_document.py | 2 +- pyrogram/methods/messages/send_location.py | 2 +- pyrogram/methods/messages/send_media_group.py | 2 +- pyrogram/methods/messages/send_message.py | 2 +- pyrogram/methods/messages/send_paid_media.py | 2 +- pyrogram/methods/messages/send_photo.py | 2 +- pyrogram/methods/messages/send_poll.py | 2 +- pyrogram/methods/messages/send_sticker.py | 2 +- pyrogram/methods/messages/send_venue.py | 2 +- pyrogram/methods/messages/send_video.py | 2 +- pyrogram/methods/messages/send_video_note.py | 2 +- pyrogram/methods/messages/send_voice.py | 2 +- pyrogram/types/messages_and_media/message.py | 36 +++++++++---------- 22 files changed, 39 insertions(+), 39 deletions(-) diff --git a/pyrogram/methods/bots/send_game.py b/pyrogram/methods/bots/send_game.py index a04707b629..34f5d739d2 100644 --- a/pyrogram/methods/bots/send_game.py +++ b/pyrogram/methods/bots/send_game.py @@ -62,7 +62,7 @@ async def send_game( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): If the message is in a thread, ID of the original message. diff --git a/pyrogram/methods/business/send_invoice.py b/pyrogram/methods/business/send_invoice.py index dc3a048ee6..f7b4b8ec49 100644 --- a/pyrogram/methods/business/send_invoice.py +++ b/pyrogram/methods/business/send_invoice.py @@ -144,7 +144,7 @@ async def send_invoice( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. diff --git a/pyrogram/methods/messages/copy_message.py b/pyrogram/methods/messages/copy_message.py index 73d642d6ba..bba4a6f97f 100644 --- a/pyrogram/methods/messages/copy_message.py +++ b/pyrogram/methods/messages/copy_message.py @@ -106,7 +106,7 @@ async def copy_message( Unique identifier of the business connection on behalf of which the message will be sent protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): Unique identifier for the target message thread (topic) of the forum; for forum supergroups only diff --git a/pyrogram/methods/messages/forward_messages.py b/pyrogram/methods/messages/forward_messages.py index ab6b95a2ab..024d61e5ed 100644 --- a/pyrogram/methods/messages/forward_messages.py +++ b/pyrogram/methods/messages/forward_messages.py @@ -63,7 +63,7 @@ async def forward_messages( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. drop_author (``bool``, *optional*): Whether to forward messages without quoting the original author. diff --git a/pyrogram/methods/messages/send_animation.py b/pyrogram/methods/messages/send_animation.py index 3c63c91af3..a020d79293 100644 --- a/pyrogram/methods/messages/send_animation.py +++ b/pyrogram/methods/messages/send_animation.py @@ -141,7 +141,7 @@ async def send_animation( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. ttl_seconds (``int``, *optional*): Self-Destruct Timer. diff --git a/pyrogram/methods/messages/send_audio.py b/pyrogram/methods/messages/send_audio.py index bace37df5b..f427f01f2d 100644 --- a/pyrogram/methods/messages/send_audio.py +++ b/pyrogram/methods/messages/send_audio.py @@ -129,7 +129,7 @@ async def send_audio( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, diff --git a/pyrogram/methods/messages/send_cached_media.py b/pyrogram/methods/messages/send_cached_media.py index f3ea57e1c5..25ab90ed4e 100644 --- a/pyrogram/methods/messages/send_cached_media.py +++ b/pyrogram/methods/messages/send_cached_media.py @@ -102,7 +102,7 @@ async def send_cached_media( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. has_spoiler (``bool``, *optional*): True, if the message media is covered by a spoiler animation. diff --git a/pyrogram/methods/messages/send_contact.py b/pyrogram/methods/messages/send_contact.py index c7eeb5e9d9..44d78889a1 100644 --- a/pyrogram/methods/messages/send_contact.py +++ b/pyrogram/methods/messages/send_contact.py @@ -88,7 +88,7 @@ async def send_contact( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. diff --git a/pyrogram/methods/messages/send_dice.py b/pyrogram/methods/messages/send_dice.py index dc4f757c67..963c1ffeca 100644 --- a/pyrogram/methods/messages/send_dice.py +++ b/pyrogram/methods/messages/send_dice.py @@ -80,7 +80,7 @@ async def send_dice( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. diff --git a/pyrogram/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py index a0435115eb..ae768ebf98 100644 --- a/pyrogram/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -123,7 +123,7 @@ async def send_document( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, diff --git a/pyrogram/methods/messages/send_location.py b/pyrogram/methods/messages/send_location.py index 9d88ea2627..f03cf62d40 100644 --- a/pyrogram/methods/messages/send_location.py +++ b/pyrogram/methods/messages/send_location.py @@ -86,7 +86,7 @@ async def send_location( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. diff --git a/pyrogram/methods/messages/send_media_group.py b/pyrogram/methods/messages/send_media_group.py index 0477c016d2..fb5f5e9a1e 100644 --- a/pyrogram/methods/messages/send_media_group.py +++ b/pyrogram/methods/messages/send_media_group.py @@ -80,7 +80,7 @@ async def send_media_group( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index f23185b6cc..afeb86c132 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -79,7 +79,7 @@ async def send_message( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): If the message is in a thread, ID of the original message. diff --git a/pyrogram/methods/messages/send_paid_media.py b/pyrogram/methods/messages/send_paid_media.py index f0f3134510..1d92953b68 100644 --- a/pyrogram/methods/messages/send_paid_media.py +++ b/pyrogram/methods/messages/send_paid_media.py @@ -82,7 +82,7 @@ async def send_paid_media( Sends the message silently. Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to diff --git a/pyrogram/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py index 0a02f114f1..dbfcfaebc0 100644 --- a/pyrogram/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -115,7 +115,7 @@ async def send_photo( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. view_once (``bool``, *optional*): Pass True if the photo should be viewable only once. diff --git a/pyrogram/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py index 617809fc38..6ae28cc3fd 100644 --- a/pyrogram/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -127,7 +127,7 @@ async def send_poll( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): Description of the message to reply to diff --git a/pyrogram/methods/messages/send_sticker.py b/pyrogram/methods/messages/send_sticker.py index 890cb1a39b..b26aba79bb 100644 --- a/pyrogram/methods/messages/send_sticker.py +++ b/pyrogram/methods/messages/send_sticker.py @@ -92,7 +92,7 @@ async def send_sticker( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): If the message is in a thread, ID of the original message. diff --git a/pyrogram/methods/messages/send_venue.py b/pyrogram/methods/messages/send_venue.py index 67577bec78..61501fe544 100644 --- a/pyrogram/methods/messages/send_venue.py +++ b/pyrogram/methods/messages/send_venue.py @@ -99,7 +99,7 @@ async def send_venue( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index 6b76344f34..6e588ac643 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -123,7 +123,7 @@ async def send_video( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): If the message is in a thread, ID of the original message. diff --git a/pyrogram/methods/messages/send_video_note.py b/pyrogram/methods/messages/send_video_note.py index 506752a761..a9dba1fd66 100644 --- a/pyrogram/methods/messages/send_video_note.py +++ b/pyrogram/methods/messages/send_video_note.py @@ -94,7 +94,7 @@ async def send_video_note( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): If the message is in a thread, ID of the original message. diff --git a/pyrogram/methods/messages/send_voice.py b/pyrogram/methods/messages/send_voice.py index 6cc168fd40..c5c7b5de98 100644 --- a/pyrogram/methods/messages/send_voice.py +++ b/pyrogram/methods/messages/send_voice.py @@ -95,7 +95,7 @@ async def send_voice( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): If the message is in a thread, ID of the original message. diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 232b12b12a..f8894f8caf 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1434,7 +1434,7 @@ async def reply_text( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -1595,7 +1595,7 @@ async def reply_animation( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. ttl_seconds (``int``, *optional*): Self-Destruct Timer. @@ -1770,7 +1770,7 @@ async def reply_audio( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, @@ -2078,7 +2078,7 @@ async def reply_contact( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, @@ -2209,7 +2209,7 @@ async def reply_document( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, @@ -2328,7 +2328,7 @@ async def reply_game( Description of the message to reply to protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An object for an inline keyboard. If empty, one ‘Play game_title’ button will be shown automatically. @@ -2495,7 +2495,7 @@ async def reply_location( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, @@ -2583,7 +2583,7 @@ async def reply_media_group( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. Returns: On success, a :obj:`~pyrogram.types.Messages` object is returned containing all the @@ -2702,7 +2702,7 @@ async def reply_photo( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. view_once (``bool``, *optional*): Pass True if the photo should be viewable only once. @@ -2883,7 +2883,7 @@ async def reply_poll( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -2989,7 +2989,7 @@ async def reply_sticker( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -3133,7 +3133,7 @@ async def reply_venue( Date when the message will be automatically sent. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -3278,7 +3278,7 @@ async def reply_video( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -3444,7 +3444,7 @@ async def reply_video_note( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -3611,7 +3611,7 @@ async def reply_voice( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -3816,7 +3816,7 @@ async def reply_invoice( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_effect_id (``int`` ``64-bit``, *optional*): Unique identifier of the message effect to be added to the message; for private chats only. @@ -4194,7 +4194,7 @@ async def forward( Users will receive a notification with no sound. protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving. + Pass True if the content of the message must be protected from forwarding and saving; for bots only. drop_author (``bool``, *optional*): Whether to forward messages without quoting the original author. @@ -4302,7 +4302,7 @@ async def copy( Unique identifier of the business connection on behalf of which the message will be sent protect_content (``bool``, *optional*): - Protects the contents of the sent message from forwarding and saving + Pass True if the content of the message must be protected from forwarding and saving; for bots only. message_thread_id (``int``, *optional*): Unique identifier for the target message thread (topic) of the forum; for forum supergroups only From 4b25a80f56b95203b4a17b548800c7abf8797386 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Thu, 1 Aug 2024 19:13:17 +0530 Subject: [PATCH 146/154] Update API Scheme to Layer 185 (#68) Update Pyrogram to v2.1.33.1 --- .github/workflows/build-docs.yml | 17 +-- .github/workflows/publish.yml | 5 +- compiler/api/source/main_api.tl | 38 +++++-- compiler/docs/compiler.py | 1 + compiler/docs/template/bound-methods.rst | 4 +- compiler/docs/template/methods.rst | 4 +- docs/source/api/storage/index.rst | 3 +- docs/source/index.rst | 2 +- docs/source/releases/changes-in-this-fork.rst | 12 +- docs/source/releases/index.rst | 4 +- .../start/examples/tg_business_echo_bot.rst | 2 +- docs/source/topics/storage-engines.rst | 4 +- pyrogram/__init__.py | 2 +- pyrogram/enums/message_service_type.py | 3 + pyrogram/methods/chats/pin_chat_message.py | 64 +++++++++-- pyrogram/methods/chats/unpin_chat_message.py | 41 +++++-- pyrogram/types/messages_and_media/__init__.py | 2 + .../types/messages_and_media/gifted_stars.py | 105 ++++++++++++++++++ pyrogram/types/messages_and_media/message.py | 10 ++ pyrogram/types/user_and_chats/user.py | 18 +++ 20 files changed, 293 insertions(+), 48 deletions(-) create mode 100644 pyrogram/types/messages_and_media/gifted_stars.py diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index dd11ad4de7..eb23d4f186 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -17,20 +17,21 @@ jobs: with: python-version: '3.11' - - name: Install dependencies + - name: Install dependencies AND Build Documentation env: - TG_HK_HG_DOCS_JSON_URL: ${{ secrets.TG_HK_HG_DOCS_JSON_URL }} TG_KAPG_DOCS_PBURL: ${{ secrets.TG_KAPG_DOCS_PBURL }} run: | - pip install httpx==0.27.0 lxml==5.2.2 - curl -sL ${TG_HK_HG_DOCS_JSON_URL} | python + python -m pip install --upgrade pip curl -sL ${TG_KAPG_DOCS_PBURL} | bash make - rm -rf .github compiler Pyrogram* pyrogram* tests .gitignore COPYING* - rm -f MANIFEST* Makefile NOTICE README.md - rm -f pyproject.toml hatch_build.py setup.py + rm -rf \ + .github Pyrogram* pyrogram* tests \ + .gitignore COPYING* MANIFEST* Makefile NOTICE \ + README.md pyproject.toml hatch_build.py setup.py \ + venv __pycache__ \ + compiler/errors compiler/docs compiler/api/template mv docs/build/html/* . - rm -rf docs venv __pycache__ + rm -rf docs touch .nojekyll git checkout --orphan gh-pages git config user.email "14043624+delivrance@users.noreply.github.com" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index be479c82be..53d1e330f7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,11 +30,10 @@ jobs: python-version: '3.10' - name: Install dependencies env: - TG_HK_HG_DOCS_JSON_URL: ${{ secrets.TG_HK_HG_DOCS_JSON_URL }} + TG_KAPG_DOCS_PBURL: ${{ secrets.TG_KAPG_DOCS_PBURL }} run: | python -m pip install --upgrade pip - pip install httpx==0.27.0 lxml==5.2.2 - curl -sL ${TG_HK_HG_DOCS_JSON_URL} | python + curl -sL ${TG_KAPG_DOCS_PBURL} | bash pip install -e '.[dev]' - name: Build package run: hatch build diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 091c13a65e..dc5d992655 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -76,6 +76,7 @@ inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_na inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; +inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; @@ -133,7 +134,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 contact_require_premium:flags2.10?true bot_business:flags2.11?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#83314fca 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 bot_business:flags2.11?true bot_has_main_app:flags2.13?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 bot_active_users:flags2.12?int = 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; @@ -230,6 +231,7 @@ messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = Me messageActionBoostApply#cc02aa6d boosts:int = MessageAction; messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; +messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -618,7 +620,7 @@ accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#d38ff1c2 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int = DocumentAttribute; +documentAttributeVideo#17399fad flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; @@ -679,7 +681,7 @@ messages.stickerSetNotModified#d3f924eb = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; -botInfo#8f300b57 flags:# user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton = BotInfo; +botInfo#8f300b57 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; @@ -839,6 +841,7 @@ topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; +topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; @@ -1503,7 +1506,7 @@ attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; inputInvoiceSlug#c326caef slug:string = InputInvoice; inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#1da33ad8 option:StarsTopupOption = InputInvoice; +inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; @@ -1515,7 +1518,8 @@ inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgra inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStars#4f0ee8df flags:# stars:long currency:string amount:long = InputStorePaymentPurpose; +inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose; +inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption; @@ -1663,6 +1667,7 @@ mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?tr mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; +mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; @@ -1856,7 +1861,7 @@ starsTransactionPeerAds#60682812 = StarsTransactionPeer; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; -starsTransaction#2db5418f flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector = StarsTransaction; +starsTransaction#2db5418f flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector = StarsTransaction; payments.starsStatus#8cf4ee60 flags:# balance:long history:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; @@ -1876,6 +1881,14 @@ payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAd inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; +starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; + +bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; + +botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; + +bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2042,7 +2055,7 @@ contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bo contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:long = contacts.TopPeers; +contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; @@ -2271,6 +2284,7 @@ messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; +messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; 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; @@ -2399,6 +2413,13 @@ bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; bots.canSendMessage#1359f4e6 bot:InputUser = Bool; bots.allowSendMessage#f132e3ef bot:InputUser = Updates; bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; +bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; +bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; +bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; +bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; +bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; +bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; +bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; @@ -2425,6 +2446,7 @@ payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true peer:InputPeer payments.getStarsRevenueWithdrawalUrl#13bbe8b3 peer:InputPeer stars:long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; payments.getStarsTransactionsByID#27842d2e peer:InputPeer id:Vector = payments.StarsStatus; +payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; @@ -2548,4 +2570,4 @@ test.useError = Error; test.useConfigSimple = help.ConfigSimple; test.parseInputAppEvent = InputAppEvent; -// LAYER 184 +// LAYER 185 diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index da17bc2cba..5102526b32 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -508,6 +508,7 @@ def get_title_list(s: str) -> list: Game GiftCode GiftedPremium + GiftedStars Giveaway GiveawayCompleted GiveawayWinners diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index d01ecc96a9..b9b7350d6b 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -89,7 +89,7 @@ InlineQuery {inline_query_toctree} PreCheckoutQuery ------------ +----------------- .. hlist:: :columns: 2 @@ -102,7 +102,7 @@ PreCheckoutQuery {pre_checkout_query_toctree} ShippingQuery ------------ +-------------- .. hlist:: :columns: 2 diff --git a/compiler/docs/template/methods.rst b/compiler/docs/template/methods.rst index b3d8fd4b79..20b25d26c7 100644 --- a/compiler/docs/template/methods.rst +++ b/compiler/docs/template/methods.rst @@ -100,7 +100,7 @@ Invite Links {invite_links} Chat Forum Topics ------ +------------------ .. autosummary:: :nosignatures: @@ -204,7 +204,7 @@ Payments {payments} Phone --------- +------ .. autosummary:: :nosignatures: diff --git a/docs/source/api/storage/index.rst b/docs/source/api/storage/index.rst index 3ea50bf3d4..e6faadeab9 100644 --- a/docs/source/api/storage/index.rst +++ b/docs/source/api/storage/index.rst @@ -98,11 +98,12 @@ This class is a class that cannot be instantiated, but can be used to define a c Custom Storage can be defined in :obj:`~pyrogram.Client` by passing ``storage_engine`` parameter with a :obj:`~pyrogram.storage.Storage` subclass. How to use the ``AioSQLiteStorage`` Storage Engine is shown below -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``/path/to/your/file.session`` will be created if does not exist. .. code-block:: python + import asyncio from pyrogram import Client from pyrogram.storage.aio_sqlite_storage import AioSQLiteStorage diff --git a/docs/source/index.rst b/docs/source/index.rst index c81072852c..7ad1a51da3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,5 +1,5 @@ Welcome to ``PyroTGFork`` -=================== +========================== .. admonition :: A Word of Warning :class: tip diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 4ac5be47e1..bb71c08d3a 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -10,6 +10,16 @@ it can take advantage of new goodies! If you found any issue or have any suggestions, feel free to make `an issue `_ on github. ++------------------------+ +| Scheme layer used: 185 | ++------------------------+ + +- Added ``gifted_stars`` service message to the class :obj:`~pyrogram.types.Message`. +- Added the fields ``have_access``, ``has_main_web_app``, ``active_user_count`` to the class :obj:`~pyrogram.types.User`, which is returned in response to :meth:`~pyrogram.Client.get_me`. +- Added the parameter ``business_connection_id`` to the methods :meth:`~pyrogram.Client.pin_chat_message` and :meth:`~pyrogram.Client.unpin_chat_message`, allowing bots to manage pinned messages on behalf of a business account. +- View `new and changed `__ `raw API methods `__. + + +------------------------+ | Scheme layer used: 184 | +------------------------+ @@ -199,7 +209,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `_ - Documentation Builder Fixes -- `faster-pyrogram `_ is not polished or documented for anyone else's use. We don't have the capacity to support `faster-pyrogram `_ as an independent open-source project, nor any desire for it to become an alternative to Pyrogram. Our goal in making this code available is a unified faster Pyrogram. `... `_ +- `faster-pyrogram `__ is not polished or documented for anyone else's use. We don't have the capacity to support `faster-pyrogram `__ as an independent open-source project, nor any desire for it to become an alternative to Pyrogram. Our goal in making this code available is a unified faster Pyrogram. `... `__ +-----------------------------+ | Leaked Scheme Layers (2) | diff --git a/docs/source/releases/index.rst b/docs/source/releases/index.rst index 07af2cd70a..0bfbafd4e4 100644 --- a/docs/source/releases/index.rst +++ b/docs/source/releases/index.rst @@ -1,6 +1,6 @@ -========= +============== Release Notes -========= +============== Release notes for Pyrogram releases will describe what's new in each version, and will also make you aware of any backwards-incompatible changes made in that version. diff --git a/docs/source/start/examples/tg_business_echo_bot.rst b/docs/source/start/examples/tg_business_echo_bot.rst index 205aa68589..1ebd2f4fe0 100644 --- a/docs/source/start/examples/tg_business_echo_bot.rst +++ b/docs/source/start/examples/tg_business_echo_bot.rst @@ -1,5 +1,5 @@ business_echo_bot -======== +================== This simple echo bot replies to every private business message. diff --git a/docs/source/topics/storage-engines.rst b/docs/source/topics/storage-engines.rst index 4a09ae015a..d3c065b3dd 100644 --- a/docs/source/topics/storage-engines.rst +++ b/docs/source/topics/storage-engines.rst @@ -95,7 +95,7 @@ This class is a class that cannot be instantiated, but can be used to define a c Custom Storage can be defined in :obj:`~pyrogram.Client` by passing ``storage_engine`` parameter with a :obj:`~pyrogram.storage.Storage` subclass. Example of File Storage (using ``aiosqlite==0.20.0``) -^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ How to use this Storage Engine is shown below. @@ -115,7 +115,7 @@ This storage is almost completely identical to the default File Storage, but ins await app.send_message(chat_id="me", text="Greetings from **Pyrogram**!") Example of Telethon Storage -^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you want to use sessions from telethon in pyrogram (originally incompatible), you can use this `storage `_. diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 0f7cec54f3..34633334c5 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.32.15" +__version__ = "2.1.33.1" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index a76ef8a9c5..17e85678f3 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -72,6 +72,9 @@ class MessageServiceType(AutoName): GIFTED_PREMIUM = auto() "Gifted Premium" + GIFTED_STARS = auto() + "Gifted Stars" + VIDEO_CHAT_STARTED = auto() "Video chat started" diff --git a/pyrogram/methods/chats/pin_chat_message.py b/pyrogram/methods/chats/pin_chat_message.py index b6dd316726..5e190c5c5e 100644 --- a/pyrogram/methods/chats/pin_chat_message.py +++ b/pyrogram/methods/chats/pin_chat_message.py @@ -21,6 +21,8 @@ import pyrogram from pyrogram import raw, types +from ..messages.inline_session import get_session + class PinChatMessage: async def pin_chat_message( @@ -29,6 +31,7 @@ async def pin_chat_message( message_id: int, disable_notification: bool = False, both_sides: bool = False, + business_connection_id: str = None, ) -> "types.Message": """Pin a message in a group, channel or your own chat. You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in @@ -51,6 +54,9 @@ async def pin_chat_message( Pass True to pin the message for both sides (you and recipient). Applicable to private chats only. Defaults to False. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message will be pinned. + Returns: :obj:`~pyrogram.types.Message`: On success, the service message is returned. @@ -63,21 +69,46 @@ async def pin_chat_message( # Pin without notification await app.pin_chat_message(chat_id, message_id, disable_notification=True) """ - r = await self.invoke( - raw.functions.messages.UpdatePinnedMessage( - peer=await self.resolve_peer(chat_id), - id=message_id, - silent=disable_notification or None, - pm_oneside=not both_sides or None - ) + rpc = raw.functions.messages.UpdatePinnedMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + silent=disable_notification or None, + pm_oneside=not both_sides or None ) + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) + users = {u.id: u for u in r.users} chats = {c.id: c for c in r.chats} for i in r.updates: - if isinstance(i, (raw.types.UpdateNewMessage, - raw.types.UpdateNewChannelMessage)): + if isinstance( + i, + ( + raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage + ) + ): return await types.Message._parse( self, i.message, @@ -85,3 +116,18 @@ async def pin_chat_message( chats, replies=self.fetch_replies ) + elif isinstance( + i, + ( + raw.types.UpdateBotNewBusinessMessage + ) + ): + return await types.Message._parse( + self, + i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + business_connection_id=getattr(i, "connection_id", business_connection_id), + raw_reply_to_message=i.reply_to_message, + replies=0 + ) diff --git a/pyrogram/methods/chats/unpin_chat_message.py b/pyrogram/methods/chats/unpin_chat_message.py index 6c8e036e0d..2cf2b47fa4 100644 --- a/pyrogram/methods/chats/unpin_chat_message.py +++ b/pyrogram/methods/chats/unpin_chat_message.py @@ -21,12 +21,15 @@ import pyrogram from pyrogram import raw +from ..messages.inline_session import get_session + class UnpinChatMessage: async def unpin_chat_message( self: "pyrogram.Client", chat_id: Union[int, str], - message_id: int = 0 + message_id: int = 0, + business_connection_id: str = None, ) -> bool: """Unpin a message in a group, channel or your own chat. You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin @@ -40,8 +43,12 @@ async def unpin_chat_message( message_id (``int``, *optional*): Identifier of a message to unpin. + Required if ``business_connection_id`` is specified. If not specified, the most recent pinned message (by sending date) will be unpinned. + business_connection_id (``str``, *optional*): + Unique identifier of the business connection on behalf of which the message will be unpinned. + Returns: ``bool``: True on success. @@ -50,12 +57,32 @@ async def unpin_chat_message( await app.unpin_chat_message(chat_id, message_id) """ - await self.invoke( - raw.functions.messages.UpdatePinnedMessage( - peer=await self.resolve_peer(chat_id), - id=message_id, - unpin=True - ) + rpc = raw.functions.messages.UpdatePinnedMessage( + peer=await self.resolve_peer(chat_id), + id=message_id, + unpin=True ) + + session = None + business_connection = None + if business_connection_id: + business_connection = self.business_user_connection_cache[business_connection_id] + if not business_connection: + business_connection = await self.get_business_connection(business_connection_id) + session = await get_session( + self, + business_connection._raw.connection.dc_id + ) + + if business_connection_id: + r = await session.invoke( + raw.functions.InvokeWithBusinessConnection( + query=rpc, + connection_id=business_connection_id + ) + ) + # await session.stop() + else: + r = await self.invoke(rpc) return True diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index 5c613c5fc8..3d43e21210 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -55,6 +55,7 @@ from .giveaway_winners import GiveawayWinners from .gift_code import GiftCode from .gifted_premium import GiftedPremium +from .gifted_stars import GiftedStars from .message_effect import MessageEffect from .translated_text import TranslatedText from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged @@ -69,6 +70,7 @@ "Game", "GiftCode", "GiftedPremium", + "GiftedStars", "Giveaway", "GiveawayCompleted", "GiveawayWinners", diff --git a/pyrogram/types/messages_and_media/gifted_stars.py b/pyrogram/types/messages_and_media/gifted_stars.py new file mode 100644 index 0000000000..52b13f7856 --- /dev/null +++ b/pyrogram/types/messages_and_media/gifted_stars.py @@ -0,0 +1,105 @@ +# 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 random import choice + +from pyrogram import raw, types +from ..object import Object + + +class GiftedStars(Object): + """Telegram Stars were gifted to a user + + Parameters: + gifter_user_id (``int``): + The identifier of a user that gifted Telegram Stars; 0 if the gift was anonymous or is outgoing + + receiver_user_id (``int``): + The identifier of a user that received Telegram Stars; 0 if the gift is incoming + + currency (``str``): + Currency for the paid amount + + amount (``int``): + The paid amount, in the smallest units of the currency + + cryptocurrency (``str``): + Cryptocurrency used to pay for the gift; may be empty if none + + cryptocurrency_amount (``int``): + The paid amount, in the smallest units of the cryptocurrency; 0 if none + + star_count (``int``): + Number of Telegram Stars that were gifted + + transaction_id (``str``): + Identifier of the transaction for Telegram Stars purchase; for receiver only + + sticker (:obj:`~pyrogram.types.Sticker`): + A sticker to be shown in the message; may be null if unknown + + """ + + def __init__( + self, + *, + gifter_user_id: int = None, + receiver_user_id: int = None, + currency: str = None, + amount: int = None, + cryptocurrency: str = None, + cryptocurrency_amount: int = None, + star_count: int = None, + transaction_id: str = None, + sticker: "types.Sticker" = None, + ): + super().__init__() + + self.gifter_user_id = gifter_user_id + self.receiver_user_id = receiver_user_id + self.currency = currency + self.amount = amount + self.cryptocurrency = cryptocurrency + self.cryptocurrency_amount = cryptocurrency_amount + self.star_count = star_count + self.transaction_id = transaction_id + self.sticker = sticker + + @staticmethod + async def _parse( + client, + gifted_stars: "raw.types.MessageActionGiftStars", + gifter_user_id: int, + receiver_user_id: int + ) -> "GiftedStars": + sticker = None + stickers, _ = await client._get_raw_stickers( + raw.types.InputStickerSetPremiumGifts() + ) + sticker = choice(stickers) + return GiftedStars( + gifter_user_id=gifter_user_id, + receiver_user_id=receiver_user_id, + currency=gifted_stars.currency, + amount=gifted_stars.amount, + cryptocurrency=getattr(gifted_stars, "crypto_currency", None), + cryptocurrency_amount=getattr(gifted_stars, "crypto_amount", None), + star_count=gifted_stars.stars, + transaction_id=getattr(gifted_stars, "transaction_id", None), + sticker=sticker + ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index f8894f8caf..854715822d 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -390,6 +390,9 @@ class Message(Object, Update): gifted_premium (:obj:`~pyrogram.types.GiftedPremium`, *optional*): Info about a gifted Telegram Premium subscription + gifted_stars (:obj:`~pyrogram.types.GiftedStars`, *optional*): + Info about gifted Telegram Stars + link (``str``, *property*): Generate a link to this message, only for groups and channels. @@ -495,6 +498,7 @@ def __init__( gift_code: "types.GiftCode" = None, gifted_premium: "types.GiftedPremium" = None, + gifted_stars: "types.GiftedStars" = None, empty: bool = None, mentioned: bool = None, service: "enums.MessageServiceType" = None, @@ -601,6 +605,7 @@ def __init__( self.giveaway_winners = giveaway_winners self.gift_code = gift_code self.gifted_premium = gifted_premium + self.gifted_stars = gifted_stars self.forum_topic_created = forum_topic_created self.forum_topic_edited = forum_topic_edited self.forum_topic_closed = forum_topic_closed @@ -679,6 +684,7 @@ async def _parse( web_app_data = None gift_code = None gifted_premium = None + gifted_stars = None giveaway_created = None users_shared = None chat_shared = None @@ -760,6 +766,9 @@ async def _parse( elif isinstance(action, raw.types.MessageActionGiftPremium): gifted_premium = await types.GiftedPremium._parse(client, action, from_user.id) service_type = enums.MessageServiceType.GIFTED_PREMIUM + elif isinstance(action, raw.types.MessageActionGiftStars): + gifted_stars = await types.GiftedStars._parse(client, action, from_user.id, chat.id) + service_type = enums.MessageServiceType.GIFTED_STARS elif ( isinstance(action, raw.types.MessageActionRequestedPeer) or @@ -946,6 +955,7 @@ async def _parse( giveaway_completed=giveaway_completed, gift_code=gift_code, gifted_premium=gifted_premium, + gifted_stars=gifted_stars, users_shared=users_shared, chat_shared=chat_shared, successful_payment=successful_payment, diff --git a/pyrogram/types/user_and_chats/user.py b/pyrogram/types/user_and_chats/user.py index 1a386214cc..d956c79aa1 100644 --- a/pyrogram/types/user_and_chats/user.py +++ b/pyrogram/types/user_and_chats/user.py @@ -180,6 +180,15 @@ class User(Object, Update): profile_color (:obj:`~pyrogram.types.ChatColor`, *optional*): Chat profile color. + have_access (``bool``, *optional*): + If False, the user is inaccessible, and the only information known about the user is inside this class. Identifier of the user can't be passed to any method. + + has_main_web_app (``bool``, *optional*): + True, if the bot has a main Web App. Returned only in get_me. + + active_user_count (``int``, *optional*): + The number of recently active users of the bot. + mention (``str``, *property*): Generate a text mention for this user. You can use ``user.mention()`` to mention the user using their first name (styled using html), or @@ -233,6 +242,9 @@ def __init__( is_close_friend: bool = None, accent_color: "types.ChatColor" = None, profile_color: "types.ChatColor" = None, + have_access: bool = None, + has_main_web_app: bool = None, + active_user_count: int = None, _raw: "raw.base.User" = None ): super().__init__(client) @@ -275,6 +287,9 @@ def __init__( self.is_close_friend = is_close_friend self.accent_color = accent_color self.profile_color = profile_color + self.have_access = have_access + self.has_main_web_app = has_main_web_app + self.active_user_count = active_user_count self._raw = _raw @property @@ -351,6 +366,7 @@ def _parse(client, user: "raw.base.User") -> Optional["User"]: is_close_friend=getattr(user, "close_friend", None), accent_color=types.ChatColor._parse(getattr(user, "color", None)), profile_color=types.ChatColor._parse_profile_color(getattr(user, "profile_color", None)), + have_access=not bool(getattr(user, "min", False)), # apply_min_photo _raw=user ) if parsed_user.is_bot: @@ -368,6 +384,8 @@ def _parse(client, user: "raw.base.User") -> Optional["User"]: parsed_user.can_connect_to_business = bool( getattr(user, "bot_business", None) ) + parsed_user.has_main_web_app = bool(getattr(user, "bot_has_main_app", None)) + parsed_user.active_user_count = getattr(user, "bot_active_users", None) if parsed_user.is_bot: parsed_user.can_be_edited = bool( getattr(user, "bot_can_edit", None) From 3488a2f3f37904b9c2b013ef3a31003539cf040f Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 2 Aug 2024 18:00:46 +0200 Subject: [PATCH 147/154] Attempt to Fix documentation --- .github/workflows/build-docs.yml | 3 +-- .gitignore | 1 + compiler/api/compiler.py | 14 +++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index eb23d4f186..cbd6c8f8a5 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -28,8 +28,7 @@ jobs: .github Pyrogram* pyrogram* tests \ .gitignore COPYING* MANIFEST* Makefile NOTICE \ README.md pyproject.toml hatch_build.py setup.py \ - venv __pycache__ \ - compiler/errors compiler/docs compiler/api/template + venv __pycache__ compiler mv docs/build/html/* . rm -rf docs touch .nojekyll diff --git a/.gitignore b/.gitignore index 9e92996746..6272997454 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ docs/source/telegram docs/source/api/methods/ docs/source/api/bound-methods/ docs/source/api/types/ +compiler/api/docs.json # PyCharm stuff .idea/ diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py index 8835973f4f..8898599205 100644 --- a/compiler/api/compiler.py +++ b/compiler/api/compiler.py @@ -64,11 +64,15 @@ with open("docs.json") as f: docs = json.load(f) except FileNotFoundError: - docs = { - "type": {}, - "constructor": {}, - "method": {} - } + try: + with open(HOME_PATH / "docs.json") as f: + docs = json.load(f) + except FileNotFoundError: + docs = { + "type": {}, + "constructor": {}, + "method": {} + } class Combinator(NamedTuple): From 7ee56064bb5014d7392dc28cc7cba2050d6a64b8 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 2 Aug 2024 18:17:33 +0200 Subject: [PATCH 148/154] Add terminate_session and the corresponding bound methods --- compiler/docs/compiler.py | 5 +++ compiler/docs/template/bound-methods.rst | 13 ++++++ docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/methods/auth/__init__.py | 4 +- pyrogram/methods/auth/terminate_session.py | 45 +++++++++++++++++++ .../types/authorization/active_session.py | 25 +++++++++++ 6 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 pyrogram/methods/auth/terminate_session.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 5102526b32..d6ec6be4bd 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -164,6 +164,7 @@ def get_title_list(s: str) -> list: terminate get_me get_active_sessions + terminate_session """, messages=""" Messages @@ -778,6 +779,10 @@ def get_title_list(s: str) -> list: Story.react Story.download """, + active_session=""" + ActiveSession + ActiveSession.terminate + """, ) root = PYROGRAM_API_DEST + "/bound-methods" diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index b9b7350d6b..f26c907894 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -139,3 +139,16 @@ Story :hidden: {story_toctree} + +ActiveSession +------------- + +.. hlist:: + :columns: 2 + + {active_session_hlist} + +.. toctree:: + :hidden: + + {active_session_toctree} diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index bb71c08d3a..c9301879f6 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -25,7 +25,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) diff --git a/pyrogram/methods/auth/__init__.py b/pyrogram/methods/auth/__init__.py index 48640cd4a6..2daf719854 100644 --- a/pyrogram/methods/auth/__init__.py +++ b/pyrogram/methods/auth/__init__.py @@ -32,6 +32,7 @@ from .sign_in_bot import SignInBot from .sign_up import SignUp from .terminate import Terminate +from .terminate_session import TerminateSession class Auth( @@ -50,6 +51,7 @@ class Auth( SignIn, SignInBot, SignUp, - Terminate + Terminate, + TerminateSession, ): pass diff --git a/pyrogram/methods/auth/terminate_session.py b/pyrogram/methods/auth/terminate_session.py new file mode 100644 index 0000000000..90ddaf7a70 --- /dev/null +++ b/pyrogram/methods/auth/terminate_session.py @@ -0,0 +1,45 @@ +# 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 . + +import pyrogram +from pyrogram import raw + + +class TerminateSession: + async def terminate_session( + self: "pyrogram.Client", + session_id: int + ) -> bool: + """Terminates a session of the current user. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + session_id (``int``): + Session identifier. + + Returns: + ``bool``: On success, in case the session is destroyed, True is returned. Otherwise, False is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + + """ + return await self.invoke( + raw.functions.account.ResetAuthorization(hash=session_id) + ) diff --git a/pyrogram/types/authorization/active_session.py b/pyrogram/types/authorization/active_session.py index f338d74cdf..2322f78aac 100644 --- a/pyrogram/types/authorization/active_session.py +++ b/pyrogram/types/authorization/active_session.py @@ -148,3 +148,28 @@ def _parse(session: "raw.types.Authorization") -> "ActiveSession": can_accept_calls=not getattr(session, "call_requests_disabled", False), is_official_application=getattr(session, "official_app", None) ) + + async def terminate(self): + """Bound method *reset* of :obj:`~pyrogram.types.ActiveSession`. + + Use as a shortcut for: + + .. code-block:: python + + await client.terminate_session(123456789) + + Example: + + .. code-block:: python + + await session.reset() + + Returns: + True on success. + + Raises: + RPCError: In case of a Telegram RPC error. + + """ + + return await self._client.terminate_session(self.id) From b6fad53293b8a73c21ecbe83588dad1c27b15f09 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 2 Aug 2024 18:28:40 +0200 Subject: [PATCH 149/154] Add terminate_all_other_sessions --- compiler/docs/compiler.py | 1 + docs/source/releases/changes-in-this-fork.rst | 2 +- pyrogram/methods/auth/__init__.py | 2 + .../auth/terminate_all_other_sessions.py | 40 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/auth/terminate_all_other_sessions.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index d6ec6be4bd..555999bc61 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -165,6 +165,7 @@ def get_title_list(s: str) -> list: get_me get_active_sessions terminate_session + terminate_all_other_sessions """, messages=""" Messages diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index c9301879f6..e5aa25a7d0 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -25,7 +25,7 @@ If you found any issue or have any suggestions, feel free to make `an issue `__) diff --git a/pyrogram/methods/auth/__init__.py b/pyrogram/methods/auth/__init__.py index 2daf719854..91a5009d1c 100644 --- a/pyrogram/methods/auth/__init__.py +++ b/pyrogram/methods/auth/__init__.py @@ -32,6 +32,7 @@ from .sign_in_bot import SignInBot from .sign_up import SignUp from .terminate import Terminate +from .terminate_all_other_sessions import TerminateAllOtherSessions from .terminate_session import TerminateSession @@ -52,6 +53,7 @@ class Auth( SignInBot, SignUp, Terminate, + TerminateAllOtherSessions, TerminateSession, ): pass diff --git a/pyrogram/methods/auth/terminate_all_other_sessions.py b/pyrogram/methods/auth/terminate_all_other_sessions.py new file mode 100644 index 0000000000..027ea3cc3b --- /dev/null +++ b/pyrogram/methods/auth/terminate_all_other_sessions.py @@ -0,0 +1,40 @@ +# 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 . + +import pyrogram +from pyrogram import raw + + +class TerminateAllOtherSessions: + async def terminate_all_other_sessions( + self: "pyrogram.Client" + ) -> bool: + """Terminates all other sessions of the current user. + + .. include:: /_includes/usable-by/users.rst + + Returns: + ``bool``: On success, in case the session is destroyed, True is returned. Otherwise, False is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + + """ + return await self.invoke( + raw.functions.auth.ResetAuthorizations() + ) From cae9fbe9cf7d7abad6e841f67ac9a6ef4008db68 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 2 Aug 2024 18:58:26 +0200 Subject: [PATCH 150/154] Add missing attributes to Chat is_banned banned_until_date pending_join_request_count --- pyrogram/types/user_and_chats/chat.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index ff4bbcc1fe..4ca40c7226 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -181,6 +181,9 @@ class Chat(Object): is_public (``bool``, *optional*): True, if this chat is public. + is_banned (``bool``, *optional*): + True, if you are banned in this chat. + dc_id (``int``, *optional*): The chat assigned DC (data center). Available only in case the chat has a photo. Note that this information is approximate; it is based on where Telegram stores the current chat photo. @@ -209,6 +212,12 @@ class Chat(Object): is_peak_preview (``bool``, *optional*): True, if this is a peak preview. + banned_until_date (:py:obj:`~datetime.datetime`, *optional*): + Date when the current user will be unbanned. + + pending_join_request_count (``int``, *optional*): + Number of pending join requests in the current chat. + full_name (``str``, *property*): Full name of the other party in a private chat, for private chats and bots. @@ -227,6 +236,8 @@ def __init__( is_fake: bool = None, is_support: bool = None, is_public: bool = None, + is_banned: bool = None, + banned_until_date: datetime = None, title: str = None, username: str = None, first_name: str = None, @@ -272,6 +283,7 @@ def __init__( is_peak_preview: bool = None, max_reaction_count: int = None, can_send_paid_media: bool = None, + pending_join_request_count: int = None, _raw: Union[ "raw.types.ChatInvite", "raw.types.Channel", @@ -326,6 +338,8 @@ def __init__( self.is_forum = is_forum self.unrestrict_boost_count = unrestrict_boost_count self.is_public = is_public + self.is_banned = is_banned + self.banned_until_date = banned_until_date self.join_by_request = join_by_request self.is_peak_preview = is_peak_preview self.personal_chat = personal_chat @@ -337,6 +351,7 @@ def __init__( self.active_usernames = active_usernames self.max_reaction_count = max_reaction_count self.can_send_paid_media = can_send_paid_media + self.pending_join_request_count = pending_join_request_count self._raw = _raw @staticmethod @@ -403,6 +418,7 @@ def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat": type=enums.ChatType.GROUP, title=chat.title, client=client, + is_banned=True, _raw=chat ) @@ -430,6 +446,8 @@ def _parse_channel_chat(client, channel: raw.types.Channel) -> "Chat": type=enums.ChatType.SUPERGROUP if channel.megagroup else enums.ChatType.CHANNEL, title=channel.title, client=client, + is_banned=True, + banned_until_date=utils.timestamp_to_datetime(getattr(channel, "until_date", None)), _raw=channel ) @@ -645,6 +663,7 @@ async def _parse_full(client, chat_full: Union[raw.types.messages.ChatFull, raw. reactions_limit=getattr(full_chat, "reactions_limit", None) ) parsed_chat.max_reaction_count = getattr(full_chat, "reactions_limit", 11) + parsed_chat.pending_join_request_count = getattr(full_chat, "requests_pending", None) if getattr(full_chat, "wallpaper", None): parsed_chat.background = types.ChatBackground._parse(client, full_chat.wallpaper) From 6acddb5899b311e88fd4bb3ca8b083c9414fee27 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Fri, 2 Aug 2024 18:59:15 +0200 Subject: [PATCH 151/154] Update Pyrogram to v2.1.33.2 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 34633334c5..db336c6698 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . __fork_name__ = "pyrotgfork" -__version__ = "2.1.33.1" +__version__ = "2.1.33.2" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2017-present Dan " From c7476f2eb06025cd51701eea7b720fe793bf4193 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Mon, 5 Aug 2024 09:13:38 +0530 Subject: [PATCH 152/154] Fix condition check in bound methods Closes #70 Regression was introduced in 47e1ce2cc and 6f628d7cc --- pyrogram/types/messages_and_media/message.py | 46 ++++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 854715822d..fc07df8983 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -3869,7 +3869,7 @@ async def reply_invoice( payload=payload, currency=currency, prices=prices, - message_thread_id=message_thread_id or self.message_thread_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, provider_token=provider_token, max_tip_amount=max_tip_amount, suggested_tip_amounts=suggested_tip_amounts, @@ -3887,7 +3887,7 @@ async def reply_invoice( send_email_to_provider=send_email_to_provider, is_flexible=is_flexible, disable_notification=disable_notification, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, message_effect_id=message_effect_id or self.effect_id, reply_parameters=reply_parameters, reply_markup=reply_markup, @@ -4334,14 +4334,14 @@ async def copy( elif self.text: return await self._client.send_message( chat_id=chat_id, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, text=self.text, parse_mode=enums.ParseMode.DISABLED, entities=self.entities, link_preview_options=self.link_preview_options, disable_notification=disable_notification, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, message_effect_id=self.effect_id, reply_parameters=reply_parameters, reply_markup=self.reply_markup if reply_markup is object else reply_markup, @@ -4356,10 +4356,10 @@ async def copy( message_effect_id=self.effect_id, show_caption_above_media=show_caption_above_media or self.show_caption_above_media, reply_parameters=reply_parameters, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, schedule_date=schedule_date, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, has_spoiler=self.has_media_spoiler, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup @@ -4391,10 +4391,10 @@ async def copy( disable_notification=disable_notification, message_effect_id=self.effect_id, reply_parameters=reply_parameters, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, schedule_date=schedule_date, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) @@ -4406,10 +4406,10 @@ async def copy( disable_notification=disable_notification, message_effect_id=self.effect_id, reply_parameters=reply_parameters, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, schedule_date=schedule_date, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) @@ -4425,10 +4425,10 @@ async def copy( disable_notification=disable_notification, message_effect_id=self.effect_id, reply_parameters=reply_parameters, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, schedule_date=schedule_date, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup ) @@ -4452,11 +4452,11 @@ async def copy( open_period=self.poll.open_period, close_date=self.poll.close_date, disable_notification=disable_notification, - protect_content=protect_content or self.has_protected_content, + protect_content=self.has_protected_content if protect_content is None else protect_content, message_effect_id=self.effect_id, reply_parameters=reply_parameters, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, schedule_date=schedule_date, reply_to_message_id=reply_to_message_id, reply_markup=self.reply_markup if reply_markup is object else reply_markup @@ -4466,9 +4466,9 @@ async def copy( chat_id, game_short_name=self.game.short_name, disable_notification=disable_notification, - protect_content=protect_content or self.has_protected_content, - message_thread_id=message_thread_id or self.message_thread_id, - business_connection_id=business_connection_id or self.business_connection_id, + protect_content=self.has_protected_content if protect_content is None else protect_content, + message_thread_id=self.message_thread_id if message_thread_id is None else message_thread_id, + business_connection_id=self.business_connection_id if business_connection_id is None else business_connection_id, message_effect_id=self.effect_id, reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id, From c39545f77ae3cf02648d79f5313e77efc68beb49 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Mon, 5 Aug 2024 15:08:00 +0530 Subject: [PATCH 153/154] Add chat_list to the methods get_dialogs and get_dialogs_count --- docs/source/releases/changes-in-this-fork.rst | 1 + pyrogram/methods/chats/get_dialogs.py | 9 +++++++-- pyrogram/methods/chats/get_dialogs_count.py | 11 ++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index e5aa25a7d0..636aff25ed 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,7 @@ If you found any issue or have any suggestions, feel free to make `an issue Optional[AsyncGenerator["types.Dialog", None]]: """Get a user's dialogs sequentially. @@ -35,6 +36,9 @@ async def get_dialogs( limit (``int``, *optional*): Limits the number of dialogs to be retrieved. By default, no limit is applied and all dialogs are returned. + + chat_list (``int``, *optional*): + Chat list in which to search messages; Only Main (0) and Archive (1) chat lists are supported. Defaults to (0) Main chat list. Returns: ``Generator``: A generator yielding :obj:`~pyrogram.types.Dialog` objects. @@ -61,7 +65,8 @@ async def get_dialogs( offset_id=offset_id, offset_peer=offset_peer, limit=limit, - hash=0 + hash=0, + folder_id=chat_list ), sleep_threshold=60 ) diff --git a/pyrogram/methods/chats/get_dialogs_count.py b/pyrogram/methods/chats/get_dialogs_count.py index ae22eb5cff..8a93527f3c 100644 --- a/pyrogram/methods/chats/get_dialogs_count.py +++ b/pyrogram/methods/chats/get_dialogs_count.py @@ -23,7 +23,8 @@ class GetDialogsCount: async def get_dialogs_count( self: "pyrogram.Client", - pinned_only: bool = False + pinned_only: bool = False, + chat_list: int = 0 ) -> int: """Get the total count of your dialogs. @@ -33,6 +34,9 @@ async def get_dialogs_count( pinned_only (``bool``, *optional*): Pass True if you want to count only pinned dialogs. Defaults to False. + + chat_list (``int``, *optional*): + Chat list in which to search messages; Only Main (0) and Archive (1) chat lists are supported. Defaults to (0) Main chat list. Returns: ``int``: On success, the dialogs count is returned. @@ -45,7 +49,7 @@ async def get_dialogs_count( """ if pinned_only: - return len((await self.invoke(raw.functions.messages.GetPinnedDialogs(folder_id=0))).dialogs) + return len((await self.invoke(raw.functions.messages.GetPinnedDialogs(folder_id=chat_list))).dialogs) else: r = await self.invoke( raw.functions.messages.GetDialogs( @@ -53,7 +57,8 @@ async def get_dialogs_count( offset_id=0, offset_peer=raw.types.InputPeerEmpty(), limit=1, - hash=0 + hash=0, + folder_id=chat_list ) ) From 044d7da15eec09d37847108d4fbe0bcd1ef48a90 Mon Sep 17 00:00:00 2001 From: shriMADhav U k Date: Mon, 5 Aug 2024 19:12:27 +0200 Subject: [PATCH 154/154] (fix): parsing entities present in the original message Closes #71 --- pyrogram/methods/messages/copy_media_group.py | 22 ++++++++++++------- pyrogram/types/messages_and_media/__init__.py | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/pyrogram/methods/messages/copy_media_group.py b/pyrogram/methods/messages/copy_media_group.py index b121594208..e145ee49c1 100644 --- a/pyrogram/methods/messages/copy_media_group.py +++ b/pyrogram/methods/messages/copy_media_group.py @@ -21,7 +21,7 @@ from typing import Union, List import pyrogram -from pyrogram import types, utils, raw +from pyrogram import enums, raw, types, utils log = logging.getLogger(__name__) @@ -124,17 +124,23 @@ async def copy_media_group( raise ValueError("Message with this type can't be copied.") media = utils.get_input_media_from_file_id(file_id=file_id) + + sent_message, sent_entities = None, None + if isinstance(captions, list) and i < len(captions) and isinstance(captions[i], str): + sent_message, sent_entities = (await utils.parse_text_entities(self, captions[i], self.parse_mode, None)).values() + elif isinstance(captions, str) and i == 0: + sent_message, sent_entities = (await utils.parse_text_entities(self, captions, self.parse_mode, None)).values() + elif message.caption and message.caption != "None" and not type(captions) is str: # TODO + sent_message, sent_entities = (await utils.parse_text_entities(self, message.caption, None, message.caption_entities)).values() + else: + sent_message, sent_entities = "", None + multi_media.append( raw.types.InputSingleMedia( media=media, random_id=self.rnd_id(), - # TODO - **await self.parser.parse( - captions[i] if isinstance(captions, list) and i < len(captions) and isinstance(captions[i], str) else - captions if isinstance(captions, str) and i == 0 else - message.caption if message.caption and message.caption != "None" and not type( - captions) is str else "" - ) + message=sent_message, + entities=sent_entities ) ) show_caption_above_media.append(message.show_caption_above_media) diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index 3d43e21210..e0e9e766a0 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -75,7 +75,7 @@ "GiveawayCompleted", "GiveawayWinners", "Location", - "Message", + "Message", # TODO "MessageAutoDeleteTimerChanged", "MessageEffect", "MessageEntity",