diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index 382e521e..08db4c4f 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -51,7 +51,7 @@ BOT_INLINE_DISABLED The inline feature of the bot is disabled INLINE_RESULT_EXPIRED The inline bot query expired INVITE_HASH_INVALID The invite link hash is invalid USER_ALREADY_PARTICIPANT The user is already a participant of this chat -TTL_MEDIA_INVALID This kind of media does not support self-destruction +TTL_MEDIA_INVALID The media does not support self-destruction MAX_ID_INVALID The max_id parameter is invalid CHANNEL_INVALID The channel parameter is invalid DC_ID_INVALID The dc_id parameter is invalid @@ -59,7 +59,7 @@ LIMIT_INVALID The limit parameter is invalid OFFSET_INVALID The offset parameter is invalid EMAIL_INVALID The email provided is invalid USER_IS_BOT A bot cannot send messages to other bots or to itself -WEBPAGE_CURL_FAILED Telegram could not fetch the provided URL +WEBPAGE_CURL_FAILED Telegram server could not fetch the provided URL STICKERSET_INVALID The requested sticker set is invalid PEER_FLOOD The method can't be used because your account is limited MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters @@ -68,4 +68,12 @@ USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side USER_NOT_PARTICIPANT The user is not a member of this chat CHANNEL_PRIVATE The channel/supergroup is not accessible -MESSAGE_IDS_EMPTY The requested message doesn't exist \ No newline at end of file +MESSAGE_IDS_EMPTY The requested message doesn't exist +WEBPAGE_MEDIA_EMPTY The URL doesn't contain any valid media +QUERY_ID_INVALID The callback query id is invalid +MEDIA_EMPTY The media is invalid +USER_IS_BLOCKED The user blocked you +YOU_BLOCKED_USER You blocked this user +ADMINS_TOO_MUCH The chat has too many administrators +BOTS_TOO_MUCH The chat has too many bots +USER_ADMIN_INVALID The action requires admin privileges \ No newline at end of file diff --git a/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv b/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv index 60d1b51a..d1c666c6 100644 --- a/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv +++ b/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv @@ -4,4 +4,5 @@ RPC_CALL_FAIL Telegram is having internal problems. Please try again later RPC_MCGET_FAIL Telegram is having internal problems. Please try again later PERSISTENT_TIMESTAMP_OUTDATED Telegram is having internal problems. Please try again later HISTORY_GET_FAILED Telegram is having internal problems. Please try again later -REG_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later \ No newline at end of file +REG_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later +RANDOM_ID_DUPLICATE Telegram is having internal problems. Please try again later \ No newline at end of file diff --git a/examples/welcome_bot.py b/examples/welcome_bot.py index 5dbb44fb..4326ed6c 100644 --- a/examples/welcome_bot.py +++ b/examples/welcome_bot.py @@ -6,22 +6,40 @@ to make it only work for specific messages in a specific chat. from pyrogram import Client, Emoji, Filters -MENTION = "[{}](tg://user?id={})" -MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {}!" +USER = "**{}**" +MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {{}}!".format(Emoji.SPARKLES) + +enabled_groups = Filters.chat("PyrogramChat") +last_welcomes = {} app = Client("my_account") -@app.on_message(Filters.chat("PyrogramChat") & Filters.new_chat_members) +@app.on_message(enabled_groups & Filters.new_chat_members) def welcome(client, message): - # Build the new members list (with mentions) by using their first_name - new_members = [MENTION.format(i.first_name, i.id) for i in message.new_chat_members] + chat_id = message.chat.id - # Build the welcome message by using an emoji and the list we built above - text = MESSAGE.format(Emoji.SPARKLES, ", ".join(new_members)) + # Get the previous welcome message and members, if any + previous_welcome, previous_members = last_welcomes.pop(chat_id, (None, [])) - # Send the welcome message - message.reply(text, disable_web_page_preview=True) + # Delete the previous message, if exists + if previous_welcome: + previous_welcome.delete() + + # Build the new members list by using their first_name. Also append the previous members, if any + new_members = [USER.format(i.first_name) for i in message.new_chat_members] + previous_members + + # Build the welcome message by using an emoji and the list we created above + text = MESSAGE.format(", ".join(new_members)) + + # Actually send the welcome and save the new message and the new members list + last_welcomes[message.chat.id] = message.reply(text, disable_web_page_preview=True), new_members + + +@app.on_message(enabled_groups) +def reset(client, message): + # Don't make the bot delete the previous welcome in case someone talks in the middle + last_welcomes.pop(message.chat.id, None) app.run() # Automatically start() and idle() diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 52d27829..924c5df7 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -199,10 +199,9 @@ class Client(Methods, BaseClient): self.dispatcher = Dispatcher(self, workers) def __enter__(self): - self.start() - return self + return self.start() - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__(self, *args): self.stop() @property @@ -284,6 +283,8 @@ class Client(Methods, BaseClient): mimetypes.init() + return self + async def stop(self): """Use this method to manually stop the Client. Requires no parameters. @@ -318,6 +319,8 @@ class Client(Methods, BaseClient): self.is_started = False await self.session.stop() + return self + async def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)): """Blocks the program execution until one of the signals are received, then gently stop the Client by closing the underlying connection. @@ -439,6 +442,8 @@ class Client(Methods, BaseClient): else: self.user_id = r.user.id + print("Logged in successfully as @{}".format(r.user.username)) + async def authorize_user(self): phone_number_invalid_raises = self.phone_number is not None phone_code_invalid_raises = self.phone_code is not None @@ -623,7 +628,7 @@ class Client(Methods, BaseClient): self.password = None self.user_id = r.user.id - print("Login successful") + print("Logged in successfully as {}".format(r.user.first_name)) def fetch_peers(self, entities: list): for entity in entities: @@ -1234,7 +1239,7 @@ class Client(Methods, BaseClient): version: int = 0, size: int = None, progress: callable = None, - progress_args: tuple = None) -> str: + progress_args: tuple = ()) -> str: with await self.media_sessions_lock: session = self.media_sessions.get(dc_id, None) @@ -1316,7 +1321,7 @@ class Client(Methods, BaseClient): offset += limit if progress: - progress(self, min(offset, size), size, *progress_args) + progress(self, min(offset, size) if size != 0 else offset, size, *progress_args) r = await session.send( functions.upload.GetFile( @@ -1398,7 +1403,7 @@ class Client(Methods, BaseClient): offset += limit if progress: - progress(self, min(offset, size), size, *progress_args) + progress(self, min(offset, size) if size != 0 else offset, size, *progress_args) if len(chunk) < limit: break diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index c4460f38..e687ced1 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -338,6 +338,7 @@ async def parse_messages( video_note = None sticker = None document = None + web_page = None media = message.media @@ -585,6 +586,8 @@ async def parse_messages( file_size=doc.size, date=doc.date ) + elif isinstance(media, types.MessageMediaWebPage): + web_page = True else: media = None @@ -632,6 +635,7 @@ async def parse_messages( video_note=video_note, sticker=sticker, document=document, + web_page=web_page, views=message.views, via_bot=parse_user(users.get(message.via_bot_id, None)), outgoing=message.out, diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index 6042173f..fa9eace3 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -118,6 +118,9 @@ class Filters: venue = create("Venue", lambda _, m: bool(m.venue)) """Filter messages that contain :obj:`Venue ` objects.""" + web_page = create("WebPage", lambda _, m: m.web_page) + """Filter messages sent with a webpage preview.""" + private = create("Private", lambda _, m: bool(m.chat and m.chat.type == "private")) """Filter messages sent in private chats.""" @@ -169,6 +172,9 @@ class Filters: mentioned = create("Mentioned", lambda _, m: bool(m.mentioned)) """Filter messages containing mentions""" + via_bot = create("ViaBot", lambda _, m: bool(m.via_bot)) + """Filter messages sent via inline bots""" + service = create("Service", lambda _, m: bool(m.service)) """Filter service messages. A service message contains any of the following fields set diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/client/methods/decorators/on_callback_query.py index a7079236..51a6df2e 100644 --- a/pyrogram/client/methods/decorators/on_callback_query.py +++ b/pyrogram/client/methods/decorators/on_callback_query.py @@ -27,6 +27,13 @@ class OnCallbackQuery(BaseClient): callback queries. This does the same thing as :meth:`add_handler` using the :class:`CallbackQueryHandler`. + .. note:: + This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*. + + To reference your own function after it has been decorated, you need to access + *my_function[0].callback*, that is, the *callback* field of Handler object which is the the + first element in the tuple. + Args: filters (:obj:`Filters `): Pass one or more filters to allow only a subset of callback queries to be passed diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py index 2fd8f298..c23b7594 100644 --- a/pyrogram/client/methods/decorators/on_deleted_messages.py +++ b/pyrogram/client/methods/decorators/on_deleted_messages.py @@ -27,6 +27,13 @@ class OnDeletedMessages(BaseClient): deleted messages. This does the same thing as :meth:`add_handler` using the :class:`DeletedMessagesHandler`. + .. note:: + This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*. + + To reference your own function after it has been decorated, you need to access + *my_function[0].callback*, that is, the *callback* field of Handler object which is the the + first element in the tuple. + Args: filters (:obj:`Filters `): Pass one or more filters to allow only a subset of messages to be passed diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/client/methods/decorators/on_message.py index 690f8368..a098cfa2 100644 --- a/pyrogram/client/methods/decorators/on_message.py +++ b/pyrogram/client/methods/decorators/on_message.py @@ -27,6 +27,13 @@ class OnMessage(BaseClient): messages. This does the same thing as :meth:`add_handler` using the :class:`MessageHandler`. + .. note:: + This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*. + + To reference your own function after it has been decorated, you need to access + *my_function[0].callback*, that is, the *callback* field of Handler object which is the the + first element in the tuple. + Args: filters (:obj:`Filters `): Pass one or more filters to allow only a subset of messages to be passed diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/client/methods/decorators/on_raw_update.py index 1391482f..52728e1c 100644 --- a/pyrogram/client/methods/decorators/on_raw_update.py +++ b/pyrogram/client/methods/decorators/on_raw_update.py @@ -26,6 +26,13 @@ class OnRawUpdate(BaseClient): raw updates. This does the same thing as :meth:`add_handler` using the :class:`RawUpdateHandler`. + .. note:: + This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*. + + To reference your own function after it has been decorated, you need to access + *my_function[0].callback*, that is, the *callback* field of Handler object which is the the + first element in the tuple. + Args: group (``int``, *optional*): The group identifier, defaults to 0. diff --git a/pyrogram/client/methods/decorators/on_user_status.py b/pyrogram/client/methods/decorators/on_user_status.py index 5aa6f783..2ca41e56 100644 --- a/pyrogram/client/methods/decorators/on_user_status.py +++ b/pyrogram/client/methods/decorators/on_user_status.py @@ -27,6 +27,13 @@ class OnUserStatus(BaseClient): user status updates. This does the same thing as :meth:`add_handler` using the :class:`UserStatusHandler`. + .. note:: + This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*. + + To reference your own function after it has been decorated, you need to access + *my_function[0].callback*, that is, the *callback* field of Handler object which is the the + first element in the tuple. + Args: filters (:obj:`Filters `): Pass one or more filters to allow only a subset of UserStatus updated to be passed in your function. diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py index 35cc6e87..0f045277 100644 --- a/pyrogram/client/methods/messages/send_media_group.py +++ b/pyrogram/client/methods/messages/send_media_group.py @@ -108,6 +108,7 @@ class SendMediaGroup(BaseClient): peer=await self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( file=await self.save_file(i.media), + thumb=None if i.thumb is None else self.save_file(i.thumb), mime_type=mimetypes.types_map[".mp4"], attributes=[ types.DocumentAttributeVideo( diff --git a/pyrogram/client/methods/utilities/download_media.py b/pyrogram/client/methods/utilities/download_media.py index 5eebdab6..f532c84a 100644 --- a/pyrogram/client/methods/utilities/download_media.py +++ b/pyrogram/client/methods/utilities/download_media.py @@ -28,7 +28,7 @@ class DownloadMedia(BaseClient): file_name: str = "", block: bool = True, progress: callable = None, - progress_args: tuple = None): + progress_args: tuple = ()): """Use this method to download the media from a Message. Args: diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 96f9c7c3..3ace38bc 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -134,6 +134,12 @@ class Message(Object): venue (:obj:`Venue `, *optional*): Message is a venue, information about the venue. + web_page (``bool``, *optional*): + Message was sent with a webpage preview. + **Note:** Support for web pages is still basic; a simple boolean is set in case the message contains a + web page preview. In future versions this property could turn into a full web page object that contains + more details. + new_chat_members (List of :obj:`User `, *optional*): New members that were added to the group or supergroup and information about them (the bot itself may be one of these members). @@ -246,6 +252,7 @@ class Message(Object): contact=None, location=None, venue=None, + web_page=None, new_chat_members: list = None, left_chat_member=None, new_chat_title: str = None, @@ -297,6 +304,7 @@ class Message(Object): self.contact = contact # flags.22?Contact self.location = location # flags.23?Location self.venue = venue # flags.24?Venue + self.web_page = web_page self.new_chat_members = new_chat_members # flags.25?Vector self.left_chat_member = left_chat_member # flags.26?User self.new_chat_title = new_chat_title # flags.27?string