2
0
mirror of https://github.com/pyrogram/pyrogram synced 2025-08-29 13:27:47 +00:00

Merge branch 'develop'

This commit is contained in:
Dan 2018-11-13 13:17:33 +01:00
commit c3d8fbc441
13 changed files with 252 additions and 218 deletions

View File

@ -2,3 +2,4 @@ id message
CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat
RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup) RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup)
CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users
MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat
1 id message
2 CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat
3 RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup)
4 CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users
5 MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat

View File

@ -23,7 +23,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8" "e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
) )
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)" __license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__version__ = "0.9.1" __version__ = "0.9.2"
from .api.errors import Error from .api.errors import Error
from .client.types import ( from .client.types import (

View File

@ -22,10 +22,9 @@ from collections import OrderedDict
from queue import Queue from queue import Queue
from threading import Thread from threading import Thread
import pyrogram
from pyrogram.api import types from pyrogram.api import types
from ..ext import utils from ..ext import utils
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler from ..handlers import CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler, RawUpdateHandler
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -46,15 +45,39 @@ class Dispatcher:
types.UpdateDeleteChannelMessages types.UpdateDeleteChannelMessages
) )
CALLBACK_QUERY_UPDATES = (
types.UpdateBotCallbackQuery,
types.UpdateInlineBotCallbackQuery
)
MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES
def __init__(self, client, workers): UPDATES = None
def __init__(self, client, workers: int):
self.client = client self.client = client
self.workers = workers self.workers = workers
self.workers_list = [] self.workers_list = []
self.updates = Queue() self.updates = Queue()
self.groups = OrderedDict() self.groups = OrderedDict()
Dispatcher.UPDATES = {
Dispatcher.MESSAGE_UPDATES:
lambda upd, usr, cht: (utils.parse_messages(self.client, upd.message, usr, cht), MessageHandler),
Dispatcher.DELETE_MESSAGE_UPDATES:
lambda upd, usr, cht: (utils.parse_deleted_messages(upd), DeletedMessagesHandler),
Dispatcher.CALLBACK_QUERY_UPDATES:
lambda upd, usr, cht: (utils.parse_callback_query(self.client, upd, usr), CallbackQueryHandler),
(types.UpdateUserStatus,):
lambda upd, usr, cht: (utils.parse_user_status(upd.status, upd.user_id), UserStatusHandler)
}
Dispatcher.UPDATES = {key: value for key_tuple, value in Dispatcher.UPDATES.items() for key in key_tuple}
def start(self): def start(self):
for i in range(self.workers): for i in range(self.workers):
self.workers_list.append( self.workers_list.append(
@ -70,8 +93,8 @@ class Dispatcher:
for _ in range(self.workers): for _ in range(self.workers):
self.updates.put(None) self.updates.put(None)
for i in self.workers_list: for worker in self.workers_list:
i.join() worker.join()
self.workers_list.clear() self.workers_list.clear()
@ -84,60 +107,10 @@ class Dispatcher:
def remove_handler(self, handler, group: int): def remove_handler(self, handler, group: int):
if group not in self.groups: if group not in self.groups:
raise ValueError("Group {} does not exist. " raise ValueError("Group {} does not exist. Handler was not removed.".format(group))
"Handler was not removed.".format(group))
self.groups[group].remove(handler) self.groups[group].remove(handler)
def dispatch(self, update, users: dict = None, chats: dict = None, is_raw: bool = False):
for group in self.groups.values():
try:
for handler in group:
if is_raw:
if not isinstance(handler, RawUpdateHandler):
continue
args = (self.client, update, users, chats)
else:
message = (update.message
or update.channel_post
or update.edited_message
or update.edited_channel_post)
deleted_messages = (update.deleted_channel_posts
or update.deleted_messages)
callback_query = update.callback_query
user_status = update.user_status
if message and isinstance(handler, MessageHandler):
if not handler.check(message):
continue
args = (self.client, message)
elif deleted_messages and isinstance(handler, DeletedMessagesHandler):
if not handler.check(deleted_messages):
continue
args = (self.client, deleted_messages)
elif callback_query and isinstance(handler, CallbackQueryHandler):
if not handler.check(callback_query):
continue
args = (self.client, callback_query)
elif user_status and isinstance(handler, UserStatusHandler):
if not handler.check(user_status):
continue
args = (self.client, user_status)
else:
continue
handler.callback(*args)
break
except Exception as e:
log.error(e, exc_info=True)
def update_worker(self): def update_worker(self):
name = threading.current_thread().name name = threading.current_thread().name
log.debug("{} started".format(name)) log.debug("{} started".format(name))
@ -153,79 +126,32 @@ class Dispatcher:
chats = {i.id: i for i in update[2]} chats = {i.id: i for i in update[2]}
update = update[0] update = update[0]
self.dispatch(update, users=users, chats=chats, is_raw=True) parser = Dispatcher.UPDATES.get(type(update), None)
if isinstance(update, Dispatcher.MESSAGE_UPDATES): if parser is None:
if isinstance(update.message, types.MessageEmpty):
continue continue
message = utils.parse_messages( update, handler_type = parser(update, users, chats)
self.client,
update.message,
users,
chats
)
is_edited_message = isinstance(update, Dispatcher.EDIT_MESSAGE_UPDATES) for group in self.groups.values():
for handler in group:
args = None
self.dispatch( if isinstance(handler, RawUpdateHandler):
pyrogram.Update( args = (update, users, chats)
message=((message if message.chat.type != "channel" elif isinstance(handler, handler_type):
else None) if not is_edited_message if handler.check(update):
else None), args = (update,)
edited_message=((message if message.chat.type != "channel"
else None) if is_edited_message
else None),
channel_post=((message if message.chat.type == "channel"
else None) if not is_edited_message
else None),
edited_channel_post=((message if message.chat.type == "channel"
else None) if is_edited_message
else None)
)
)
elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES): if args is None:
is_channel = hasattr(update, 'channel_id')
messages = utils.parse_deleted_messages(
update.messages,
(update.channel_id if is_channel else None)
)
self.dispatch(
pyrogram.Update(
deleted_messages=(messages if not is_channel else None),
deleted_channel_posts=(messages if is_channel else None)
)
)
elif isinstance(update, types.UpdateBotCallbackQuery):
self.dispatch(
pyrogram.Update(
callback_query=utils.parse_callback_query(
self.client, update, users
)
)
)
elif isinstance(update, types.UpdateInlineBotCallbackQuery):
self.dispatch(
pyrogram.Update(
callback_query=utils.parse_inline_callback_query(
self.client, update, users
)
)
)
elif isinstance(update, types.UpdateUserStatus):
self.dispatch(
pyrogram.Update(
user_status=utils.parse_user_status(
update.status, update.user_id
)
)
)
else:
continue continue
try:
handler.callback(self.client, *args)
except Exception as e:
log.error(e, exc_info=True)
finally:
break
except Exception as e: except Exception as e:
log.error(e, exc_info=True) log.error(e, exc_info=True)

View File

@ -606,6 +606,8 @@ def parse_messages(
forward_from_message_id=forward_from_message_id, forward_from_message_id=forward_from_message_id,
forward_signature=forward_signature, forward_signature=forward_signature,
forward_date=forward_date, forward_date=forward_date,
mentioned=message.mentioned,
media=bool(media) or None,
edit_date=message.edit_date, edit_date=message.edit_date,
media_group_id=message.grouped_id, media_group_id=message.grouped_id,
photo=photo, photo=photo,
@ -640,7 +642,7 @@ def parse_messages(
replies=replies - 1 replies=replies - 1
) )
except MessageIdsEmpty: except MessageIdsEmpty:
m.reply_to_message = None pass
elif isinstance(message, types.MessageService): elif isinstance(message, types.MessageService):
action = message.action action = message.action
@ -727,6 +729,7 @@ def parse_messages(
date=message.date, date=message.date,
chat=parse_chat(message, users, chats), chat=parse_chat(message, users, chats),
from_user=parse_user(users.get(message.from_id, None)), from_user=parse_user(users.get(message.from_id, None)),
service=True,
new_chat_members=new_chat_members, new_chat_members=new_chat_members,
left_chat_member=left_chat_member, left_chat_member=left_chat_member,
new_chat_title=new_chat_title, new_chat_title=new_chat_title,
@ -741,23 +744,26 @@ def parse_messages(
) )
if isinstance(action, types.MessageActionPinMessage): if isinstance(action, types.MessageActionPinMessage):
try:
m.pinned_message = client.get_messages( m.pinned_message = client.get_messages(
m.chat.id, m.chat.id,
reply_to_message_ids=message.id, reply_to_message_ids=message.id,
replies=0 replies=0
) )
except MessageIdsEmpty:
pass
else: else:
m = pyrogram_types.Message(message_id=message.id, client=proxy(client)) m = pyrogram_types.Message(message_id=message.id, client=proxy(client), empty=True)
parsed_messages.append(m) parsed_messages.append(m)
return parsed_messages if is_list else parsed_messages[0] return parsed_messages if is_list else parsed_messages[0]
def parse_deleted_messages( def parse_deleted_messages(update) -> pyrogram_types.Messages:
messages: list, messages = update.messages
channel_id: int channel_id = getattr(update, "channel_id", None)
) -> pyrogram_types.Messages:
parsed_messages = [] parsed_messages = []
for message in messages: for message in messages:
@ -864,8 +870,12 @@ def parse_profile_photos(photos):
) )
def parse_callback_query(client, callback_query, users): def parse_callback_query(client, update, users):
peer = callback_query.peer message = None
inline_message_id = None
if isinstance(update, types.UpdateBotCallbackQuery):
peer = update.peer
if isinstance(peer, types.PeerUser): if isinstance(peer, types.PeerUser):
peer_id = peer.user_id peer_id = peer.user_id
@ -874,32 +884,26 @@ def parse_callback_query(client, callback_query, users):
else: else:
peer_id = int("-100" + str(peer.channel_id)) peer_id = int("-100" + str(peer.channel_id))
return pyrogram_types.CallbackQuery( message = client.get_messages(peer_id, update.msg_id)
id=str(callback_query.query_id), elif isinstance(update, types.UpdateInlineBotCallbackQuery):
from_user=parse_user(users[callback_query.user_id]),
message=client.get_messages(peer_id, callback_query.msg_id),
chat_instance=str(callback_query.chat_instance),
data=callback_query.data.decode(),
game_short_name=callback_query.game_short_name,
client=client
)
def parse_inline_callback_query(client, callback_query, users):
return pyrogram_types.CallbackQuery(
id=str(callback_query.query_id),
from_user=parse_user(users[callback_query.user_id]),
chat_instance=str(callback_query.chat_instance),
inline_message_id = b64encode( inline_message_id = b64encode(
pack( pack(
"<iqq", "<iqq",
callback_query.msg_id.dc_id, update.msg_id.dc_id,
callback_query.msg_id.id, update.msg_id.id,
callback_query.msg_id.access_hash update.msg_id.access_hash
), ),
b"-_" b"-_"
).decode().rstrip("="), ).decode().rstrip("=")
game_short_name=callback_query.game_short_name,
return pyrogram_types.CallbackQuery(
id=str(update.query_id),
from_user=parse_user(users[update.user_id]),
message=message,
inline_message_id=inline_message_id,
chat_instance=str(update.chat_instance),
data=update.data.decode(),
game_short_name=update.game_short_name,
client=client client=client
) )

View File

@ -166,7 +166,37 @@ class Filters:
inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup)) inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
"""Filter messages containing inline keyboard markups""" """Filter messages containing inline keyboard markups"""
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162)) mentioned = create("Mentioned", lambda _, m: bool(m.mentioned))
"""Filter messages containing mentions"""
service = create("Service", lambda _, m: bool(m.service))
"""Filter service messages. 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"""
media = create("Media", lambda _, m: bool(m.media))
"""Filter media messages. A media message contains any of the following fields set
- audio
- document
- photo
- sticker
- video
- animation
- voice
- video_note
- contact
- location
- venue"""
@staticmethod @staticmethod
def command(command: str or list, def command(command: str or list,
@ -252,15 +282,16 @@ class Filters:
Args: Args:
users (``int`` | ``str`` | ``list``): users (``int`` | ``str`` | ``list``):
Pass one or more user ids/usernames to filter users. Pass one or more user ids/usernames to filter users.
For you yourself, "me" or "self" can be used as well.
Defaults to None (no users). Defaults to None (no users).
""" """
def __init__(self, users: int or str or list = None): def __init__(self, users: int or str or list = None):
users = [] if users is None else users if type(users) is list else [users] users = [] if users is None else users if type(users) is list else [users]
super().__init__( super().__init__(
{i.lower().strip("@") if type(i) is str else i for i in users} {"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in users}
if type(users) is list else if type(users) is list else
{users.lower().strip("@") if type(users) is str else users} {"me" if users in ["me", "self"] else users.lower().strip("@") if type(users) is str else users}
) )
def __call__(self, message): def __call__(self, message):
@ -268,7 +299,9 @@ class Filters:
message.from_user message.from_user
and (message.from_user.id in self and (message.from_user.id in self
or (message.from_user.username or (message.from_user.username
and message.from_user.username.lower() in self)) and message.from_user.username.lower() in self)
or ("me" in self
and message.from_user.is_self))
) )
# noinspection PyPep8Naming # noinspection PyPep8Naming
@ -281,15 +314,16 @@ class Filters:
Args: Args:
chats (``int`` | ``str`` | ``list``): chats (``int`` | ``str`` | ``list``):
Pass one or more chat ids/usernames to filter chats. Pass one or more chat ids/usernames to filter chats.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
Defaults to None (no chats). Defaults to None (no chats).
""" """
def __init__(self, chats: int or str or list = None): def __init__(self, chats: int or str or list = None):
chats = [] if chats is None else chats if type(chats) is list else [chats] chats = [] if chats is None else chats if type(chats) is list else [chats]
super().__init__( super().__init__(
{i.lower().strip("@") if type(i) is str else i for i in chats} {"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in chats}
if type(chats) is list else if type(chats) is list else
{chats.lower().strip("@") if type(chats) is str else chats} {"me" if chats in ["me", "self"] else chats.lower().strip("@") if type(chats) is str else chats}
) )
def __call__(self, message): def __call__(self, message):
@ -297,41 +331,10 @@ class Filters:
message.chat message.chat
and (message.chat.id in self and (message.chat.id in self
or (message.chat.username or (message.chat.username
and message.chat.username.lower() in self)) and message.chat.username.lower() in self)
or ("me" in self and message.from_user
and message.from_user.is_self
and not message.outgoing))
) )
service = create( dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))
"Service",
lambda _, m: bool(
Filters.new_chat_members(m)
or Filters.left_chat_member(m)
or Filters.new_chat_title(m)
or Filters.new_chat_photo(m)
or Filters.delete_chat_photo(m)
or Filters.group_chat_created(m)
or Filters.supergroup_chat_created(m)
or Filters.channel_chat_created(m)
or Filters.migrate_to_chat_id(m)
or Filters.migrate_from_chat_id(m)
or Filters.pinned_message(m)
)
)
"""Filter all service messages."""
media = create(
"Media",
lambda _, m: bool(
Filters.audio(m)
or Filters.document(m)
or Filters.photo(m)
or Filters.sticker(m)
or Filters.video(m)
or Filters.animation(m)
or Filters.voice(m)
or Filters.video_note(m)
or Filters.contact(m)
or Filters.location(m)
or Filters.venue(m)
)
)
"""Filter all media messages."""

View File

@ -22,7 +22,7 @@ from ...ext import BaseClient
class OnCallbackQuery(BaseClient): class OnCallbackQuery(BaseClient):
def on_callback_query(self, filters=None, group: int = 0): def on_callback_query(self=None, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling """Use this decorator to automatically register a function for handling
callback queries. This does the same thing as :meth:`add_handler` using the callback queries. This does the same thing as :meth:`add_handler` using the
:class:`CallbackQueryHandler`. :class:`CallbackQueryHandler`.
@ -37,6 +37,9 @@ class OnCallbackQuery(BaseClient):
""" """
def decorator(func): def decorator(func):
if isinstance(func, tuple):
func = func[0].callback
handler = pyrogram.CallbackQueryHandler(func, filters) handler = pyrogram.CallbackQueryHandler(func, filters)
if isinstance(self, Filter): if isinstance(self, Filter):

View File

@ -22,7 +22,7 @@ from ...ext import BaseClient
class OnDeletedMessages(BaseClient): class OnDeletedMessages(BaseClient):
def on_deleted_messages(self, filters=None, group: int = 0): def on_deleted_messages(self=None, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling """Use this decorator to automatically register a function for handling
deleted messages. This does the same thing as :meth:`add_handler` using the deleted messages. This does the same thing as :meth:`add_handler` using the
:class:`DeletedMessagesHandler`. :class:`DeletedMessagesHandler`.
@ -37,6 +37,9 @@ class OnDeletedMessages(BaseClient):
""" """
def decorator(func): def decorator(func):
if isinstance(func, tuple):
func = func[0].callback
handler = pyrogram.DeletedMessagesHandler(func, filters) handler = pyrogram.DeletedMessagesHandler(func, filters)
if isinstance(self, Filter): if isinstance(self, Filter):

View File

@ -21,7 +21,7 @@ from ...ext import BaseClient
class OnDisconnect(BaseClient): class OnDisconnect(BaseClient):
def on_disconnect(self): def on_disconnect(self=None):
"""Use this decorator to automatically register a function for handling """Use this decorator to automatically register a function for handling
disconnections. This does the same thing as :meth:`add_handler` using the disconnections. This does the same thing as :meth:`add_handler` using the
:class:`DisconnectHandler`. :class:`DisconnectHandler`.

View File

@ -37,6 +37,9 @@ class OnMessage(BaseClient):
""" """
def decorator(func): def decorator(func):
if isinstance(func, tuple):
func = func[0].callback
handler = pyrogram.MessageHandler(func, filters) handler = pyrogram.MessageHandler(func, filters)
if isinstance(self, Filter): if isinstance(self, Filter):

View File

@ -32,6 +32,9 @@ class OnRawUpdate(BaseClient):
""" """
def decorator(func): def decorator(func):
if isinstance(func, tuple):
func = func[0].callback
handler = pyrogram.RawUpdateHandler(func) handler = pyrogram.RawUpdateHandler(func)
if isinstance(self, int): if isinstance(self, int):

View File

@ -36,6 +36,9 @@ class OnUserStatus(BaseClient):
""" """
def decorator(func): def decorator(func):
if isinstance(func, tuple):
func = func[0].callback
handler = pyrogram.UserStatusHandler(func, filters) handler = pyrogram.UserStatusHandler(func, filters)
if isinstance(self, Filter): if isinstance(self, Filter):

View File

@ -55,6 +55,24 @@ class Message(Object):
For replies, the original message. Note that the Message object in this field will not contain For replies, the original message. Note that the Message object in this field will not contain
further reply_to_message fields even if it itself is a reply. further reply_to_message fields even if it itself is a reply.
mentioned (``bool``, *optional*):
The message contains a mention.
empty (``bool``, *optional*):
The message is empty.
A message can be empty in case it was deleted or you tried to retrieve a message that doesn't exist yet.
service (``bool``, *optional*):
The message is a service message.
A service message has one and only one of these 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.
media (``bool``` *optional*):
The message is a media message.
A media message has one and only one of these fields set: audio, document, photo, sticker, video, animation,
voice, video_note, contact, location, venue.
edit_date (``int``, *optional*): edit_date (``int``, *optional*):
Date the message was last edited in Unix time. Date the message was last edited in Unix time.
@ -206,6 +224,10 @@ class Message(Object):
forward_signature: str = None, forward_signature: str = None,
forward_date: int = None, forward_date: int = None,
reply_to_message=None, reply_to_message=None,
mentioned=None,
empty=None,
service=None,
media=None,
edit_date: int = None, edit_date: int = None,
media_group_id: str = None, media_group_id: str = None,
author_signature: str = None, author_signature: str = None,
@ -253,6 +275,10 @@ class Message(Object):
self.forward_signature = forward_signature # flags.4?string self.forward_signature = forward_signature # flags.4?string
self.forward_date = forward_date # flags.5?int self.forward_date = forward_date # flags.5?int
self.reply_to_message = reply_to_message # flags.6?Message self.reply_to_message = reply_to_message # flags.6?Message
self.mentioned = mentioned
self.empty = empty
self.service = service
self.media = media
self.edit_date = edit_date # flags.7?int self.edit_date = edit_date # flags.7?int
self.media_group_id = media_group_id # flags.8?string self.media_group_id = media_group_id # flags.8?string
self.author_signature = author_signature # flags.9?string self.author_signature = author_signature # flags.9?string
@ -364,6 +390,54 @@ class Message(Object):
reply_markup=reply_markup reply_markup=reply_markup
) )
def edit(self, text: str, parse_mode: str = "", disable_web_page_preview: bool = None, reply_markup=None):
"""Bound method *edit* of :obj:`Message <pyrogram.Message>
Use as a shortcut for:
.. code-block:: python
client.edit_message_text(
chat_id=message.chat.id,
message_id=message.message_id,
text="hello",
)
Example:
.. code-block:: python
message.edit("hello")
Args:
text (``str``):
New text of the message.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
Defaults to Markdown.
disable_web_page_preview (``bool``, *optional*):
Disables link previews for links in this message.
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
An InlineKeyboardMarkup object.
Returns:
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return self._client.edit_message_text(
chat_id=self.chat.id,
message_id=self.message_id,
text=text,
parse_mode=parse_mode,
disable_web_page_preview=disable_web_page_preview,
reply_markup=reply_markup
)
def forward(self, def forward(self,
chat_id: int or str, chat_id: int or str,
disable_notification: bool = None): disable_notification: bool = None):
@ -560,7 +634,7 @@ class Message(Object):
else: else:
raise ValueError("The message doesn't contain any keyboard") raise ValueError("The message doesn't contain any keyboard")
def download(self, file_name: str = "", block: bool = True): def download(self, file_name: str = "", block: bool = True, progress: callable = None, progress_args: tuple = None):
"""Bound method *download* of :obj:`Message <pyrogram.Message>`. """Bound method *download* of :obj:`Message <pyrogram.Message>`.
Use as a shortcut for: Use as a shortcut for:
@ -585,6 +659,15 @@ class Message(Object):
Blocks the code execution until the file has been downloaded. Blocks the code execution until the file has been downloaded.
Defaults to True. Defaults to True.
progress (``callable``):
Pass a callback function to view the download progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
below for a detailed description).
progress_args (``tuple``):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass
a chat_id and a message_id in order to edit a message with the updated progress.
Returns: Returns:
On success, the absolute path of the downloaded file as string is returned, None otherwise. On success, the absolute path of the downloaded file as string is returned, None otherwise.
@ -595,5 +678,7 @@ class Message(Object):
return self._client.download_media( return self._client.download_media(
message=self, message=self,
file_name=file_name, file_name=file_name,
block=block block=block,
progress=progress,
progress_args=progress_args,
) )

View File

@ -37,7 +37,7 @@ class Connection:
4: TCPIntermediateO 4: TCPIntermediateO
} }
def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 1): def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 3):
self.dc_id = dc_id self.dc_id = dc_id
self.ipv6 = ipv6 self.ipv6 = ipv6
self.proxy = proxy self.proxy = proxy