From e42599051c3d1e593cfe5afa2068e899889ae645 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 3 Mar 2019 16:50:25 +0100 Subject: [PATCH 1/7] Use a lower timeout when starting a session to speed up re-connections Sometimes the server drops right after a successful connection and pyrogram keeps waiting up 15 seconds (current WAIT_TIMEOUT) for the first query to time out and start again a new connection. --- pyrogram/session/session.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 21bb1133..5392728f 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -48,6 +48,7 @@ class Result: class Session: INITIAL_SALT = 0x616e67656c696361 NET_WORKERS = 1 + START_TIMEOUT = 1 WAIT_TIMEOUT = 15 MAX_RETRIES = 5 ACKS_THRESHOLD = 8 @@ -130,8 +131,14 @@ class Session: Thread(target=self.recv, name="RecvThread").start() self.current_salt = FutureSalt(0, 0, self.INITIAL_SALT) - self.current_salt = FutureSalt(0, 0, self._send(functions.Ping(0)).new_server_salt) - self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0] + self.current_salt = FutureSalt( + 0, 0, + self._send( + functions.Ping(0), + timeout=self.START_TIMEOUT + ).new_server_salt + ) + self.current_salt = self._send(functions.GetFutureSalts(1), timeout=self.START_TIMEOUT).salts[0] self.next_salt_thread = Thread(target=self.next_salt, name="NextSaltThread") self.next_salt_thread.start() @@ -150,7 +157,8 @@ class Session: lang_pack="", query=functions.help.GetConfig(), ) - ) + ), + timeout=self.START_TIMEOUT ) self.ping_thread = Thread(target=self.ping, name="PingThread") From 2a9c34481f1ab55a2ca967594cf41c861317c55c Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 3 Mar 2019 17:55:53 +0100 Subject: [PATCH 2/7] Add PHOTO_EXT_INVALID error --- compiler/error/source/400_BAD_REQUEST.tsv | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index 953b96af..8537e43d 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -91,3 +91,4 @@ IMAGE_PROCESS_FAILED The server failed to process your image USERNAME_NOT_MODIFIED The username was not modified CALL_ALREADY_ACCEPTED The call is already accepted CALL_ALREADY_DECLINED The call is already declined +PHOTO_EXT_INVALID The photo extension is invalid \ No newline at end of file From 64775f52092d306ece84c19eaf322fd84a98e72c Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 4 Mar 2019 12:50:42 +0100 Subject: [PATCH 3/7] Fix "ModuleNotFoundError is not defined" error for Python <3.6 --- pyrogram/client/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index edbe29d1..fbf9f038 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -1179,7 +1179,7 @@ class Client(Methods, BaseClient): try: module = import_module(module_path) - except ModuleNotFoundError: + except ImportError: log.warning('[LOAD] Ignoring non-existent module "{}"'.format(module_path)) continue @@ -1215,7 +1215,7 @@ class Client(Methods, BaseClient): try: module = import_module(module_path) - except ModuleNotFoundError: + except ImportError: log.warning('[UNLOAD] Ignoring non-existent module "{}"'.format(module_path)) continue From a4ea3f768c71c02cd40e20f2bd30a1b36f75efa2 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 4 Mar 2019 12:56:47 +0100 Subject: [PATCH 4/7] Fix get_chat_member not working when passing "me" in basic groups --- pyrogram/client/methods/chats/get_chat_member.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/client/methods/chats/get_chat_member.py b/pyrogram/client/methods/chats/get_chat_member.py index faf0c33b..7ed4104b 100644 --- a/pyrogram/client/methods/chats/get_chat_member.py +++ b/pyrogram/client/methods/chats/get_chat_member.py @@ -55,7 +55,7 @@ class GetChatMember(BaseClient): ) for member in pyrogram.ChatMembers._parse(self, full_chat).chat_members: - if member.user.id == user_id.user_id: + if member.user.is_self: return member else: raise errors.UserNotParticipant From b3ef53a29a8dc153fa6f5f5576f79526897d428e Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 11 Mar 2019 21:26:07 +0100 Subject: [PATCH 5/7] Add send_cached_media method --- pyrogram/client/methods/messages/__init__.py | 4 +- .../methods/messages/send_cached_media.py | 135 ++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 pyrogram/client/methods/messages/send_cached_media.py diff --git a/pyrogram/client/methods/messages/__init__.py b/pyrogram/client/methods/messages/__init__.py index f76d0a22..dde50b7b 100644 --- a/pyrogram/client/methods/messages/__init__.py +++ b/pyrogram/client/methods/messages/__init__.py @@ -30,6 +30,7 @@ from .iter_history import IterHistory from .retract_vote import RetractVote from .send_animation import SendAnimation from .send_audio import SendAudio +from .send_cached_media import SendCachedMedia from .send_chat_action import SendChatAction from .send_contact import SendContact from .send_document import SendDocument @@ -74,6 +75,7 @@ class Messages( ClosePoll, RetractVote, DownloadMedia, - IterHistory + IterHistory, + SendCachedMedia ): pass diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py new file mode 100644 index 00000000..843b7197 --- /dev/null +++ b/pyrogram/client/methods/messages/send_cached_media.py @@ -0,0 +1,135 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 binascii +import struct +from typing import Union + +import pyrogram +from pyrogram.api import functions, types +from pyrogram.api.errors import FileIdInvalid +from pyrogram.client.ext import BaseClient, utils + + +class SendCachedMedia(BaseClient): + def send_cached_media( + self, + chat_id: Union[int, str], + file_id: str, + caption: str = "", + parse_mode: str = "", + disable_notification: bool = None, + reply_to_message_id: int = None, + reply_markup: Union[ + "pyrogram.InlineKeyboardMarkup", + "pyrogram.ReplyKeyboardMarkup", + "pyrogram.ReplyKeyboardRemove", + "pyrogram.ForceReply" + ] = None + ) -> Union["pyrogram.Message", None]: + """Use this method to send any 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 sending media using a file_id, thus saving you from the + hassle of using the correct method for the media the file_id is pointing to. + + Args: + 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). + + file_id (``str``): + Media to send. + Pass a file_id as string to send a media that exists on the Telegram servers. + + caption (``bool``, *optional*): + Media caption, 0-1024 characters. + + parse_mode (``str``, *optional*): + Use :obj:`MARKDOWN ` or :obj:`HTML ` + if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption. + Defaults to Markdown. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_message_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`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. + + Returns: + On success, the sent :obj:`Message ` is returned. + + Raises: + :class:`Error ` in case of a Telegram RPC error. + """ + style = self.html if parse_mode.lower() == "html" else self.markdown + + try: + decoded = utils.decode(file_id) + fmt = " 24 else " Date: Mon, 11 Mar 2019 21:26:15 +0100 Subject: [PATCH 6/7] Add EXTERNAL_URL_INVALID error --- compiler/error/source/400_BAD_REQUEST.tsv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index 8537e43d..0b9804a7 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -91,4 +91,5 @@ IMAGE_PROCESS_FAILED The server failed to process your image USERNAME_NOT_MODIFIED The username was not modified CALL_ALREADY_ACCEPTED The call is already accepted CALL_ALREADY_DECLINED The call is already declined -PHOTO_EXT_INVALID The photo extension is invalid \ No newline at end of file +PHOTO_EXT_INVALID The photo extension is invalid +EXTERNAL_URL_INVALID The external media URL is invalid \ No newline at end of file From 90b959555da61419d817673e3fcc3ee4f8a18fe2 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Tue, 12 Mar 2019 16:46:54 +0100 Subject: [PATCH 7/7] Fix flood waits generated when iterating over basic chat members --- pyrogram/client/methods/chats/iter_chat_members.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py index 5d0fa911..b0aeb51b 100644 --- a/pyrogram/client/methods/chats/iter_chat_members.py +++ b/pyrogram/client/methods/chats/iter_chat_members.py @@ -20,6 +20,7 @@ from string import ascii_lowercase from typing import Union, Generator import pyrogram +from pyrogram.api import types from ...ext import BaseClient @@ -82,6 +83,7 @@ class IterChatMembers(BaseClient): queries = [query] if query else QUERIES total = limit or (1 << 31) - 1 limit = min(200, total) + resolved_chat_id = self.resolve_peer(chat_id) filter = ( Filters.RECENT @@ -107,6 +109,9 @@ class IterChatMembers(BaseClient): if not chat_members: break + if isinstance(resolved_chat_id, types.InputPeerChat): + total = len(chat_members) + offset += len(chat_members) for chat_member in chat_members: