Merge branch 'develop' into asyncio

# Conflicts:
#	pyrogram/client/client.py
#	pyrogram/client/dispatcher/dispatcher.py
#	pyrogram/client/ext/utils.py
#	pyrogram/client/methods/bots/get_inline_bot_results.py
#	pyrogram/client/methods/bots/request_callback_answer.py
#	pyrogram/client/methods/bots/send_inline_bot_result.py
#	pyrogram/client/methods/chats/delete_chat_photo.py
#	pyrogram/client/methods/chats/export_chat_invite_link.py
#	pyrogram/client/methods/chats/get_chat.py
#	pyrogram/client/methods/chats/get_chat_member.py
#	pyrogram/client/methods/chats/get_chat_members.py
#	pyrogram/client/methods/chats/get_chat_members_count.py
#	pyrogram/client/methods/chats/get_dialogs.py
#	pyrogram/client/methods/chats/join_chat.py
#	pyrogram/client/methods/chats/kick_chat_member.py
#	pyrogram/client/methods/chats/leave_chat.py
#	pyrogram/client/methods/chats/pin_chat_message.py
#	pyrogram/client/methods/chats/promote_chat_member.py
#	pyrogram/client/methods/chats/restrict_chat_member.py
#	pyrogram/client/methods/chats/set_chat_description.py
#	pyrogram/client/methods/chats/set_chat_photo.py
#	pyrogram/client/methods/chats/set_chat_title.py
#	pyrogram/client/methods/chats/unban_chat_member.py
#	pyrogram/client/methods/chats/unpin_chat_message.py
#	pyrogram/client/methods/contacts/add_contacts.py
#	pyrogram/client/methods/contacts/delete_contacts.py
#	pyrogram/client/methods/messages/delete_messages.py
#	pyrogram/client/methods/messages/edit_message_caption.py
#	pyrogram/client/methods/messages/edit_message_media.py
#	pyrogram/client/methods/messages/edit_message_reply_markup.py
#	pyrogram/client/methods/messages/edit_message_text.py
#	pyrogram/client/methods/messages/forward_messages.py
#	pyrogram/client/methods/messages/get_history.py
#	pyrogram/client/methods/messages/get_messages.py
#	pyrogram/client/methods/messages/send_animation.py
#	pyrogram/client/methods/messages/send_audio.py
#	pyrogram/client/methods/messages/send_chat_action.py
#	pyrogram/client/methods/messages/send_contact.py
#	pyrogram/client/methods/messages/send_document.py
#	pyrogram/client/methods/messages/send_location.py
#	pyrogram/client/methods/messages/send_media_group.py
#	pyrogram/client/methods/messages/send_message.py
#	pyrogram/client/methods/messages/send_photo.py
#	pyrogram/client/methods/messages/send_sticker.py
#	pyrogram/client/methods/messages/send_venue.py
#	pyrogram/client/methods/messages/send_video.py
#	pyrogram/client/methods/messages/send_video_note.py
#	pyrogram/client/methods/messages/send_voice.py
#	pyrogram/client/methods/password/change_cloud_password.py
#	pyrogram/client/methods/password/enable_cloud_password.py
#	pyrogram/client/methods/password/remove_cloud_password.py
#	pyrogram/client/methods/users/delete_user_profile_photos.py
#	pyrogram/client/methods/users/get_me.py
#	pyrogram/client/methods/users/get_user_profile_photos.py
#	pyrogram/client/methods/users/get_users.py
#	pyrogram/client/methods/utilities/download_media.py
#	pyrogram/client/types/messages_and_media/message.py
This commit is contained in:
Dan 2018-12-22 12:23:08 +01:00
commit e6667be10b
102 changed files with 2137 additions and 1956 deletions

View file

@ -475,39 +475,6 @@ def start():
f.write("\n 0x3072cfa1: \"pyrogram.api.core.GzipPacked\",") f.write("\n 0x3072cfa1: \"pyrogram.api.core.GzipPacked\",")
f.write("\n 0x5bb8e511: \"pyrogram.api.core.Message\",") f.write("\n 0x5bb8e511: \"pyrogram.api.core.Message\",")
f.write("\n 0xb0700000: \"pyrogram.client.types.Update\",")
f.write("\n 0xb0700001: \"pyrogram.client.types.User\",")
f.write("\n 0xb0700002: \"pyrogram.client.types.Chat\",")
f.write("\n 0xb0700003: \"pyrogram.client.types.Message\",")
f.write("\n 0xb0700004: \"pyrogram.client.types.MessageEntity\",")
f.write("\n 0xb0700005: \"pyrogram.client.types.PhotoSize\",")
f.write("\n 0xb0700006: \"pyrogram.client.types.Audio\",")
f.write("\n 0xb0700007: \"pyrogram.client.types.Document\",")
f.write("\n 0xb0700008: \"pyrogram.client.types.Video\",")
f.write("\n 0xb0700009: \"pyrogram.client.types.Voice\",")
f.write("\n 0xb0700010: \"pyrogram.client.types.VideoNote\",")
f.write("\n 0xb0700011: \"pyrogram.client.types.Contact\",")
f.write("\n 0xb0700012: \"pyrogram.client.types.Location\",")
f.write("\n 0xb0700013: \"pyrogram.client.types.Venue\",")
f.write("\n 0xb0700014: \"pyrogram.client.types.UserProfilePhotos\",")
f.write("\n 0xb0700015: \"pyrogram.client.types.ChatPhoto\",")
f.write("\n 0xb0700016: \"pyrogram.client.types.ChatMember\",")
f.write("\n 0xb0700017: \"pyrogram.client.types.Sticker\",")
f.write("\n 0xb0700018: \"pyrogram.client.types.bots.ForceReply\",")
f.write("\n 0xb0700019: \"pyrogram.client.types.bots.InlineKeyboardButton\",")
f.write("\n 0xb0700020: \"pyrogram.client.types.bots.InlineKeyboardMarkup\",")
f.write("\n 0xb0700021: \"pyrogram.client.types.bots.KeyboardButton\",")
f.write("\n 0xb0700022: \"pyrogram.client.types.bots.ReplyKeyboardMarkup\",")
f.write("\n 0xb0700023: \"pyrogram.client.types.bots.ReplyKeyboardRemove\",")
f.write("\n 0xb0700024: \"pyrogram.client.types.CallbackQuery\",")
f.write("\n 0xb0700025: \"pyrogram.client.types.Animation\",")
f.write("\n 0xb0700026: \"pyrogram.client.types.Messages\",")
f.write("\n 0xb0700027: \"pyrogram.client.types.Photo\",")
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")
f.write("\n 0xb0700029: \"pyrogram.client.types.Dialogs\",")
f.write("\n 0xb0700030: \"pyrogram.client.types.ChatMembers\",")
f.write("\n 0xb0700031: \"pyrogram.client.types.UserStatus\"")
f.write("\n}\n") f.write("\n}\n")
for k, v in namespaces.items(): for k, v in namespaces.items():

View file

@ -37,7 +37,7 @@ from .api.errors import Error
from .client.types import ( from .client.types import (
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto, Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact, InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, UserStatus, Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, User, UserStatus,
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply, UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
) )

View file

@ -36,6 +36,7 @@ from hashlib import sha256, md5
from importlib import import_module from importlib import import_module
from pathlib import Path from pathlib import Path
from signal import signal, SIGINT, SIGTERM, SIGABRT from signal import signal, SIGINT, SIGTERM, SIGABRT
from typing import Union, List
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.core import Object from pyrogram.api.core import Object
@ -44,8 +45,7 @@ from pyrogram.api.errors import (
PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty, PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty,
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded, PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned, PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate) VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied)
from pyrogram.client.handlers import DisconnectHandler
from pyrogram.client.handlers.handler import Handler from pyrogram.client.handlers.handler import Handler
from pyrogram.crypto import AES from pyrogram.crypto import AES
from pyrogram.session import Auth, Session from pyrogram.session import Auth, Session
@ -153,7 +153,7 @@ class Client(Methods, BaseClient):
def __init__(self, def __init__(self,
session_name: str, session_name: str,
api_id: int or str = None, api_id: Union[int, str] = None,
api_hash: str = None, api_hash: str = None,
app_version: str = None, app_version: str = None,
device_model: str = None, device_model: str = None,
@ -163,7 +163,7 @@ class Client(Methods, BaseClient):
proxy: dict = None, proxy: dict = None,
test_mode: bool = False, test_mode: bool = False,
phone_number: str = None, phone_number: str = None,
phone_code: str or callable = None, phone_code: Union[str, callable] = None,
password: str = None, password: str = None,
force_sms: bool = False, force_sms: bool = False,
first_name: str = None, first_name: str = None,
@ -372,7 +372,7 @@ class Client(Methods, BaseClient):
return coroutine return coroutine
def add_handler(self, handler, group: int = 0): def add_handler(self, handler: Handler, group: int = 0):
"""Use this method to register an update handler. """Use this method to register an update handler.
You can register multiple handlers, but at most one handler within a group You can register multiple handlers, but at most one handler within a group
@ -396,7 +396,7 @@ class Client(Methods, BaseClient):
return handler, group return handler, group
def remove_handler(self, handler, group: int = 0): def remove_handler(self, handler: Handler, group: int = 0):
"""Removes a previously-added update handler. """Removes a previously-added update handler.
Make sure to provide the right group that the handler was added in. You can use Make sure to provide the right group that the handler was added in. You can use
@ -534,16 +534,8 @@ class Client(Methods, BaseClient):
try: try:
if phone_registered: if phone_registered:
r = await self.send(
functions.auth.SignIn(
self.phone_number,
phone_code_hash,
self.phone_code
)
)
else:
try: try:
await self.send( r = await self.send(
functions.auth.SignIn( functions.auth.SignIn(
self.phone_number, self.phone_number,
phone_code_hash, phone_code_hash,
@ -551,20 +543,27 @@ class Client(Methods, BaseClient):
) )
) )
except PhoneNumberUnoccupied: except PhoneNumberUnoccupied:
pass log.warning("Phone number unregistered")
phone_registered = False
continue
else:
self.first_name = self.first_name if self.first_name is not None else input("First name: ")
self.last_name = self.last_name if self.last_name is not None else input("Last name: ")
self.first_name = self.first_name if self.first_name is not None else await ainput("First name: ") try:
self.last_name = self.last_name if self.last_name is not None else await ainput("Last name: ") r = await self.send(
functions.auth.SignUp(
r = await self.send( self.phone_number,
functions.auth.SignUp( phone_code_hash,
self.phone_number, self.phone_code,
phone_code_hash, self.first_name,
self.phone_code, self.last_name
self.first_name, )
self.last_name
) )
) except PhoneNumberOccupied:
log.warning("Phone number already registered")
phone_registered = True
continue
except (PhoneCodeInvalid, PhoneCodeEmpty, PhoneCodeExpired, PhoneCodeHashEmpty) as e: except (PhoneCodeInvalid, PhoneCodeEmpty, PhoneCodeExpired, PhoneCodeHashEmpty) as e:
if phone_code_invalid_raises: if phone_code_invalid_raises:
raise raise
@ -630,7 +629,9 @@ class Client(Methods, BaseClient):
print("Logged in successfully as {}".format(r.user.first_name)) print("Logged in successfully as {}".format(r.user.first_name))
def fetch_peers(self, entities: list): def fetch_peers(self, entities: List[Union[types.User,
types.Chat, types.ChatForbidden,
types.Channel, types.ChannelForbidden]]):
for entity in entities: for entity in entities:
if isinstance(entity, types.User): if isinstance(entity, types.User):
user_id = entity.id user_id = entity.id
@ -886,7 +887,10 @@ class Client(Methods, BaseClient):
log.info("UpdatesWorkerTask stopped") log.info("UpdatesWorkerTask stopped")
async def send(self, data: Object, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT): async def send(self,
data: Object,
retries: int = Session.MAX_RETRIES,
timeout: float = Session.WAIT_TIMEOUT):
"""Use this method to send Raw Function queries. """Use this method to send Raw Function queries.
This method makes possible to manually call every single Telegram API method in a low-level manner. This method makes possible to manually call every single Telegram API method in a low-level manner.
@ -1045,7 +1049,8 @@ class Client(Methods, BaseClient):
indent=4 indent=4
) )
async def get_initial_dialogs_chunk(self, offset_date: int = 0): async def get_initial_dialogs_chunk(self,
offset_date: int = 0):
while True: while True:
try: try:
r = await self.send( r = await self.send(
@ -1077,7 +1082,8 @@ class Client(Methods, BaseClient):
await self.get_initial_dialogs_chunk() await self.get_initial_dialogs_chunk()
async def resolve_peer(self, peer_id: int or str): async def resolve_peer(self,
peer_id: Union[int, str]):
"""Use this method to get the InputPeer of a known peer_id. """Use this method to get the InputPeer of a known peer_id.
This is a utility method intended to be used only when working with Raw Functions (i.e: a Telegram API method This is a utility method intended to be used only when working with Raw Functions (i.e: a Telegram API method
@ -1146,13 +1152,13 @@ class Client(Methods, BaseClient):
part_size = 512 * 1024 part_size = 512 * 1024
file_size = os.path.getsize(path) file_size = os.path.getsize(path)
if file_size == 0: if file_size == 0:
raise ValueError("File size equals to 0 B") raise ValueError("File size equals to 0 B")
if file_size > 1500 * 1024 * 1024: if file_size > 1500 * 1024 * 1024:
raise ValueError("Telegram doesn't support uploading files bigger than 1500 MiB") raise ValueError("Telegram doesn't support uploading files bigger than 1500 MiB")
file_total_parts = int(math.ceil(file_size / part_size)) file_total_parts = int(math.ceil(file_size / part_size))
is_big = file_size > 10 * 1024 * 1024 is_big = file_size > 10 * 1024 * 1024
is_missing_part = file_id is not None is_missing_part = file_id is not None

View file

@ -20,9 +20,9 @@ import asyncio
import logging import logging
from collections import OrderedDict from collections import OrderedDict
import pyrogram
from pyrogram.api import types from pyrogram.api import types
from ..ext import utils from ..handlers import CallbackQueryHandler, MessageHandler, RawUpdateHandler, UserStatusHandler, DeletedMessagesHandler
from ..handlers import CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler, RawUpdateHandler
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -38,7 +38,7 @@ class Dispatcher:
types.UpdateEditChannelMessage types.UpdateEditChannelMessage
) )
DELETE_MESSAGE_UPDATES = ( DELETE_MESSAGES_UPDATES = (
types.UpdateDeleteMessages, types.UpdateDeleteMessages,
types.UpdateDeleteChannelMessages types.UpdateDeleteChannelMessages
) )
@ -59,16 +59,16 @@ class Dispatcher:
self.groups = OrderedDict() self.groups = OrderedDict()
async def message_parser(update, users, chats): async def message_parser(update, users, chats):
return await utils.parse_messages(self.client, update.message, users, chats), MessageHandler return await pyrogram.Message._parse(self.client, update.message, users, chats), MessageHandler
async def deleted_messages_parser(update, users, chats): async def deleted_messages_parser(update, users, chats):
return utils.parse_deleted_messages(update), DeletedMessagesHandler return pyrogram.Messages._parse_deleted(self.client, update), DeletedMessagesHandler
async def callback_query_parser(update, users, chats): async def callback_query_parser(update, users, chats):
return await utils.parse_callback_query(self.client, update, users), CallbackQueryHandler return await pyrogram.CallbackQuery._parse(self.client, update, users), CallbackQueryHandler
async def user_status_parser(update, users, chats): async def user_status_parser(update, users, chats):
return utils.parse_user_status(update.status, update.user_id), UserStatusHandler return pyrogram.UserStatus._parse(self.client, update.status, update.user_id), UserStatusHandler
self.update_parsers = { self.update_parsers = {
Dispatcher.MESSAGE_UPDATES: message_parser, Dispatcher.MESSAGE_UPDATES: message_parser,

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import UnknownError from pyrogram.api.errors import UnknownError
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient
@ -23,7 +25,7 @@ from pyrogram.client.ext import BaseClient
class GetInlineBotResults(BaseClient): class GetInlineBotResults(BaseClient):
async def get_inline_bot_results(self, async def get_inline_bot_results(self,
bot: int or str, bot: Union[int, str],
query: str, query: str,
offset: str = "", offset: str = "",
latitude: float = None, latitude: float = None,

View file

@ -16,13 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions from pyrogram.api import functions
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient
class RequestCallbackAnswer(BaseClient): class RequestCallbackAnswer(BaseClient):
async def request_callback_answer(self, async def request_callback_answer(self,
chat_id: int or str, chat_id: Union[int, str],
message_id: int, message_id: int,
callback_data: bytes): callback_data: bytes):
"""Use this method to request a callback answer from bots. This is the equivalent of clicking an """Use this method to request a callback answer from bots. This is the equivalent of clicking an

View file

@ -16,13 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions from pyrogram.api import functions
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient
class SendInlineBotResult(BaseClient): class SendInlineBotResult(BaseClient):
async def send_inline_bot_result(self, async def send_inline_bot_result(self,
chat_id: int or str, chat_id: Union[int, str],
query_id: int, query_id: int,
result_id: str, result_id: str,
disable_notification: bool = None, disable_notification: bool = None,

View file

@ -16,12 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class DeleteChatPhoto(BaseClient): class DeleteChatPhoto(BaseClient):
async def delete_chat_photo(self, chat_id: int or str): async def delete_chat_photo(self,
chat_id: Union[int, str]) -> bool:
"""Use this method to delete a chat photo. """Use this method to delete a chat photo.
Photos can't be changed for private chats. Photos can't be changed for private chats.
You must be an administrator in the chat for this to work and must have the appropriate admin rights. You must be an administrator in the chat for this to work and must have the appropriate admin rights.

View file

@ -16,12 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class ExportChatInviteLink(BaseClient): class ExportChatInviteLink(BaseClient):
async def export_chat_invite_link(self, chat_id: int or str): async def export_chat_invite_link(self,
chat_id: Union[int, str]) -> str:
"""Use this method to generate a new invite link for a chat; any previously generated link is revoked. """Use this method to generate a new invite link for a chat; any previously generated link is revoked.
You must be an administrator in the chat for this to work and have the appropriate admin rights. You must be an administrator in the chat for this to work and have the appropriate admin rights.

View file

@ -16,12 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetChat(BaseClient): class GetChat(BaseClient):
async def get_chat(self, chat_id: int or str): async def get_chat(self,
chat_id: Union[int, str]) -> "pyrogram.Chat":
"""Use this method to get up to date information about the chat (current name of the user for """Use this method to get up to date information about the chat (current name of the user for
one-on-one conversations, current username of a user, group or channel, etc.) one-on-one conversations, current username of a user, group or channel, etc.)
@ -44,4 +48,4 @@ class GetChat(BaseClient):
else: else:
r = await self.send(functions.messages.GetFullChat(peer.chat_id)) r = await self.send(functions.messages.GetFullChat(peer.chat_id))
return await utils.parse_chat_full(self, r) return pyrogram.Chat._parse_full(self, r)

View file

@ -16,14 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types, errors from pyrogram.api import functions, types, errors
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetChatMember(BaseClient): class GetChatMember(BaseClient):
async def get_chat_member(self, async def get_chat_member(self,
chat_id: int or str, chat_id: Union[int, str],
user_id: int or str): user_id: Union[int, str]) -> "pyrogram.ChatMember":
"""Use this method to get information about one member of a chat. """Use this method to get information about one member of a chat.
Args: Args:
@ -51,7 +54,7 @@ class GetChatMember(BaseClient):
) )
) )
for member in utils.parse_chat_members(full_chat).chat_members: for member in pyrogram.ChatMembers._parse(self, full_chat).chat_members:
if member.user.id == user_id.user_id: if member.user.id == user_id.user_id:
return member return member
else: else:
@ -64,12 +67,6 @@ class GetChatMember(BaseClient):
) )
) )
return utils.parse_chat_members( return pyrogram.ChatMember._parse(self, r.participant, r.users[0])
types.channels.ChannelParticipants(
count=1,
participants=[r.participant],
users=r.users
)
).chat_members[0]
else: else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))

View file

@ -16,8 +16,11 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient, utils from ...ext import BaseClient
class Filters: class Filters:
@ -31,11 +34,11 @@ class Filters:
class GetChatMembers(BaseClient): class GetChatMembers(BaseClient):
async def get_chat_members(self, async def get_chat_members(self,
chat_id: int or str, chat_id: Union[int, str],
offset: int = 0, offset: int = 0,
limit: int = 200, limit: int = 200,
query: str = "", query: str = "",
filter: str = Filters.ALL): filter: str = Filters.ALL) -> "pyrogram.ChatMembers":
"""Use this method to get the members list of a chat. """Use this method to get the members list of a chat.
A chat can be either a basic group, a supergroup or a channel. A chat can be either a basic group, a supergroup or a channel.
@ -83,7 +86,8 @@ class GetChatMembers(BaseClient):
peer = await self.resolve_peer(chat_id) peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat): if isinstance(peer, types.InputPeerChat):
return utils.parse_chat_members( return pyrogram.ChatMembers._parse(
self,
await self.send( await self.send(
functions.messages.GetFullChat( functions.messages.GetFullChat(
peer.chat_id peer.chat_id
@ -108,7 +112,8 @@ class GetChatMembers(BaseClient):
else: else:
raise ValueError("Invalid filter \"{}\"".format(filter)) raise ValueError("Invalid filter \"{}\"".format(filter))
return utils.parse_chat_members( return pyrogram.ChatMembers._parse(
self,
await self.send( await self.send(
functions.channels.GetParticipants( functions.channels.GetParticipants(
channel=peer, channel=peer,

View file

@ -16,12 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class GetChatMembersCount(BaseClient): class GetChatMembersCount(BaseClient):
async def get_chat_members_count(self, chat_id: int or str): async def get_chat_members_count(self,
chat_id: Union[int, str]) -> int:
"""Use this method to get the number of members in a chat. """Use this method to get the number of members in a chat.
Args: Args:

View file

@ -18,31 +18,31 @@
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetDialogs(BaseClient): class GetDialogs(BaseClient):
async def get_dialogs(self, async def get_dialogs(self,
offset_dialogs=None, offset_dialog: "pyrogram.Dialog" = None,
limit: int = 100, limit: int = 100,
pinned_only: bool = False): pinned_only: bool = False) -> "pyrogram.Dialogs":
"""Use this method to get the user's dialogs """Use this method to get the user's dialogs
You can get up to 100 dialogs at once. You can get up to 100 dialogs at once.
Args: Args:
offset_dialog (:obj:`Dialog`):
Sequential Dialog of the first dialog to be returned.
Defaults to None (start from the beginning).
limit (``str``, *optional*): limit (``str``, *optional*):
Limits the number of dialogs to be retrieved. Limits the number of dialogs to be retrieved.
Defaults to 100 Defaults to 100.
pinned_only (``bool``, *optional*): pinned_only (``bool``, *optional*):
Pass True if you want to get only pinned dialogs. Pass True if you want to get only pinned dialogs.
Defaults to False. Defaults to False.
offset_dialogs (:obj:`Dialogs`):
Pass the previous dialogs object to retrieve the next dialogs chunk starting from the last dialog.
Defaults to None (start from the beginning).
Returns: Returns:
On success, a :obj:`Dialogs` object is returned. On success, a :obj:`Dialogs` object is returned.
@ -53,22 +53,9 @@ class GetDialogs(BaseClient):
if pinned_only: if pinned_only:
r = await self.send(functions.messages.GetPinnedDialogs()) r = await self.send(functions.messages.GetPinnedDialogs())
else: else:
offset_date = 0
if offset_dialogs:
for dialog in reversed(offset_dialogs.dialogs):
top_message = dialog.top_message
if top_message:
message_date = top_message.date
if message_date:
offset_date = message_date
break
r = await self.send( r = await self.send(
functions.messages.GetDialogs( functions.messages.GetDialogs(
offset_date=offset_date, offset_date=offset_dialog.top_message.date if offset_dialog else 0,
offset_id=0, offset_id=0,
offset_peer=types.InputPeerEmpty(), offset_peer=types.InputPeerEmpty(),
limit=limit, limit=limit,
@ -77,49 +64,4 @@ class GetDialogs(BaseClient):
) )
) )
users = {i.id: i for i in r.users} return pyrogram.Dialogs._parse(self, r)
chats = {i.id: i for i in r.chats}
messages = {}
for message in r.messages:
to_id = message.to_id
if isinstance(to_id, types.PeerUser):
if message.out:
chat_id = to_id.user_id
else:
chat_id = message.from_id
elif isinstance(to_id, types.PeerChat):
chat_id = -to_id.chat_id
else:
chat_id = int("-100" + str(to_id.channel_id))
messages[chat_id] = await utils.parse_messages(self, message, users, chats)
dialogs = []
for dialog in r.dialogs:
chat_id = dialog.peer
if isinstance(chat_id, types.PeerUser):
chat_id = chat_id.user_id
elif isinstance(chat_id, types.PeerChat):
chat_id = -chat_id.chat_id
else:
chat_id = int("-100" + str(chat_id.channel_id))
dialogs.append(
pyrogram.Dialog(
chat=utils.parse_dialog_chat(dialog.peer, users, chats),
top_message=messages.get(chat_id),
unread_messages_count=dialog.unread_count,
unread_mentions_count=dialog.unread_mentions_count,
unread_mark=dialog.unread_mark,
is_pinned=dialog.pinned
)
)
return pyrogram.Dialogs(
total_count=getattr(r, "count", len(r.dialogs)),
dialogs=dialogs
)

View file

@ -21,7 +21,8 @@ from ...ext import BaseClient
class JoinChat(BaseClient): class JoinChat(BaseClient):
async def join_chat(self, chat_id: str): async def join_chat(self,
chat_id: str):
"""Use this method to join a group chat or channel. """Use this method to join a group chat or channel.
Args: Args:

View file

@ -16,16 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import utils
from ...ext import BaseClient from ...ext import BaseClient
class KickChatMember(BaseClient): class KickChatMember(BaseClient):
async def kick_chat_member(self, async def kick_chat_member(self,
chat_id: int or str, chat_id: Union[int, str],
user_id: int or str, user_id: Union[int, str],
until_date: int = 0): until_date: int = 0) -> "pyrogram.Message":
"""Use this method to kick a user from a group, a supergroup or a channel. """Use this method to kick 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 In the case of supergroups and channels, the user will not be able to return to the group on their own using
invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must
@ -86,7 +88,7 @@ class KickChatMember(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,12 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class LeaveChat(BaseClient): class LeaveChat(BaseClient):
async def leave_chat(self, chat_id: int or str, delete: bool = False): async def leave_chat(self,
chat_id: Union[int, str],
delete: bool = False):
"""Use this method to leave a group chat or channel. """Use this method to leave a group chat or channel.
Args: Args:

View file

@ -16,12 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class PinChatMessage(BaseClient): class PinChatMessage(BaseClient):
async def pin_chat_message(self, chat_id: int or str, message_id: int, disable_notification: bool = None): async def pin_chat_message(self,
chat_id: Union[int, str],
message_id: int,
disable_notification: bool = None) -> bool:
"""Use this method to pin a message in a supergroup or a channel. """Use this method to pin a message in a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in
the supergroup or "can_edit_messages" admin right in the channel. the supergroup or "can_edit_messages" admin right in the channel.

View file

@ -16,14 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class PromoteChatMember(BaseClient): class PromoteChatMember(BaseClient):
async def promote_chat_member(self, async def promote_chat_member(self,
chat_id: int or str, chat_id: Union[int, str],
user_id: int or str, user_id: Union[int, str],
can_change_info: bool = True, can_change_info: bool = True,
can_post_messages: bool = False, can_post_messages: bool = False,
can_edit_messages: bool = False, can_edit_messages: bool = False,
@ -31,7 +33,7 @@ class PromoteChatMember(BaseClient):
can_invite_users: bool = True, can_invite_users: bool = True,
can_restrict_members: bool = True, can_restrict_members: bool = True,
can_pin_messages: bool = False, can_pin_messages: bool = False,
can_promote_members: bool = False): can_promote_members: bool = False) -> bool:
"""Use this method to promote or demote a user in a supergroup or a channel. """Use this method to promote or demote a user in a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the appropriate admin rights. You must be an administrator in the chat for this to work and must have the appropriate admin rights.
Pass False for all boolean parameters to demote a user. Pass False for all boolean parameters to demote a user.

View file

@ -16,19 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class RestrictChatMember(BaseClient): class RestrictChatMember(BaseClient):
async def restrict_chat_member(self, async def restrict_chat_member(self,
chat_id: int or str, chat_id: Union[int, str],
user_id: int or str, user_id: Union[int, str],
until_date: int = 0, until_date: int = 0,
can_send_messages: bool = False, can_send_messages: bool = False,
can_send_media_messages: bool = False, can_send_media_messages: bool = False,
can_send_other_messages: bool = False, can_send_other_messages: bool = False,
can_add_web_page_previews: bool = False): can_add_web_page_previews: bool = False) -> bool:
"""Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for """Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for
this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift
restrictions from a user. restrictions from a user.

View file

@ -16,12 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class SetChatDescription(BaseClient): class SetChatDescription(BaseClient):
async def set_chat_description(self, chat_id: int or str, description: str): async def set_chat_description(self,
chat_id: Union[int, str],
description: str) -> bool:
"""Use this method to change the description of a supergroup or a channel. """Use this method to change the description of a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the appropriate admin rights. You must be an administrator in the chat for this to work and must have the appropriate admin rights.

View file

@ -19,13 +19,16 @@
import os import os
from base64 import b64decode from base64 import b64decode
from struct import unpack from struct import unpack
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class SetChatPhoto(BaseClient): class SetChatPhoto(BaseClient):
async def set_chat_photo(self, chat_id: int or str, photo: str): async def set_chat_photo(self,
chat_id: Union[int, str],
photo: str) -> bool:
"""Use this method to set a new profile photo for the chat. """Use this method to set a new profile photo for the chat.
Photos can't be changed for private chats. Photos can't be changed for private chats.
You must be an administrator in the chat for this to work and must have the appropriate admin rights. You must be an administrator in the chat for this to work and must have the appropriate admin rights.

View file

@ -16,12 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class SetChatTitle(BaseClient): class SetChatTitle(BaseClient):
async def set_chat_title(self, chat_id: int or str, title: str): async def set_chat_title(self,
chat_id: Union[int, str],
title: str) -> bool:
"""Use this method to change the title of a chat. """Use this method to change the title of a chat.
Titles can't be changed for private chats. Titles can't be changed for private chats.
You must be an administrator in the chat for this to work and must have the appropriate admin rights. You must be an administrator in the chat for this to work and must have the appropriate admin rights.

View file

@ -16,14 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class UnbanChatMember(BaseClient): class UnbanChatMember(BaseClient):
async def unban_chat_member(self, async def unban_chat_member(self,
chat_id: int or str, chat_id: Union[int, str],
user_id: int or str): user_id: Union[int, str]) -> bool:
"""Use this method to unban a previously kicked user in a supergroup or channel. """Use this method to unban a previously kicked user in a supergroup or channel.
The user will **not** return to the group or channel automatically, but will be able to join via link, etc. The user will **not** return to the group or channel automatically, but will be able to join via link, etc.
You must be an administrator for this to work. You must be an administrator for this to work.

View file

@ -16,12 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class UnpinChatMessage(BaseClient): class UnpinChatMessage(BaseClient):
async def unpin_chat_message(self, chat_id: int or str): async def unpin_chat_message(self,
chat_id: Union[int, str]) -> bool:
"""Use this method to unpin a message in a supergroup or a channel. """Use this method to unpin a message in a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin
right in the supergroup or "can_edit_messages" admin right in the channel. right in the supergroup or "can_edit_messages" admin right in the channel.

View file

@ -16,17 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import List
import pyrogram
from pyrogram.api import functions from pyrogram.api import functions
from ...ext import BaseClient from ...ext import BaseClient
class AddContacts(BaseClient): class AddContacts(BaseClient):
async def add_contacts(self, contacts: list): async def add_contacts(self,
contacts: List["pyrogram.InputPhoneContact"]):
"""Use this method to add contacts to your Telegram address book. """Use this method to add contacts to your Telegram address book.
Args: Args:
contacts (``list``): contacts (List of :obj:`InputPhoneContact <pyrogram.InputPhoneContact>`):
A list of :obj:`InputPhoneContact <pyrogram.InputPhoneContact>` The contact list to be added
Returns: Returns:
On success, the added contacts are returned. On success, the added contacts are returned.

View file

@ -16,17 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import List
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import PeerIdInvalid from pyrogram.api.errors import PeerIdInvalid
from ...ext import BaseClient from ...ext import BaseClient
class DeleteContacts(BaseClient): class DeleteContacts(BaseClient):
async def delete_contacts(self, ids: list): async def delete_contacts(self,
ids: List[int]):
"""Use this method to delete contacts from your Telegram address book """Use this method to delete contacts from your Telegram address book
Args: Args:
ids (``list``): ids (List of ``int``):
A list of unique identifiers for the target users. A list of unique identifiers for the target users.
Can be an ID (int), a username (string) or phone number (string). Can be an ID (int), a username (string) or phone number (string).

View file

@ -16,13 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Tuple
import pyrogram import pyrogram
from pyrogram.client.filters.filter import Filter from pyrogram.client.filters.filter import Filter
from pyrogram.client.handlers.handler import Handler
from ...ext import BaseClient from ...ext import BaseClient
class OnCallbackQuery(BaseClient): class OnCallbackQuery(BaseClient):
def on_callback_query(self=None, filters=None, group: int = 0): def on_callback_query(self=None,
filters=None,
group: int = 0) -> callable:
"""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`.
@ -43,7 +48,7 @@ class OnCallbackQuery(BaseClient):
The group identifier, defaults to 0. The group identifier, defaults to 0.
""" """
def decorator(func): def decorator(func: callable) -> Tuple[Handler, int]:
if isinstance(func, tuple): if isinstance(func, tuple):
func = func[0].callback func = func[0].callback

View file

@ -16,13 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Tuple
import pyrogram import pyrogram
from pyrogram.client.filters.filter import Filter from pyrogram.client.filters.filter import Filter
from pyrogram.client.handlers.handler import Handler
from ...ext import BaseClient from ...ext import BaseClient
class OnDeletedMessages(BaseClient): class OnDeletedMessages(BaseClient):
def on_deleted_messages(self=None, filters=None, group: int = 0): def on_deleted_messages(self=None,
filters=None,
group: int = 0) -> callable:
"""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`.
@ -43,7 +48,7 @@ class OnDeletedMessages(BaseClient):
The group identifier, defaults to 0. The group identifier, defaults to 0.
""" """
def decorator(func): def decorator(func: callable) -> Tuple[Handler, int]:
if isinstance(func, tuple): if isinstance(func, tuple):
func = func[0].callback func = func[0].callback

View file

@ -17,17 +17,18 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram import pyrogram
from pyrogram.client.handlers.handler import Handler
from ...ext import BaseClient from ...ext import BaseClient
class OnDisconnect(BaseClient): class OnDisconnect(BaseClient):
def on_disconnect(self=None): def on_disconnect(self=None) -> callable:
"""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`.
""" """
def decorator(func): def decorator(func: callable) -> Handler:
handler = pyrogram.DisconnectHandler(func) handler = pyrogram.DisconnectHandler(func)
if self is not None: if self is not None:

View file

@ -22,7 +22,9 @@ from ...ext import BaseClient
class OnMessage(BaseClient): class OnMessage(BaseClient):
def on_message(self=None, filters=None, group: int = 0): def on_message(self=None,
filters=None,
group: int = 0) -> callable:
"""Use this decorator to automatically register a function for handling """Use this decorator to automatically register a function for handling
messages. This does the same thing as :meth:`add_handler` using the messages. This does the same thing as :meth:`add_handler` using the
:class:`MessageHandler`. :class:`MessageHandler`.

View file

@ -16,12 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Tuple
import pyrogram import pyrogram
from pyrogram.client.handlers.handler import Handler
from ...ext import BaseClient from ...ext import BaseClient
class OnRawUpdate(BaseClient): class OnRawUpdate(BaseClient):
def on_raw_update(self=None, group: int = 0): def on_raw_update(self=None,
group: int = 0) -> callable:
"""Use this decorator to automatically register a function for handling """Use this decorator to automatically register a function for handling
raw updates. This does the same thing as :meth:`add_handler` using the raw updates. This does the same thing as :meth:`add_handler` using the
:class:`RawUpdateHandler`. :class:`RawUpdateHandler`.
@ -38,7 +42,7 @@ class OnRawUpdate(BaseClient):
The group identifier, defaults to 0. The group identifier, defaults to 0.
""" """
def decorator(func): def decorator(func: callable) -> Tuple[Handler, int]:
if isinstance(func, tuple): if isinstance(func, tuple):
func = func[0].callback func = func[0].callback

View file

@ -16,13 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Tuple
import pyrogram import pyrogram
from pyrogram.client.filters.filter import Filter from pyrogram.client.filters.filter import Filter
from pyrogram.client.handlers.handler import Handler
from ...ext import BaseClient from ...ext import BaseClient
class OnUserStatus(BaseClient): class OnUserStatus(BaseClient):
def on_user_status(self=None, filters=None, group: int = 0): def on_user_status(self=None,
filters=None,
group: int = 0) -> callable:
"""Use this decorator to automatically register a function for handling """Use this decorator to automatically register a function for handling
user status updates. This does the same thing as :meth:`add_handler` using the user status updates. This does the same thing as :meth:`add_handler` using the
:class:`UserStatusHandler`. :class:`UserStatusHandler`.
@ -42,7 +47,7 @@ class OnUserStatus(BaseClient):
The group identifier, defaults to 0. The group identifier, defaults to 0.
""" """
def decorator(func): def decorator(func: callable) -> Tuple[Handler, int]:
if isinstance(func, tuple): if isinstance(func, tuple):
func = func[0].callback func = func[0].callback

View file

@ -16,15 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union, Iterable
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient
class DeleteMessages(BaseClient): class DeleteMessages(BaseClient):
async def delete_messages(self, async def delete_messages(self,
chat_id: int or str, chat_id: Union[int, str],
message_ids, message_ids: Iterable[int],
revoke: bool = True): revoke: bool = True) -> bool:
"""Use this method to delete messages, including service messages, with the following limitations: """Use this method to delete messages, including service messages, with the following limitations:
- A message can only be deleted if it was sent less than 48 hours ago. - A message can only be deleted if it was sent less than 48 hours ago.

View file

@ -16,17 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient
class EditMessageCaption(BaseClient): class EditMessageCaption(BaseClient):
async def edit_message_caption(self, async def edit_message_caption(self,
chat_id: int or str, chat_id: Union[int, str],
message_id: int, message_id: int,
caption: str, caption: str,
parse_mode: str = "", parse_mode: str = "",
reply_markup=None): reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "pyrogram.Message":
"""Use this method to edit captions of messages. """Use this method to edit captions of messages.
Args: Args:
@ -68,7 +71,7 @@ class EditMessageCaption(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid from pyrogram.api.errors import FileIdInvalid
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,14 +30,15 @@ from pyrogram.client.types import (
InputMediaPhoto, InputMediaVideo, InputMediaAudio, InputMediaPhoto, InputMediaVideo, InputMediaAudio,
InputMediaAnimation, InputMediaDocument InputMediaAnimation, InputMediaDocument
) )
from pyrogram.client.types.input_media import InputMedia
class EditMessageMedia(BaseClient): class EditMessageMedia(BaseClient):
async def edit_message_media(self, async def edit_message_media(self,
chat_id: int or str, chat_id: Union[int, str],
message_id: int, message_id: int,
media, media: InputMedia,
reply_markup=None): reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "pyrogram.Message":
"""Use this method to edit audio, document, photo, or video messages. """Use this method to edit audio, document, photo, or video messages.
If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise, If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise,
@ -333,7 +336,7 @@ class EditMessageMedia(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,15 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient
class EditMessageReplyMarkup(BaseClient): class EditMessageReplyMarkup(BaseClient):
async def edit_message_reply_markup(self, async def edit_message_reply_markup(self,
chat_id: int or str, chat_id: Union[int, str],
message_id: int, message_id: int,
reply_markup=None): reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "pyrogram.Message":
"""Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots). """Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
Args: Args:
@ -57,7 +60,7 @@ class EditMessageReplyMarkup(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,18 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient
class EditMessageText(BaseClient): class EditMessageText(BaseClient):
async def edit_message_text(self, async def edit_message_text(self,
chat_id: int or str, chat_id: Union[int, str],
message_id: int, message_id: int,
text: str, text: str,
parse_mode: str = "", parse_mode: str = "",
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
reply_markup=None): reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "pyrogram.Message":
"""Use this method to edit text messages. """Use this method to edit text messages.
Args: Args:
@ -73,7 +76,7 @@ class EditMessageText(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,16 +16,19 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union, Iterable
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient, utils from ...ext import BaseClient
class ForwardMessages(BaseClient): class ForwardMessages(BaseClient):
async def forward_messages(self, async def forward_messages(self,
chat_id: int or str, chat_id: Union[int, str],
from_chat_id: int or str, from_chat_id: Union[int, str],
message_ids, message_ids: Iterable[int],
disable_notification: bool = None): disable_notification: bool = None) -> "pyrogram.Messages":
"""Use this method to forward messages of any kind. """Use this method to forward messages of any kind.
Args: Args:
@ -48,7 +51,7 @@ class ForwardMessages(BaseClient):
Users will receive a notification with no sound. Users will receive a notification with no sound.
Returns: Returns:
On success and in case *message_ids* was a list, the returned value will be a list of the forwarded On success and in case *message_ids* was an iterable, the returned value will be a list of the forwarded
:obj:`Messages <pyrogram.Message>` even if a list contains just one element, otherwise if :obj:`Messages <pyrogram.Message>` even if a list contains just one element, otherwise if
*message_ids* was an integer, the single forwarded :obj:`Message <pyrogram.Message>` *message_ids* was an integer, the single forwarded :obj:`Message <pyrogram.Message>`
is returned. is returned.
@ -77,10 +80,14 @@ class ForwardMessages(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
messages.append( messages.append(
await utils.parse_messages( await pyrogram.Message._parse(
self, i.message, self, i.message,
users, chats users, chats
) )
) )
return messages if is_iterable else messages[0] return pyrogram.Messages(
client=self,
total_count=len(messages),
messages=messages
) if is_iterable else messages[0]

View file

@ -16,14 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram import pyrogram
from pyrogram.api import functions from pyrogram.api import functions
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetHistory(BaseClient): class GetHistory(BaseClient):
async def get_history(self, async def get_history(self,
chat_id: int or str, chat_id: Union[int, str],
offset: int = 0, offset: int = 0,
limit: int = 100, limit: int = 100,
offset_id: int = 0, offset_id: int = 0,
@ -59,52 +61,18 @@ class GetHistory(BaseClient):
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error. :class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
""" """
r = await self.send( return await pyrogram.Messages._parse(
functions.messages.GetHistory( self,
peer=await self.resolve_peer(chat_id), await self.send(
offset_id=offset_id, functions.messages.GetHistory(
offset_date=offset_date, peer=await self.resolve_peer(chat_id),
add_offset=offset, offset_id=offset_id,
limit=limit, offset_date=offset_date,
max_id=0, add_offset=offset,
min_id=0, limit=limit,
hash=0 max_id=0,
min_id=0,
hash=0
)
) )
) )
users = {i.id: i for i in r.users}
chats = {i.id: i for i in r.chats}
reply_to_messages = {
i.reply_to_msg_id: None
for i in r.messages
if i.reply_to_msg_id
}
if reply_to_messages:
temp = await self.get_messages(
chat_id, reply_to_messages,
replies=0
)
assert len(temp) == len(reply_to_messages)
for i in range(len(temp)):
reply_to_messages[temp[i].message_id] = temp[i]
messages = await utils.parse_messages(
self, r.messages,
users, chats,
replies=0
)
assert len(messages) == len(r.messages)
for i in range(len(messages)):
if r.messages[i].reply_to_msg_id:
messages[i].reply_to_message = reply_to_messages[r.messages[i].reply_to_msg_id]
return pyrogram.Messages(
total_count=getattr(r, "count", len(r.messages)),
messages=messages
)

View file

@ -16,16 +16,19 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union, Iterable
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetMessages(BaseClient): class GetMessages(BaseClient):
async def get_messages(self, async def get_messages(self,
chat_id: int or str, chat_id: Union[int, str],
message_ids: int or list = None, message_ids: Union[int, Iterable[int]] = None,
reply_to_message_ids: int or list = None, reply_to_message_ids: Union[int, Iterable[int]] = None,
replies: int = 1): replies: int = 1) -> "pyrogram.Messages":
"""Use this method to get one or more messages that belong to a specific chat. """Use this method to get one or more messages that belong to a specific chat.
You can retrieve up to 200 messages at once. You can retrieve up to 200 messages at once.
@ -48,10 +51,9 @@ class GetMessages(BaseClient):
The number of subsequent replies to get for each message. Defaults to 1. The number of subsequent replies to get for each message. Defaults to 1.
Returns: Returns:
On success and in case *message_ids* or *reply_to_message_ids* was a list, the returned value will be a On success and in case *message_ids* or *reply_to_message_ids* was an iterable, the returned value will be a
list of the requested :obj:`Messages <pyrogram.Messages>` even if a list contains just one element, :obj:`Messages <pyrogram.Messages>` even if a list contains just one element. Otherwise, if *message_ids* or
otherwise if *message_ids* or *reply_to_message_ids* was an integer, the single requested *reply_to_message_ids* was an integer, the single requested :obj:`Message <pyrogram.Message>` is returned.
:obj:`Message <pyrogram.Message>` is returned.
Raises: Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error. :class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
@ -76,13 +78,6 @@ class GetMessages(BaseClient):
else: else:
rpc = functions.messages.GetMessages(id=ids) rpc = functions.messages.GetMessages(id=ids)
r = await self.send(rpc) messages = await pyrogram.Messages._parse(self, self.send(rpc))
messages = await utils.parse_messages( return messages if is_iterable else messages.messages[0]
self, r.messages,
{i.id: i for i in r.users},
{i.id: i for i in r.chats},
replies=replies
)
return messages if is_iterable else messages[0]

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,7 +30,7 @@ from pyrogram.client.ext import BaseClient, utils
class SendAnimation(BaseClient): class SendAnimation(BaseClient):
async def send_animation(self, async def send_animation(self,
chat_id: int or str, chat_id: Union[int, str],
animation: str, animation: str,
caption: str = "", caption: str = "",
parse_mode: str = "", parse_mode: str = "",
@ -38,9 +40,12 @@ class SendAnimation(BaseClient):
thumb: str = None, thumb: str = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send animation files (animation or H.264/MPEG-4 AVC video without sound). """Use this method to send animation files (animation or H.264/MPEG-4 AVC video without sound).
Args: Args:
@ -184,7 +189,7 @@ class SendAnimation(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,18 +30,21 @@ from pyrogram.client.ext import BaseClient, utils
class SendAudio(BaseClient): class SendAudio(BaseClient):
async def send_audio(self, async def send_audio(self,
chat_id: int or str, chat_id: Union[int, str],
audio: str, audio: str,
caption: str = "", caption: str = "",
parse_mode: str = "", parse_mode: str = "",
duration: int = 0, duration: int = 0,
performer: str = None, performer: str = None,
title: str = None, title: str = None,
thumb: str = None,disable_notification: bool = None, thumb: str = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send audio files. """Use this method to send audio files.
For sending voice messages, use the :obj:`send_voice()` method instead. For sending voice messages, use the :obj:`send_voice()` method instead.
@ -183,7 +188,7 @@ class SendAudio(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,14 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from pyrogram.api import functions from pyrogram.api import functions
from pyrogram.client.ext import BaseClient, ChatAction from pyrogram.client.ext import BaseClient, ChatAction
class SendChatAction(BaseClient): class SendChatAction(BaseClient):
async def send_chat_action(self, async def send_chat_action(self,
chat_id: int or str, chat_id: Union[int, str],
action: ChatAction or str, action: Union[ChatAction, str],
progress: int = 0): progress: int = 0):
"""Use this method when you need to tell the other party that something is happening on your side. """Use this method when you need to tell the other party that something is happening on your side.

View file

@ -16,19 +16,25 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient
class SendContact(BaseClient): class SendContact(BaseClient):
async def send_contact(self, async def send_contact(self,
chat_id: int or str, chat_id: Union[int, str],
phone_number: str, phone_number: str,
first_name: str, first_name: str,
last_name: str = "", last_name: str = "",
vcard: str = "", disable_notification: bool = None, vcard: str = "", disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None): reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None) -> "pyrogram.Message":
"""Use this method to send phone contacts. """Use this method to send phone contacts.
Args: Args:
@ -85,7 +91,7 @@ class SendContact(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,15 +30,18 @@ from pyrogram.client.ext import BaseClient, utils
class SendDocument(BaseClient): class SendDocument(BaseClient):
async def send_document(self, async def send_document(self,
chat_id: int or str, chat_id: Union[int, str],
document: str, document: str,
thumb: str = None,caption: str = "", thumb: str = None, caption: str = "",
parse_mode: str = "", parse_mode: str = "",
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send general files. """Use this method to send general files.
Args: Args:
@ -164,7 +169,7 @@ class SendDocument(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,18 +16,24 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient
class SendLocation(BaseClient): class SendLocation(BaseClient):
async def send_location(self, async def send_location(self,
chat_id: int or str, chat_id: Union[int, str],
latitude: float, latitude: float,
longitude: float, longitude: float,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None): reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None) -> "pyrogram.Message":
"""Use this method to send points on the map. """Use this method to send points on the map.
Args: Args:
@ -78,7 +84,7 @@ class SendLocation(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,10 +20,11 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union, List
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid from pyrogram.api.errors import FileIdInvalid
from pyrogram.client import types as pyrogram_types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -32,8 +33,8 @@ class SendMediaGroup(BaseClient):
# TODO: Return new Message object # TODO: Return new Message object
# TODO: Figure out how to send albums using URLs # TODO: Figure out how to send albums using URLs
async def send_media_group(self, async def send_media_group(self,
chat_id: int or str, chat_id: Union[int, str],
media: list, media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]],
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None): reply_to_message_id: int = None):
"""Use this method to send a group of photos or videos as an album. """Use this method to send a group of photos or videos as an album.
@ -62,7 +63,7 @@ class SendMediaGroup(BaseClient):
for i in media: for i in media:
style = self.html if i.parse_mode.lower() == "html" else self.markdown style = self.html if i.parse_mode.lower() == "html" else self.markdown
if isinstance(i, pyrogram_types.InputMediaPhoto): if isinstance(i, pyrogram.InputMediaPhoto):
if os.path.exists(i.media): if os.path.exists(i.media):
media = await self.send( media = await self.send(
functions.messages.UploadMedia( functions.messages.UploadMedia(
@ -101,7 +102,7 @@ class SendMediaGroup(BaseClient):
access_hash=unpacked[3] access_hash=unpacked[3]
) )
) )
elif isinstance(i, pyrogram_types.InputMediaVideo): elif isinstance(i, pyrogram.InputMediaVideo):
if os.path.exists(i.media): if os.path.exists(i.media):
media = await self.send( media = await self.send(
functions.messages.UploadMedia( functions.messages.UploadMedia(

View file

@ -16,20 +16,25 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client import types as pyrogram_types from ...ext import BaseClient
from ...ext import utils, BaseClient
class SendMessage(BaseClient): class SendMessage(BaseClient):
async def send_message(self, async def send_message(self,
chat_id: int or str, chat_id: Union[int, str],
text: str, text: str,
parse_mode: str = "", parse_mode: str = "",
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None): reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None) -> "pyrogram.Message":
"""Use this method to send text messages. """Use this method to send text messages.
Args: Args:
@ -83,9 +88,13 @@ class SendMessage(BaseClient):
) )
if isinstance(r, types.UpdateShortSentMessage): if isinstance(r, types.UpdateShortSentMessage):
return pyrogram_types.Message( return pyrogram.Message(
message_id=r.id, message_id=r.id,
chat=pyrogram_types.Chat(id=list((await self.resolve_peer(chat_id)).__dict__.values())[0], type="private"), chat=pyrogram.Chat(
id=list((await self.resolve_peer(chat_id)).__dict__.values())[0],
type="private",
client=self
),
text=message, text=message,
date=r.date, date=r.date,
outgoing=r.out, outgoing=r.out,
@ -95,7 +104,7 @@ class SendMessage(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -19,7 +19,9 @@
import binascii import binascii
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -27,16 +29,19 @@ from pyrogram.client.ext import BaseClient, utils
class SendPhoto(BaseClient): class SendPhoto(BaseClient):
async def send_photo(self, async def send_photo(self,
chat_id: int or str, chat_id: Union[int, str],
photo: str, photo: str,
caption: str = "", caption: str = "",
parse_mode: str = "", parse_mode: str = "",
ttl_seconds: int = None, ttl_seconds: int = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send photos. """Use this method to send photos.
Args: Args:
@ -160,7 +165,7 @@ class SendPhoto(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -19,7 +19,9 @@
import binascii import binascii
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -27,13 +29,16 @@ from pyrogram.client.ext import BaseClient, utils
class SendSticker(BaseClient): class SendSticker(BaseClient):
async def send_sticker(self, async def send_sticker(self,
chat_id: int or str, chat_id: Union[int, str],
sticker: str, sticker: str,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send .webp stickers. """Use this method to send .webp stickers.
Args: Args:
@ -144,7 +149,7 @@ class SendSticker(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -16,21 +16,27 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient
class SendVenue(BaseClient): class SendVenue(BaseClient):
async def send_venue(self, async def send_venue(self,
chat_id: int or str, chat_id: Union[int, str],
latitude: float, latitude: float,
longitude: float, longitude: float,
title: str, title: str,
address: str, address: str,
foursquare_id: str = "", foursquare_id: str = "",
foursquare_type: str = "",disable_notification: bool = None, foursquare_type: str = "", disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None): reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None) -> "pyrogram.Message":
"""Use this method to send information about a venue. """Use this method to send information about a venue.
Args: Args:
@ -99,7 +105,7 @@ class SendVenue(BaseClient):
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,7 +30,7 @@ from pyrogram.client.ext import BaseClient, utils
class SendVideo(BaseClient): class SendVideo(BaseClient):
async def send_video(self, async def send_video(self,
chat_id: int or str, chat_id: Union[int, str],
video: str, video: str,
caption: str = "", caption: str = "",
parse_mode: str = "", parse_mode: str = "",
@ -39,9 +41,12 @@ class SendVideo(BaseClient):
supports_streaming: bool = True, supports_streaming: bool = True,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send video files. """Use this method to send video files.
Args: Args:
@ -187,7 +192,7 @@ class SendVideo(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,15 +30,18 @@ from pyrogram.client.ext import BaseClient, utils
class SendVideoNote(BaseClient): class SendVideoNote(BaseClient):
async def send_video_note(self, async def send_video_note(self,
chat_id: int or str, chat_id: Union[int, str],
video_note: str, video_note: str,
duration: int = 0, duration: int = 0,
length: int = 1, length: int = 1,
thumb: str = None,disable_notification: bool = None, thumb: str = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send video messages. """Use this method to send video messages.
Args: Args:
@ -162,7 +167,7 @@ class SendVideoNote(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -20,7 +20,9 @@ import binascii
import mimetypes import mimetypes
import os import os
import struct import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils from pyrogram.client.ext import BaseClient, utils
@ -28,16 +30,19 @@ from pyrogram.client.ext import BaseClient, utils
class SendVoice(BaseClient): class SendVoice(BaseClient):
async def send_voice(self, async def send_voice(self,
chat_id: int or str, chat_id: Union[int, str],
voice: str, voice: str,
caption: str = "", caption: str = "",
parse_mode: str = "", parse_mode: str = "",
duration: int = 0, duration: int = 0,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"] = None,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> "pyrogram.Message":
"""Use this method to send audio files. """Use this method to send audio files.
Args: Args:
@ -163,7 +168,7 @@ class SendVoice(BaseClient):
else: else:
for i in r.updates: for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return await utils.parse_messages( return await pyrogram.Message._parse(
self, i.message, self, i.message,
{i.id: i for i in r.users}, {i.id: i for i in r.users},
{i.id: i for i in r.chats} {i.id: i for i in r.chats}

View file

@ -24,7 +24,10 @@ from ...ext import BaseClient
class ChangeCloudPassword(BaseClient): class ChangeCloudPassword(BaseClient):
async def change_cloud_password(self, current_password: str, new_password: str, new_hint: str = ""): async def change_cloud_password(self,
current_password: str,
new_password: str,
new_hint: str = "") -> bool:
"""Use this method to change your Two-Step Verification password (Cloud Password) with a new one. """Use this method to change your Two-Step Verification password (Cloud Password) with a new one.
Args: Args:

View file

@ -24,7 +24,10 @@ from ...ext import BaseClient
class EnableCloudPassword(BaseClient): class EnableCloudPassword(BaseClient):
async def enable_cloud_password(self, password: str, hint: str = "", email: str = ""): async def enable_cloud_password(self,
password: str,
hint: str = "",
email: str = "") -> bool:
"""Use this method to enable the Two-Step Verification security feature (Cloud Password) on your account. """Use this method to enable the Two-Step Verification security feature (Cloud Password) on your account.
This password will be asked when you log in on a new device in addition to the SMS code. This password will be asked when you log in on a new device in addition to the SMS code.

View file

@ -23,7 +23,8 @@ from ...ext import BaseClient
class RemoveCloudPassword(BaseClient): class RemoveCloudPassword(BaseClient):
async def remove_cloud_password(self, password: str): async def remove_cloud_password(self,
password: str) -> bool:
"""Use this method to turn off the Two-Step Verification security feature (Cloud Password) on your account. """Use this method to turn off the Two-Step Verification security feature (Cloud Password) on your account.
Args: Args:

View file

@ -18,13 +18,15 @@
from base64 import b64decode from base64 import b64decode
from struct import unpack from struct import unpack
from typing import List, Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient
class DeleteUserProfilePhotos(BaseClient): class DeleteUserProfilePhotos(BaseClient):
async def delete_user_profile_photos(self, id: str or list): async def delete_user_profile_photos(self,
id: Union[str, List[str]]) -> bool:
"""Use this method to delete your own profile photos """Use this method to delete your own profile photos
Args: Args:

View file

@ -16,12 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetMe(BaseClient): class GetMe(BaseClient):
async def get_me(self): async def get_me(self) -> "pyrogram.User":
"""A simple method for testing your authorization. Requires no parameters. """A simple method for testing your authorization. Requires no parameters.
Returns: Returns:
@ -30,10 +31,11 @@ class GetMe(BaseClient):
Raises: Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error. :class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
""" """
r = await self.send( return pyrogram.User._parse(
functions.users.GetFullUser( self,
types.InputPeerSelf() await self.send(
) functions.users.GetFullUser(
types.InputPeerSelf()
)
).user
) )
return utils.parse_user(r.user)

View file

@ -16,15 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram.api import functions from pyrogram.api import functions
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetUserProfilePhotos(BaseClient): class GetUserProfilePhotos(BaseClient):
async def get_user_profile_photos(self, async def get_user_profile_photos(self,
user_id: int or str, user_id: Union[int, str],
offset: int = 0, offset: int = 0,
limit: int = 100): limit: int = 100) -> "pyrogram.UserProfilePhotos":
"""Use this method to get a list of profile pictures for a user. """Use this method to get a list of profile pictures for a user.
Args: Args:
@ -47,7 +50,8 @@ class GetUserProfilePhotos(BaseClient):
Raises: Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error. :class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
""" """
return utils.parse_profile_photos( return pyrogram.UserProfilePhotos._parse(
self,
await self.send( await self.send(
functions.photos.GetUserPhotos( functions.photos.GetUserPhotos(
user_id=await self.resolve_peer(user_id), user_id=await self.resolve_peer(user_id),

View file

@ -17,13 +17,16 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import asyncio import asyncio
from typing import Iterable, Union, List
import pyrogram
from pyrogram.api import functions from pyrogram.api import functions
from ...ext import BaseClient, utils from ...ext import BaseClient
class GetUsers(BaseClient): class GetUsers(BaseClient):
async def get_users(self, user_ids): async def get_users(self,
user_ids: Iterable[Union[int, str]]) -> Union["pyrogram.User", List["pyrogram.User"]]:
"""Use this method to get information about a user. """Use this method to get information about a user.
You can retrieve up to 200 users at once. You can retrieve up to 200 users at once.
@ -34,9 +37,9 @@ class GetUsers(BaseClient):
Iterators and Generators are also accepted. Iterators and Generators are also accepted.
Returns: Returns:
On success and in case *user_ids* was a list, the returned value will be a list of the requested On success and in case *user_ids* was an iterable, the returned value will be a list of the requested
:obj:`Users <User>` even if a list contains just one element, otherwise if :obj:`Users <User>` even if a list contains just one element, otherwise if
*user_ids* was an integer, the single requested :obj:`User` is returned. *user_ids* was an integer or string, the single requested :obj:`User` is returned.
Raises: Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error. :class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
@ -54,6 +57,6 @@ class GetUsers(BaseClient):
users = [] users = []
for i in r: for i in r:
users.append(utils.parse_user(i)) users.append(pyrogram.User._parse(self, i))
return users if is_iterable else users[0] return users if is_iterable else users[0]

View file

@ -21,7 +21,8 @@ from ...ext import BaseClient
class SetUserProfilePhoto(BaseClient): class SetUserProfilePhoto(BaseClient):
def set_user_profile_photo(self, photo: str): def set_user_profile_photo(self,
photo: str) -> bool:
"""Use this method to set a new profile photo. """Use this method to set a new profile photo.
This method only works for Users. This method only works for Users.

View file

@ -17,18 +17,19 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import asyncio import asyncio
from typing import Union
from pyrogram.client import types as pyrogram_types import pyrogram
from ...ext import BaseClient from ...ext import BaseClient
class DownloadMedia(BaseClient): class DownloadMedia(BaseClient):
async def download_media(self, async def download_media(self,
message: pyrogram_types.Message or str, message: Union["pyrogram.Message", str],
file_name: str = "", file_name: str = "",
block: bool = True, block: bool = True,
progress: callable = None, progress: callable = None,
progress_args: tuple = ()): progress_args: tuple = ()) -> Union[str, None]:
"""Use this method to download the media from a Message. """Use this method to download the media from a Message.
Args: Args:
@ -78,13 +79,14 @@ class DownloadMedia(BaseClient):
""" """
error_message = "This message doesn't contain any downloadable media" error_message = "This message doesn't contain any downloadable media"
if isinstance(message, pyrogram_types.Message): if isinstance(message, pyrogram.Message):
if message.photo: if message.photo:
media = pyrogram_types.Document( media = pyrogram.Document(
file_id=message.photo.sizes[-1].file_id, file_id=message.photo.sizes[-1].file_id,
file_size=message.photo.sizes[-1].file_size, file_size=message.photo.sizes[-1].file_size,
mime_type="", mime_type="",
date=message.photo.date date=message.photo.date,
client=self
) )
elif message.audio: elif message.audio:
media = message.audio media = message.audio
@ -103,30 +105,32 @@ class DownloadMedia(BaseClient):
else: else:
raise ValueError(error_message) raise ValueError(error_message)
elif isinstance(message, ( elif isinstance(message, (
pyrogram_types.Photo, pyrogram.Photo,
pyrogram_types.PhotoSize, pyrogram.PhotoSize,
pyrogram_types.Audio, pyrogram.Audio,
pyrogram_types.Document, pyrogram.Document,
pyrogram_types.Video, pyrogram.Video,
pyrogram_types.Voice, pyrogram.Voice,
pyrogram_types.VideoNote, pyrogram.VideoNote,
pyrogram_types.Sticker, pyrogram.Sticker,
pyrogram_types.Animation pyrogram.Animation
)): )):
if isinstance(message, pyrogram_types.Photo): if isinstance(message, pyrogram.Photo):
media = pyrogram_types.Document( media = pyrogram.Document(
file_id=message.sizes[-1].file_id, file_id=message.sizes[-1].file_id,
file_size=message.sizes[-1].file_size, file_size=message.sizes[-1].file_size,
mime_type="", mime_type="",
date=message.date date=message.date,
client=self
) )
else: else:
media = message media = message
elif isinstance(message, str): elif isinstance(message, str):
media = pyrogram_types.Document( media = pyrogram.Document(
file_id=message, file_id=message,
file_size=0, file_size=0,
mime_type="" mime_type="",
client=self
) )
else: else:
raise ValueError(error_message) raise ValueError(error_message)

View file

@ -33,7 +33,6 @@ from .messages_and_media import (
Sticker, Venue, Video, VideoNote, Voice, UserProfilePhotos, Sticker, Venue, Video, VideoNote, Voice, UserProfilePhotos,
Message, Messages, MessageEntity Message, Messages, MessageEntity
) )
from .update import Update
from .user_and_chats import ( from .user_and_chats import (
Chat, ChatMember, ChatMembers, ChatPhoto, Chat, ChatMember, ChatMembers, ChatPhoto,
Dialog, Dialogs, User, UserStatus Dialog, Dialogs, User, UserStatus

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from base64 import b64encode
from struct import pack
import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
from ..user_and_chats import User
class CallbackQuery(Object): class CallbackQuery(PyrogramType):
"""This object represents an incoming callback query from a callback button in an inline keyboard. """This object represents an incoming callback query from a callback button in an inline keyboard.
If the button that originated the query was attached to a message sent by the bot, the field message If the button that originated the query was attached to a message sent by the bot, the field message
will be present. If the button was attached to a message sent via the bot (in inline mode), will be present. If the button was attached to a message sent via the bot (in inline mode),
@ -50,27 +56,64 @@ class CallbackQuery(Object):
Short name of a Game to be returned, serves as the unique identifier for the game. Short name of a Game to be returned, serves as the unique identifier for the game.
""" """
ID = 0xb0700024
def __init__( def __init__(self,
self, *,
id: str, client: "pyrogram.client.ext.BaseClient",
from_user, id: str,
chat_instance: str, from_user: User,
client=None, chat_instance: str,
message=None, message: "pyrogram.Message" = None,
inline_message_id: str = None, inline_message_id: str = None,
data: bytes = None, data: bytes = None,
game_short_name: str = None game_short_name: str = None):
): super().__init__(client)
self._client = client
self.id = id # string self.id = id
self.from_user = from_user # User self.from_user = from_user
self.message = message # flags.0?Message self.message = message
self.inline_message_id = inline_message_id # flags.1?string self.inline_message_id = inline_message_id
self.chat_instance = chat_instance # string self.chat_instance = chat_instance
self.data = data # flags.2?string self.data = data
self.game_short_name = game_short_name # flags.3?string self.game_short_name = game_short_name
@staticmethod
def _parse(client, callback_query, users) -> "CallbackQuery":
message = None
inline_message_id = None
if isinstance(callback_query, types.UpdateBotCallbackQuery):
peer = callback_query.peer
if isinstance(peer, types.PeerUser):
peer_id = peer.user_id
elif isinstance(peer, types.PeerChat):
peer_id = -peer.chat_id
else:
peer_id = int("-100" + str(peer.channel_id))
message = client.get_messages(peer_id, callback_query.msg_id)
elif isinstance(callback_query, types.UpdateInlineBotCallbackQuery):
inline_message_id = b64encode(
pack(
"<iqq",
callback_query.msg_id.dc_id,
callback_query.msg_id.id,
callback_query.msg_id.access_hash
),
b"-_"
).decode().rstrip("=")
return CallbackQuery(
id=str(callback_query.query_id),
from_user=User._parse(client, users[callback_query.user_id]),
message=message,
inline_message_id=inline_message_id,
chat_instance=str(callback_query.chat_instance),
data=callback_query.data,
game_short_name=callback_query.game_short_name,
client=client
)
def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0): def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0):
"""Bound method *answer* of :obj:`CallbackQuery <pyrogram.CallbackQuery>`. """Bound method *answer* of :obj:`CallbackQuery <pyrogram.CallbackQuery>`.

View file

@ -16,11 +16,11 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object
from pyrogram.api.types import ReplyKeyboardForceReply from pyrogram.api.types import ReplyKeyboardForceReply
from ..pyrogram_type import PyrogramType
class ForceReply(Object): class ForceReply(PyrogramType):
"""Upon receiving a message with this object, Telegram clients will display a reply interface to the user """Upon receiving a message with this object, Telegram clients will display a reply interface to the user
(act as if the user has selected the bot's message and tapped 'Reply'). (act as if the user has selected the bot's message and tapped 'Reply').
This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to
@ -33,13 +33,14 @@ class ForceReply(Object):
2) if the bot's message is a reply (has reply_to_message_id), sender of the original message. 2) if the bot's message is a reply (has reply_to_message_id), sender of the original message.
""" """
ID = 0xb0700018 def __init__(self,
selective: bool = None):
super().__init__(None)
def __init__(self, selective: bool = None):
self.selective = selective self.selective = selective
@staticmethod @staticmethod
def read(o, *args): def read(o):
return ForceReply( return ForceReply(
selective=o.selective selective=o.selective
) )

View file

@ -16,15 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object
from pyrogram.api.types import ( from pyrogram.api.types import (
KeyboardButtonUrl, KeyboardButtonCallback, KeyboardButtonUrl, KeyboardButtonCallback,
KeyboardButtonSwitchInline KeyboardButtonSwitchInline
) )
from ..pyrogram_type import PyrogramType
class InlineKeyboardButton(Object): class InlineKeyboardButton(PyrogramType):
"""This object represents one button of an inline keyboard. You must use exactly one of the optional fields. """This object represents one button of an inline keyboard. You must use exactly one of the optional fields.
Args: Args:
@ -54,18 +53,14 @@ class InlineKeyboardButton(Object):
# TODO: Add callback_game and pay fields # TODO: Add callback_game and pay fields
ID = 0xb0700019 def __init__(self,
text: str,
callback_data: bytes = None,
url: str = None,
switch_inline_query: str = None,
switch_inline_query_current_chat: str = None):
super().__init__(None)
def __init__(
self,
text: str,
callback_data: bytes = None,
url: str = None,
switch_inline_query: str = None,
switch_inline_query_current_chat: str = None,
# callback_game=None,
# pay: bool = None
):
self.text = text self.text = text
self.url = url self.url = url
self.callback_data = callback_data self.callback_data = callback_data
@ -75,29 +70,29 @@ class InlineKeyboardButton(Object):
# self.pay = pay # self.pay = pay
@staticmethod @staticmethod
def read(b, *args): def read(o):
if isinstance(b, KeyboardButtonUrl): if isinstance(o, KeyboardButtonUrl):
return InlineKeyboardButton( return InlineKeyboardButton(
text=b.text, text=o.text,
url=b.url url=o.url
) )
if isinstance(b, KeyboardButtonCallback): if isinstance(o, KeyboardButtonCallback):
return InlineKeyboardButton( return InlineKeyboardButton(
text=b.text, text=o.text,
callback_data=b.data callback_data=o.data
) )
if isinstance(b, KeyboardButtonSwitchInline): if isinstance(o, KeyboardButtonSwitchInline):
if b.same_peer: if o.same_peer:
return InlineKeyboardButton( return InlineKeyboardButton(
text=b.text, text=o.text,
switch_inline_query_current_chat=b.query switch_inline_query_current_chat=o.query
) )
else: else:
return InlineKeyboardButton( return InlineKeyboardButton(
text=b.text, text=o.text,
switch_inline_query=b.query switch_inline_query=o.query
) )
def write(self): def write(self):

View file

@ -16,13 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List
from pyrogram.api.types import ReplyInlineMarkup, KeyboardButtonRow from pyrogram.api.types import ReplyInlineMarkup, KeyboardButtonRow
from . import InlineKeyboardButton from . import InlineKeyboardButton
from ..pyrogram_type import PyrogramType
class InlineKeyboardMarkup(Object): class InlineKeyboardMarkup(PyrogramType):
"""This object represents an inline keyboard that appears right next to the message it belongs to. """This object represents an inline keyboard that appears right next to the message it belongs to.
Args: Args:
@ -30,16 +31,17 @@ class InlineKeyboardMarkup(Object):
List of button rows, each represented by a List of InlineKeyboardButton objects. List of button rows, each represented by a List of InlineKeyboardButton objects.
""" """
ID = 0xb0700020 def __init__(self,
inline_keyboard: List[List[InlineKeyboardButton]]):
super().__init__(None)
def __init__(self, inline_keyboard: list):
self.inline_keyboard = inline_keyboard self.inline_keyboard = inline_keyboard
@staticmethod @staticmethod
def read(kb, *args): def read(o):
inline_keyboard = [] inline_keyboard = []
for i in kb.rows: for i in o.rows:
row = [] row = []
for j in i.buttons: for j in i.buttons:

View file

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object
from pyrogram.api.types import KeyboardButton as RawKeyboardButton from pyrogram.api.types import KeyboardButton as RawKeyboardButton
from pyrogram.api.types import KeyboardButtonRequestPhone, KeyboardButtonRequestGeoLocation from pyrogram.api.types import KeyboardButtonRequestPhone, KeyboardButtonRequestGeoLocation
from ..pyrogram_type import PyrogramType
class KeyboardButton(Object): class KeyboardButton(PyrogramType):
"""This object represents one button of the reply keyboard. """This object represents one button of the reply keyboard.
For simple text buttons String can be used instead of this object to specify text of the button. For simple text buttons String can be used instead of this object to specify text of the button.
Optional fields are mutually exclusive. Optional fields are mutually exclusive.
@ -41,27 +40,30 @@ class KeyboardButton(Object):
Available in private chats only. Available in private chats only.
""" """
ID = 0xb0700021 def __init__(self,
text: str,
request_contact: bool = None,
request_location: bool = None):
super().__init__(None)
def __init__(self, text: str, request_contact: bool = None, request_location: bool = None):
self.text = text self.text = text
self.request_contact = request_contact self.request_contact = request_contact
self.request_location = request_location self.request_location = request_location
@staticmethod @staticmethod
def read(b, *args): def read(o):
if isinstance(b, RawKeyboardButton): if isinstance(o, RawKeyboardButton):
return b.text return o.text
if isinstance(b, KeyboardButtonRequestPhone): if isinstance(o, KeyboardButtonRequestPhone):
return KeyboardButton( return KeyboardButton(
text=b.text, text=o.text,
request_contact=True request_contact=True
) )
if isinstance(b, KeyboardButtonRequestGeoLocation): if isinstance(o, KeyboardButtonRequestGeoLocation):
return KeyboardButton( return KeyboardButton(
text=b.text, text=o.text,
request_location=True request_location=True
) )

View file

@ -16,15 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List
from pyrogram.api.types import KeyboardButtonRow from pyrogram.api.types import KeyboardButtonRow
from pyrogram.api.types import ReplyKeyboardMarkup as RawReplyKeyboardMarkup from pyrogram.api.types import ReplyKeyboardMarkup as RawReplyKeyboardMarkup
from . import KeyboardButton from . import KeyboardButton
from ..pyrogram_type import PyrogramType
class ReplyKeyboardMarkup(Object): class ReplyKeyboardMarkup(PyrogramType):
"""This object represents a custom keyboard with reply options. """This object represents a custom keyboard with reply options.
Args: Args:
@ -49,22 +49,20 @@ class ReplyKeyboardMarkup(Object):
select the new language. Other users in the group don't see the keyboard. select the new language. Other users in the group don't see the keyboard.
""" """
ID = 0xb0700022 def __init__(self,
keyboard: List[List[KeyboardButton]],
resize_keyboard: bool = None,
one_time_keyboard: bool = None,
selective: bool = None):
super().__init__(None)
def __init__(
self,
keyboard: list,
resize_keyboard: bool = None,
one_time_keyboard: bool = None,
selective: bool = None
):
self.keyboard = keyboard self.keyboard = keyboard
self.resize_keyboard = resize_keyboard self.resize_keyboard = resize_keyboard
self.one_time_keyboard = one_time_keyboard self.one_time_keyboard = one_time_keyboard
self.selective = selective self.selective = selective
@staticmethod @staticmethod
def read(kb, *args): def read(kb):
keyboard = [] keyboard = []
for i in kb.rows: for i in kb.rows:

View file

@ -16,11 +16,11 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object
from pyrogram.api.types import ReplyKeyboardHide from pyrogram.api.types import ReplyKeyboardHide
from ..pyrogram_type import PyrogramType
class ReplyKeyboardRemove(Object): class ReplyKeyboardRemove(PyrogramType):
"""Upon receiving a message with this object, Telegram clients will remove the current custom keyboard and """Upon receiving a message with this object, Telegram clients will remove the current custom keyboard and
display the default letter-keyboard. By default, custom keyboards are displayed until a new keyboard is sent display the default letter-keyboard. By default, custom keyboards are displayed until a new keyboard is sent
by a bot. An exception is made for one-time keyboards that are hidden immediately after the user presses a by a bot. An exception is made for one-time keyboards that are hidden immediately after the user presses a
@ -35,13 +35,14 @@ class ReplyKeyboardRemove(Object):
keyboard for that user, while still showing the keyboard with poll options to users who haven't voted yet. keyboard for that user, while still showing the keyboard with poll options to users who haven't voted yet.
""" """
ID = 0xb0700023 def __init__(self,
selective: bool = None):
super().__init__(None)
def __init__(self, selective: bool = None):
self.selective = selective self.selective = selective
@staticmethod @staticmethod
def read(o, *args): def read(o):
return ReplyKeyboardRemove( return ReplyKeyboardRemove(
selective=o.selective selective=o.selective
) )

View file

@ -18,7 +18,10 @@
class InputMedia: class InputMedia:
def __init__(self, media: str, caption: str, parse_mode: str): def __init__(self,
media: str,
caption: str,
parse_mode: str):
self.media = media self.media = media
self.caption = caption self.caption = caption
self.parse_mode = parse_mode self.parse_mode = parse_mode

View file

@ -35,10 +35,16 @@ class InputPhoneContact:
Contact's last name Contact's last name
""" """
def __init__(self, phone: str, first_name: str, last_name: str = ""): def __init__(self,
phone: str,
first_name: str,
last_name: str = ""):
pass pass
def __new__(cls, phone: str, first_name: str, last_name: str = ""): def __new__(cls,
phone: str,
first_name: str,
last_name: str = ""):
return RawInputPhoneContact( return RawInputPhoneContact(
client_id=MsgId(), client_id=MsgId(),
phone="+" + phone.strip("+"), phone="+" + phone.strip("+"),

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Animation(Object): class Animation(PyrogramType):
"""This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound). """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
Args: Args:
@ -51,20 +57,20 @@ class Animation(Object):
Date the animation was sent in Unix time. Date the animation was sent in Unix time.
""" """
ID = 0xb0700025 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
width: int,
height: int,
duration: int,
thumb: PhotoSize = None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
super().__init__(client)
def __init__(
self,
file_id: str,
width: int,
height: int,
duration: int,
thumb=None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None
):
self.file_id = file_id self.file_id = file_id
self.thumb = thumb self.thumb = thumb
self.file_name = file_name self.file_name = file_name
@ -74,3 +80,27 @@ class Animation(Object):
self.width = width self.width = width
self.height = height self.height = height
self.duration = duration self.duration = duration
@staticmethod
def _parse(client, animation: types.Document, video_attributes: types.DocumentAttributeVideo,
file_name: str) -> "Animation":
return Animation(
file_id=encode(
pack(
"<iiqq",
10,
animation.dc_id,
animation.id,
animation.access_hash
)
),
width=getattr(video_attributes, "w", 0),
height=getattr(video_attributes, "h", 0),
duration=getattr(video_attributes, "duration", 0),
thumb=PhotoSize._parse(client, animation.thumb),
mime_type=animation.mime_type,
file_size=animation.size,
file_name=file_name,
date=animation.date,
client=client
)

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Audio(Object): class Audio(PyrogramType):
"""This object represents an audio file to be treated as music by the Telegram clients. """This object represents an audio file to be treated as music by the Telegram clients.
Args: Args:
@ -51,20 +57,20 @@ class Audio(Object):
Title of the audio as defined by sender or by audio tags. Title of the audio as defined by sender or by audio tags.
""" """
ID = 0xb0700006 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
duration: int,
thumb: PhotoSize = None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None,
performer: str = None,
title: str = None):
super().__init__(client)
def __init__(
self,
file_id: str,
duration: int,
thumb=None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None,
performer: str = None,
title: str = None
):
self.file_id = file_id self.file_id = file_id
self.thumb = thumb self.thumb = thumb
self.file_name = file_name self.file_name = file_name
@ -74,3 +80,27 @@ class Audio(Object):
self.duration = duration self.duration = duration
self.performer = performer self.performer = performer
self.title = title self.title = title
@staticmethod
def _parse(client, audio: types.Document, audio_attributes: types.DocumentAttributeAudio,
file_name: str) -> "Audio":
return Audio(
file_id=encode(
pack(
"<iiqq",
9,
audio.dc_id,
audio.id,
audio.access_hash
)
),
duration=audio_attributes.duration,
performer=audio_attributes.performer,
title=audio_attributes.title,
mime_type=audio.mime_type,
file_size=audio.size,
thumb=PhotoSize._parse(client, audio.thumb),
file_name=file_name,
date=audio.date,
client=client
)

View file

@ -16,10 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
class Contact(Object): class Contact(PyrogramType):
"""This object represents a phone contact. """This object represents a phone contact.
Args: Args:
@ -39,18 +42,29 @@ class Contact(Object):
Additional data about the contact in the form of a vCard. Additional data about the contact in the form of a vCard.
""" """
ID = 0xb0700011 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
phone_number: str,
first_name: str,
last_name: str = None,
user_id: int = None,
vcard: str = None):
super().__init__(client)
def __init__(
self,
phone_number: str,
first_name: str,
last_name: str = None,
user_id: int = None,
vcard: str = None
):
self.phone_number = phone_number self.phone_number = phone_number
self.first_name = first_name self.first_name = first_name
self.last_name = last_name self.last_name = last_name
self.user_id = user_id self.user_id = user_id
self.vcard = vcard self.vcard = vcard
@staticmethod
def _parse(client, contact: types.MessageMediaContact) -> "Contact":
return Contact(
phone_number=contact.phone_number,
first_name=contact.first_name,
last_name=contact.last_name or None,
vcard=contact.vcard or None,
user_id=contact.user_id or None,
client=client
)

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Document(Object): class Document(PyrogramType):
"""This object represents a general file (as opposed to photos, voice messages, audio files, ...). """This object represents a general file (as opposed to photos, voice messages, audio files, ...).
Args: Args:
@ -42,20 +48,40 @@ class Document(Object):
Date the document was sent in Unix time. Date the document was sent in Unix time.
""" """
ID = 0xb0700007 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
thumb: PhotoSize = None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
super().__init__(client)
def __init__(
self,
file_id: str,
thumb=None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None
):
self.file_id = file_id self.file_id = file_id
self.thumb = thumb self.thumb = thumb
self.file_name = file_name self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
self.date = date self.date = date
@staticmethod
def _parse(client, document: types.Document, file_name: str) -> "Document":
return Document(
file_id=encode(
pack(
"<iiqq",
5,
document.dc_id,
document.id,
document.access_hash
)
),
thumb=PhotoSize._parse(client, document.thumb),
file_name=file_name,
mime_type=document.mime_type,
file_size=document.size,
date=document.date,
client=client
)

View file

@ -16,10 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
class Location(Object): class Location(PyrogramType):
"""This object represents a point on the map. """This object represents a point on the map.
Args: Args:
@ -30,8 +33,21 @@ class Location(Object):
Latitude as defined by sender. Latitude as defined by sender.
""" """
ID = 0xb0700012 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
longitude: float,
latitude: float):
super().__init__(client)
def __init__(self, longitude: float, latitude: float):
self.longitude = longitude self.longitude = longitude
self.latitude = latitude self.latitude = latitude
@staticmethod
def _parse(client, geo_point: types.GeoPoint) -> "Location":
if isinstance(geo_point, types.GeoPoint):
return Location(
longitude=geo_point.long,
latitude=geo_point.lat,
client=client
)

View file

@ -16,11 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List, Match, Union
from ..bots import InlineKeyboardMarkup, ReplyKeyboardMarkup
import pyrogram
from pyrogram.api import types
from pyrogram.api.errors import MessageIdsEmpty
from .contact import Contact
from .location import Location
from .message_entity import MessageEntity
from ..messages_and_media.photo import Photo
from ..pyrogram_type import PyrogramType
from ..user_and_chats.chat import Chat
from ..user_and_chats.user import User
class Message(Object): class Message(PyrogramType):
"""This object represents a message. """This object represents a message.
Args: Args:
@ -193,18 +203,18 @@ class Message(Object):
via_bot (:obj:`User <pyrogram.User>`): via_bot (:obj:`User <pyrogram.User>`):
The information of the bot that generated the message from an inline query of a user. The information of the bot that generated the message from an inline query of a user.
outgoing (``bool``, *optional*): outgoing (``bool``, *optional*):
Whether the message is incoming or outgoing. Whether the message is incoming or outgoing.
Messages received from other chats are incoming (*outgoing* is False). Messages received from other chats are incoming (*outgoing* is False).
Messages sent from yourself to other chats are outgoing (*outgoing* is True). Messages sent from yourself to other chats are outgoing (*outgoing* is True).
An exception is made for your own personal chat; messages sent there will be incoming. An exception is made for your own personal chat; messages sent there will be incoming.
matches (``list``, *optional*): matches (List of regex Matches, *optional*):
A list containing all `Match Objects <https://docs.python.org/3/library/re.html#match-objects>`_ that match A list containing all `Match Objects <https://docs.python.org/3/library/re.html#match-objects>`_ that match
the text of this message. Only applicable when using :obj:`Filters.regex <pyrogram.Filters.regex>`. the text of this message. Only applicable when using :obj:`Filters.regex <pyrogram.Filters.regex>`.
command (``list``, *optional*): command (List of ``str``, *optional*):
A list containing the command and its arguments, if any. A list containing the command and its arguments, if any.
E.g.: "/start 1 2 3" would produce ["start", "1", "2", "3"]. E.g.: "/start 1 2 3" would produce ["start", "1", "2", "3"].
Only applicable when using :obj:`Filters.command <pyrogram.Filters.command>`. Only applicable when using :obj:`Filters.command <pyrogram.Filters.command>`.
@ -215,114 +225,342 @@ class Message(Object):
""" """
# TODO: Add game missing field. Also invoice, successful_payment, connected_website # TODO: Add game missing field. Also invoice, successful_payment, connected_website
ID = 0xb0700003
def __init__( def __init__(self,
self, *,
message_id: int, client: "pyrogram.client.ext.BaseClient",
client=None, message_id: int,
date: int = None, date: int = None,
chat=None, chat: Chat = None,
from_user=None, from_user: User = None,
forward_from=None, forward_from: User = None,
forward_from_chat=None, forward_from_chat: Chat = None,
forward_from_message_id: int = None, forward_from_message_id: int = None,
forward_signature: str = None, forward_signature: str = None,
forward_date: int = None, forward_date: int = None,
reply_to_message=None, reply_to_message: "Message" = None,
mentioned=None, mentioned: bool = None,
empty=None, empty: bool = None,
service=None, service: bool = None,
media=None, media: bool = 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,
text: str = None, text: str = None,
entities: list = None, entities: List["pyrogram.MessageEntity"] = None,
caption_entities: list = None, caption_entities: List["pyrogram.MessageEntity"] = None,
audio=None, audio: "pyrogram.Audio" = None,
document=None, document: "pyrogram.Document" = None,
photo=None, photo: "pyrogram.Photo" = None,
sticker=None, sticker: "pyrogram.Sticker" = None,
animation=None, animation: "pyrogram.Animation" = None,
video=None, video: "pyrogram.Video" = None,
voice=None, voice: "pyrogram.Voice" = None,
video_note=None, video_note: "pyrogram.VideoNote" = None,
caption: str = None, caption: str = None,
contact=None, contact: "pyrogram.Contact" = None,
location=None, location: "pyrogram.Location" = None,
venue=None, venue: "pyrogram.Venue" = None,
web_page=None, web_page: bool = None,
new_chat_members: list = None, new_chat_members: List[User] = None,
left_chat_member=None, left_chat_member: User = None,
new_chat_title: str = None, new_chat_title: str = None,
new_chat_photo=None, new_chat_photo: "pyrogram.Photo" = None,
delete_chat_photo: bool = None, delete_chat_photo: bool = None,
group_chat_created: bool = None, group_chat_created: bool = None,
supergroup_chat_created: bool = None, supergroup_chat_created: bool = None,
channel_chat_created: bool = None, channel_chat_created: bool = None,
migrate_to_chat_id: int = None, migrate_to_chat_id: int = None,
migrate_from_chat_id: int = None, migrate_from_chat_id: int = None,
pinned_message=None, pinned_message: "Message" = None,
views: int = None, views: int = None,
via_bot=None, via_bot: User = None,
outgoing: bool = None, outgoing: bool = None,
matches: list = None, matches: List[Match] = None,
command: list = None, command: List[str] = None,
reply_markup=None, reply_markup: Union["pyrogram.InlineKeyboardMarkup",
): "pyrogram.ReplyKeyboardMarkup",
self.message_id = message_id # int "pyrogram.ReplyKeyboardRemove",
self._client = client "pyrogram.ForceReply"] = None):
self.date = date # int super().__init__(client)
self.chat = chat # Chat
self.from_user = from_user # flags.0?User self.message_id = message_id
self.forward_from = forward_from # flags.1?User self.date = date
self.forward_from_chat = forward_from_chat # flags.2?Chat self.chat = chat
self.forward_from_message_id = forward_from_message_id # flags.3?int self.from_user = from_user
self.forward_signature = forward_signature # flags.4?string self.forward_from = forward_from
self.forward_date = forward_date # flags.5?int self.forward_from_chat = forward_from_chat
self.reply_to_message = reply_to_message # flags.6?Message self.forward_from_message_id = forward_from_message_id
self.forward_signature = forward_signature
self.forward_date = forward_date
self.reply_to_message = reply_to_message
self.mentioned = mentioned self.mentioned = mentioned
self.empty = empty self.empty = empty
self.service = service self.service = service
self.media = media self.media = media
self.edit_date = edit_date # flags.7?int self.edit_date = edit_date
self.media_group_id = media_group_id # flags.8?string self.media_group_id = media_group_id
self.author_signature = author_signature # flags.9?string self.author_signature = author_signature
self.text = text # flags.10?string self.text = text
self.entities = entities # flags.11?Vector<MessageEntity> self.entities = entities
self.caption_entities = caption_entities # flags.12?Vector<MessageEntity> self.caption_entities = caption_entities
self.audio = audio # flags.13?Audio self.audio = audio
self.document = document # flags.14?Document self.document = document
self.photo = photo # flags.16?Vector<PhotoSize> self.photo = photo
self.sticker = sticker # flags.17?Sticker self.sticker = sticker
self.animation = animation self.animation = animation
self.video = video # flags.18?Video self.video = video
self.voice = voice # flags.19?Voice self.voice = voice
self.video_note = video_note # flags.20?VideoNote self.video_note = video_note
self.caption = caption # flags.21?string self.caption = caption
self.contact = contact # flags.22?Contact self.contact = contact
self.location = location # flags.23?Location self.location = location
self.venue = venue # flags.24?Venue self.venue = venue
self.web_page = web_page self.web_page = web_page
self.new_chat_members = new_chat_members # flags.25?Vector<User> self.new_chat_members = new_chat_members
self.left_chat_member = left_chat_member # flags.26?User self.left_chat_member = left_chat_member
self.new_chat_title = new_chat_title # flags.27?string self.new_chat_title = new_chat_title
self.new_chat_photo = new_chat_photo # flags.28?Vector<PhotoSize> self.new_chat_photo = new_chat_photo
self.delete_chat_photo = delete_chat_photo # flags.29?true self.delete_chat_photo = delete_chat_photo
self.group_chat_created = group_chat_created # flags.30?true self.group_chat_created = group_chat_created
self.supergroup_chat_created = supergroup_chat_created # flags.31?true self.supergroup_chat_created = supergroup_chat_created
self.channel_chat_created = channel_chat_created # flags.32?true self.channel_chat_created = channel_chat_created
self.migrate_to_chat_id = migrate_to_chat_id # flags.33?int self.migrate_to_chat_id = migrate_to_chat_id
self.migrate_from_chat_id = migrate_from_chat_id # flags.34?int self.migrate_from_chat_id = migrate_from_chat_id
self.pinned_message = pinned_message # flags.35?Message self.pinned_message = pinned_message
self.views = views # flags.39?int self.views = views
self.via_bot = via_bot # flags.40?User self.via_bot = via_bot
self.outgoing = outgoing self.outgoing = outgoing
self.matches = matches self.matches = matches
self.command = command self.command = command
self.reply_markup = reply_markup self.reply_markup = reply_markup
@staticmethod
async def _parse(client, message: types.Message or types.MessageService or types.MessageEmpty, users: dict,
chats: dict, replies: int = 1):
if isinstance(message, types.MessageEmpty):
return Message(message_id=message.id, empty=True, client=client)
if isinstance(message, types.MessageService):
action = message.action
new_chat_members = None
left_chat_member = None
new_chat_title = None
delete_chat_photo = None
migrate_to_chat_id = None
migrate_from_chat_id = None
group_chat_created = None
channel_chat_created = None
new_chat_photo = None
if isinstance(action, types.MessageActionChatAddUser):
new_chat_members = [User._parse(client, users[i]) for i in action.users]
elif isinstance(action, types.MessageActionChatJoinedByLink):
new_chat_members = [User._parse(client, users[message.from_id])]
elif isinstance(action, types.MessageActionChatDeleteUser):
left_chat_member = User._parse(client, users[action.user_id])
elif isinstance(action, types.MessageActionChatEditTitle):
new_chat_title = action.title
elif isinstance(action, types.MessageActionChatDeletePhoto):
delete_chat_photo = True
elif isinstance(action, types.MessageActionChatMigrateTo):
migrate_to_chat_id = action.channel_id
elif isinstance(action, types.MessageActionChannelMigrateFrom):
migrate_from_chat_id = action.chat_id
elif isinstance(action, types.MessageActionChatCreate):
group_chat_created = True
elif isinstance(action, types.MessageActionChannelCreate):
channel_chat_created = True
elif isinstance(action, types.MessageActionChatEditPhoto):
new_chat_photo = Photo._parse(client, action.photo)
parsed_message = Message(
message_id=message.id,
date=message.date,
chat=Chat._parse(client, message, users, chats),
from_user=User._parse(client, users.get(message.from_id, None)),
service=True,
new_chat_members=new_chat_members,
left_chat_member=left_chat_member,
new_chat_title=new_chat_title,
new_chat_photo=new_chat_photo,
delete_chat_photo=delete_chat_photo,
migrate_to_chat_id=int("-100" + str(migrate_to_chat_id)) if migrate_to_chat_id else None,
migrate_from_chat_id=-migrate_from_chat_id if migrate_from_chat_id else None,
group_chat_created=group_chat_created,
channel_chat_created=channel_chat_created,
client=client
# TODO: supergroup_chat_created
)
if isinstance(action, types.MessageActionPinMessage):
try:
parsed_message.pinned_message = await client.get_messages(
parsed_message.chat.id,
reply_to_message_ids=message.id,
replies=0
)
except MessageIdsEmpty:
pass
return parsed_message
if isinstance(message, types.Message):
entities = [MessageEntity._parse(client, entity, users) for entity in message.entities]
entities = list(filter(lambda x: x is not None, entities))
forward_from = None
forward_from_chat = None
forward_from_message_id = None
forward_signature = None
forward_date = None
forward_header = message.fwd_from
if forward_header:
forward_date = forward_header.date
if forward_header.from_id:
forward_from = User._parse(client, users[forward_header.from_id])
else:
forward_from_chat = Chat._parse_channel_chat(client, chats[forward_header.channel_id])
forward_from_message_id = forward_header.channel_post
forward_signature = forward_header.post_author
photo = None
location = None
contact = None
venue = None
audio = None
voice = None
animation = None
video = None
video_note = None
sticker = None
document = None
web_page = None
media = message.media
if media:
if isinstance(media, types.MessageMediaPhoto):
photo = Photo._parse(client, media.photo)
elif isinstance(media, types.MessageMediaGeo):
location = Location._parse(client, media.geo)
elif isinstance(media, types.MessageMediaContact):
contact = Contact._parse(client, media)
elif isinstance(media, types.MessageMediaVenue):
venue = pyrogram.Venue._parse(client, media)
elif isinstance(media, types.MessageMediaDocument):
doc = media.document
if isinstance(doc, types.Document):
attributes = {type(i): i for i in doc.attributes}
file_name = getattr(
attributes.get(
types.DocumentAttributeFilename, None
), "file_name", None
)
if types.DocumentAttributeAudio in attributes:
audio_attributes = attributes[types.DocumentAttributeAudio]
if audio_attributes.voice:
voice = pyrogram.Voice._parse(client, doc, audio_attributes)
else:
audio = pyrogram.Audio._parse(client, doc, audio_attributes, file_name)
elif types.DocumentAttributeAnimated in attributes:
video_attributes = attributes.get(types.DocumentAttributeVideo, None)
animation = pyrogram.Animation._parse(client, doc, video_attributes, file_name)
elif types.DocumentAttributeVideo in attributes:
video_attributes = attributes[types.DocumentAttributeVideo]
if video_attributes.round_message:
video_note = pyrogram.VideoNote._parse(client, doc, video_attributes)
else:
video = pyrogram.Video._parse(client, doc, video_attributes, file_name)
elif types.DocumentAttributeSticker in attributes:
sticker = await pyrogram.Sticker._parse(
client, doc,
attributes.get(types.DocumentAttributeImageSize, None),
attributes[types.DocumentAttributeSticker],
file_name
)
else:
document = pyrogram.Document._parse(client, doc, file_name)
elif isinstance(media, types.MessageMediaWebPage):
web_page = True
media = None
else:
media = None
reply_markup = message.reply_markup
if reply_markup:
if isinstance(reply_markup, types.ReplyKeyboardForceReply):
reply_markup = pyrogram.ForceReply.read(reply_markup)
elif isinstance(reply_markup, types.ReplyKeyboardMarkup):
reply_markup = pyrogram.ReplyKeyboardMarkup.read(reply_markup)
elif isinstance(reply_markup, types.ReplyInlineMarkup):
reply_markup = pyrogram.InlineKeyboardMarkup.read(reply_markup)
elif isinstance(reply_markup, types.ReplyKeyboardHide):
reply_markup = pyrogram.ReplyKeyboardRemove.read(reply_markup)
else:
reply_markup = None
parsed_message = Message(
message_id=message.id,
date=message.date,
chat=Chat._parse(client, message, users, chats),
from_user=User._parse(client, users.get(message.from_id, None)),
text=Str(message.message).init(client, entities) or None if media is None else None,
caption=Str(message.message).init(client, entities) or None if media is not None else None,
entities=entities or None if media is None else None,
caption_entities=entities or None if media is not None else None,
author_signature=message.post_author,
forward_from=forward_from,
forward_from_chat=forward_from_chat,
forward_from_message_id=forward_from_message_id,
forward_signature=forward_signature,
forward_date=forward_date,
mentioned=message.mentioned,
media=bool(media) or None,
edit_date=message.edit_date,
media_group_id=message.grouped_id,
photo=photo,
location=location,
contact=contact,
venue=venue,
audio=audio,
voice=voice,
animation=animation,
video=video,
video_note=video_note,
sticker=sticker,
document=document,
web_page=web_page,
views=message.views,
via_bot=User._parse(client, users.get(message.via_bot_id, None)),
outgoing=message.out,
reply_markup=reply_markup,
client=client
)
if message.reply_to_msg_id and replies:
try:
parsed_message.reply_to_message = await client.get_messages(
parsed_message.chat.id,
reply_to_message_ids=message.id,
replies=replies - 1
)
except MessageIdsEmpty:
pass
return parsed_message
async def reply(self, async def reply(self,
text: str, text: str,
quote: bool = None, quote: bool = None,
@ -586,9 +824,9 @@ class Message(Object):
``ValueError``: If the provided index or position is out of range or the button label was not found ``ValueError``: If the provided index or position is out of range or the button label was not found
``TimeoutError``: If, after clicking an inline button, the bot fails to answer within 10 seconds ``TimeoutError``: If, after clicking an inline button, the bot fails to answer within 10 seconds
""" """
if isinstance(self.reply_markup, ReplyKeyboardMarkup): if isinstance(self.reply_markup, pyrogram.ReplyKeyboardMarkup):
return await self.reply(x) return await self.reply(x)
elif isinstance(self.reply_markup, InlineKeyboardMarkup): elif isinstance(self.reply_markup, pyrogram.InlineKeyboardMarkup):
if isinstance(x, int) and y is None: if isinstance(x, int) and y is None:
try: try:
button = [ button = [
@ -687,3 +925,29 @@ class Message(Object):
progress=progress, progress=progress,
progress_args=progress_args, progress_args=progress_args,
) )
class Str(str):
def __init__(self, *args):
super().__init__()
self.client = None
self.entities = None
def init(self, client, entities):
self.client = client
self.entities = entities
return self
@property
def text(self):
return self
@property
def markdown(self):
return self.client.markdown.unparse(self, self.entities)
@property
def html(self):
return self.client.html.unparse(self, self.entities)

View file

@ -16,10 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
from ..user_and_chats.user import User
class MessageEntity(Object): class MessageEntity(PyrogramType):
"""This object represents one special entity in a text message. """This object represents one special entity in a text message.
For example, hashtags, usernames, URLs, etc. For example, hashtags, usernames, URLs, etc.
@ -43,18 +47,50 @@ class MessageEntity(Object):
For "text_mention" only, the mentioned user. For "text_mention" only, the mentioned user.
""" """
ID = 0xb0700004 ENTITIES = {
types.MessageEntityMention.ID: "mention",
types.MessageEntityHashtag.ID: "hashtag",
types.MessageEntityCashtag.ID: "cashtag",
types.MessageEntityBotCommand.ID: "bot_command",
types.MessageEntityUrl.ID: "url",
types.MessageEntityEmail.ID: "email",
types.MessageEntityBold.ID: "bold",
types.MessageEntityItalic.ID: "italic",
types.MessageEntityCode.ID: "code",
types.MessageEntityPre.ID: "pre",
types.MessageEntityTextUrl.ID: "text_link",
types.MessageEntityMentionName.ID: "text_mention",
types.MessageEntityPhone.ID: "phone_number"
}
def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
type: str,
offset: int,
length: int,
url: str = None,
user: User = None):
super().__init__(client)
def __init__(
self,
type: str,
offset: int,
length: int,
url: str = None,
user=None
):
self.type = type self.type = type
self.offset = offset self.offset = offset
self.length = length self.length = length
self.url = url self.url = url
self.user = user self.user = user
@staticmethod
def _parse(client, entity, users: dict) -> "MessageEntity" or None:
type = MessageEntity.ENTITIES.get(entity.ID, None)
if type is None:
return None
return MessageEntity(
type=type,
offset=entity.offset,
length=entity.length,
url=getattr(entity, "url", None),
user=User._parse(client, users.get(getattr(entity, "user_id", None), None)),
client=client
)

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List
import pyrogram
from pyrogram.api import types
from .message import Message
from ..pyrogram_type import PyrogramType
from ..user_and_chats import Chat
class Messages(Object): class Messages(PyrogramType):
"""This object represents a chat's messages. """This object represents a chat's messages.
Args: Args:
@ -30,8 +36,55 @@ class Messages(Object):
Requested messages. Requested messages.
""" """
ID = 0xb0700026 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
total_count: int,
messages: List[Message]):
super().__init__(client)
def __init__(self, total_count: int, messages: list):
self.total_count = total_count self.total_count = total_count
self.messages = messages self.messages = messages
@staticmethod
async def _parse(client, messages: types.messages.Messages) -> "Messages":
users = {i.id: i for i in messages.users}
chats = {i.id: i for i in messages.chats}
# TODO: WTF! Py 3.5 doesn't support await inside comprehensions
parsed_messages = []
for message in messages.messages:
parsed_messages.append(await Message._parse(client, message, users, chats))
return Messages(
total_count=getattr(messages, "count", len(messages.messages)),
messages=parsed_messages,
client=client
)
@staticmethod
def _parse_deleted(client, update) -> "Messages":
messages = update.messages
channel_id = getattr(update, "channel_id", None)
parsed_messages = []
for message in messages:
parsed_messages.append(
Message(
message_id=message,
chat=Chat(
id=int("-100" + str(channel_id)),
type="channel",
client=client
) if channel_id is not None else None,
client=client
)
)
return Messages(
total_count=len(parsed_messages),
messages=parsed_messages,
client=client
)

View file

@ -16,10 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from base64 import b64encode
from struct import pack
from typing import List
import pyrogram
from pyrogram.api import types
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Photo(Object): class Photo(PyrogramType):
"""This object represents a Photo. """This object represents a Photo.
Args: Args:
@ -33,9 +41,61 @@ class Photo(Object):
Available sizes of this photo. Available sizes of this photo.
""" """
ID = 0xb0700027 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
id: str,
date: int,
sizes: List[PhotoSize]):
super().__init__(client)
def __init__(self, id: str, date: int, sizes: list):
self.id = id self.id = id
self.date = date self.date = date
self.sizes = sizes self.sizes = sizes
@staticmethod
def _parse(client, photo: types.Photo):
if isinstance(photo, types.Photo):
raw_sizes = photo.sizes
sizes = []
for raw_size in raw_sizes:
if isinstance(raw_size, (types.PhotoSize, types.PhotoCachedSize)):
if isinstance(raw_size, types.PhotoSize):
file_size = raw_size.size
elif isinstance(raw_size, types.PhotoCachedSize):
file_size = len(raw_size.bytes)
else:
file_size = 0
loc = raw_size.location
if isinstance(loc, types.FileLocation):
size = PhotoSize(
file_id=encode(
pack(
"<iiqqqqi",
2, loc.dc_id, photo.id, photo.access_hash,
loc.volume_id, loc.secret, loc.local_id)),
width=raw_size.w,
height=raw_size.h,
file_size=file_size,
client=client
)
sizes.append(size)
return Photo(
id=b64encode(
pack(
"<qq",
photo.id,
photo.access_hash
),
b"-_"
).decode().rstrip("="),
date=photo.date,
sizes=sizes,
client=client
)

View file

@ -16,10 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from pyrogram.client.ext.utils import encode
from ..pyrogram_type import PyrogramType
class PhotoSize(Object): class PhotoSize(PyrogramType):
"""This object represents one size of a photo or a file/sticker thumbnail. """This object represents one size of a photo or a file/sticker thumbnail.
Args: Args:
@ -36,10 +41,42 @@ class PhotoSize(Object):
File size. File size.
""" """
ID = 0xb0700005 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
width: int,
height: int,
file_size: int):
super().__init__(client)
def __init__(self, file_id: str, width: int, height: int, file_size: int):
self.file_id = file_id self.file_id = file_id
self.width = width self.width = width
self.height = height self.height = height
self.file_size = file_size self.file_size = file_size
@staticmethod
def _parse(client, photo_size: types.PhotoSize or types.PhotoCachedSize):
if isinstance(photo_size, (types.PhotoSize, types.PhotoCachedSize)):
if isinstance(photo_size, types.PhotoSize):
file_size = photo_size.size
elif isinstance(photo_size, types.PhotoCachedSize):
file_size = len(photo_size.bytes)
else:
file_size = 0
loc = photo_size.location
if isinstance(loc, types.FileLocation):
return PhotoSize(
file_id=encode(
pack(
"<iiqqqqi",
0, loc.dc_id, 0, 0,
loc.volume_id, loc.secret, loc.local_id)),
width=photo_size.w,
height=photo_size.h,
file_size=file_size,
client=client
)

View file

@ -16,10 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from functools import lru_cache
from struct import pack
import pyrogram
from pyrogram.api import types, functions
from pyrogram.api.errors import StickersetInvalid
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Sticker(Object): class Sticker(PyrogramType):
"""This object represents a sticker. """This object represents a sticker.
Args: Args:
@ -55,22 +63,22 @@ class Sticker(Object):
""" """
# TODO: Add mask position # TODO: Add mask position
ID = 0xb0700017
def __init__( def __init__(self,
self, *,
file_id: str, client: "pyrogram.client.ext.BaseClient",
width: int, file_id: str,
height: int, width: int,
thumb=None, height: int,
file_name: str = None, thumb: PhotoSize = None,
mime_type: str = None, file_name: str = None,
file_size: int = None, mime_type: str = None,
date: int = None, file_size: int = None,
emoji: str = None, date: int = None,
set_name: str = None, emoji: str = None,
mask_position=None set_name: str = None):
): super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.thumb = thumb self.thumb = thumb
self.file_name = file_name self.file_name = file_name
@ -81,4 +89,50 @@ class Sticker(Object):
self.height = height self.height = height
self.emoji = emoji self.emoji = emoji
self.set_name = set_name self.set_name = set_name
self.mask_position = mask_position # self.mask_position = mask_position
@staticmethod
@lru_cache(maxsize=256)
async def get_sticker_set_name(send, input_sticker_set_id):
try:
return await send(
functions.messages.GetStickerSet(
types.InputStickerSetID(*input_sticker_set_id)
)
).set.short_name
except StickersetInvalid:
return None
@staticmethod
async def _parse(client, sticker: types.Document, image_size_attributes: types.DocumentAttributeImageSize,
sticker_attributes: types.DocumentAttributeSticker, file_name: str) -> "Sticker":
sticker_set = sticker_attributes.stickerset
if isinstance(sticker_set, types.InputStickerSetID):
input_sticker_set_id = (sticker_set.id, sticker_set.access_hash)
set_name = await Sticker.get_sticker_set_name(client.send, input_sticker_set_id)
else:
set_name = None
return Sticker(
file_id=encode(
pack(
"<iiqq",
8,
sticker.dc_id,
sticker.id,
sticker.access_hash
)
),
width=image_size_attributes.w if image_size_attributes else 0,
height=image_size_attributes.h if image_size_attributes else 0,
thumb=PhotoSize._parse(client, sticker.thumb),
# TODO: mask_position
set_name=set_name,
emoji=sticker_attributes.alt or None,
file_size=sticker.size,
mime_type=sticker.mime_type,
file_name=file_name,
date=sticker.date,
client=client
)

View file

@ -16,10 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List
import pyrogram
from .photo import Photo
from ..pyrogram_type import PyrogramType
class UserProfilePhotos(Object): class UserProfilePhotos(PyrogramType):
"""This object represents a user's profile pictures. """This object represents a user's profile pictures.
Args: Args:
@ -30,8 +34,20 @@ class UserProfilePhotos(Object):
Requested profile pictures. Requested profile pictures.
""" """
ID = 0xb0700014 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
total_count: int,
photos: List[Photo]):
super().__init__(client)
def __init__(self, total_count: int, photos: list):
self.total_count = total_count self.total_count = total_count
self.photos = photos self.photos = photos
@staticmethod
def _parse(client, photos) -> "UserProfilePhotos":
return UserProfilePhotos(
total_count=getattr(photos, "count", len(photos.photos)),
photos=[Photo._parse(client, photo) for photo in photos.photos],
client=client
)

View file

@ -16,10 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from .location import Location
from ..pyrogram_type import PyrogramType
class Venue(Object): class Venue(PyrogramType):
"""This object represents a venue. """This object represents a venue.
Args: Args:
@ -41,18 +44,29 @@ class Venue(Object):
""" """
ID = 0xb0700013 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
location: Location,
title: str,
address: str,
foursquare_id: str = None,
foursquare_type: str = None):
super().__init__(client)
def __init__(
self,
location,
title: str,
address: str,
foursquare_id: str = None,
foursquare_type: str = None
):
self.location = location self.location = location
self.title = title self.title = title
self.address = address self.address = address
self.foursquare_id = foursquare_id self.foursquare_id = foursquare_id
self.foursquare_type = foursquare_type self.foursquare_type = foursquare_type
@staticmethod
def _parse(client, venue: types.MessageMediaVenue):
return Venue(
location=Location._parse(client, venue.geo),
title=venue.title,
address=venue.address,
foursquare_id=venue.venue_id or None,
foursquare_type=venue.venue_type,
client=client
)

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Video(Object): class Video(PyrogramType):
"""This object represents a video file. """This object represents a video file.
Args: Args:
@ -51,20 +57,20 @@ class Video(Object):
Date the video was sent in Unix time. Date the video was sent in Unix time.
""" """
ID = 0xb0700008 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
width: int,
height: int,
duration: int,
thumb: PhotoSize = None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
super().__init__(client)
def __init__(
self,
file_id: str,
width: int,
height: int,
duration: int,
thumb=None,
file_name: str = None,
mime_type: str = None,
file_size: int = None,
date: int = None
):
self.file_id = file_id self.file_id = file_id
self.thumb = thumb self.thumb = thumb
self.file_name = file_name self.file_name = file_name
@ -74,3 +80,27 @@ class Video(Object):
self.width = width self.width = width
self.height = height self.height = height
self.duration = duration self.duration = duration
@staticmethod
def _parse(client, video: types.Document, video_attributes: types.DocumentAttributeVideo,
file_name: str) -> "Video":
return Video(
file_id=encode(
pack(
"<iiqq",
4,
video.dc_id,
video.id,
video.access_hash
)
),
width=video_attributes.w,
height=video_attributes.h,
duration=video_attributes.duration,
thumb=PhotoSize._parse(client, video.thumb),
mime_type=video.mime_type,
file_size=video.size,
file_name=file_name,
date=video.date,
client=client
)

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from .photo_size import PhotoSize
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class VideoNote(Object): class VideoNote(PyrogramType):
"""This object represents a video message (available in Telegram apps as of v.4.0). """This object represents a video message (available in Telegram apps as of v.4.0).
Args: Args:
@ -45,18 +51,18 @@ class VideoNote(Object):
Date the video note was sent in Unix time. Date the video note was sent in Unix time.
""" """
ID = 0xb0700010 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
length: int,
duration: int,
thumb: PhotoSize = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
super().__init__(client)
def __init__(
self,
file_id: str,
length: int,
duration: int,
thumb=None,
mime_type: str = None,
file_size: int = None,
date: int = None
):
self.file_id = file_id self.file_id = file_id
self.thumb = thumb self.thumb = thumb
self.mime_type = mime_type self.mime_type = mime_type
@ -64,3 +70,24 @@ class VideoNote(Object):
self.date = date self.date = date
self.length = length self.length = length
self.duration = duration self.duration = duration
@staticmethod
def _parse(client, video_note: types.Document, video_attributes: types.DocumentAttributeVideo) -> "VideoNote":
return VideoNote(
file_id=encode(
pack(
"<iiqq",
13,
video_note.dc_id,
video_note.id,
video_note.access_hash
)
),
length=video_attributes.w,
duration=video_attributes.duration,
thumb=PhotoSize._parse(client, video_note.thumb),
file_size=video_note.size,
mime_type=video_note.mime_type,
date=video_note.date,
client=client
)

View file

@ -16,10 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class Voice(Object): class Voice(PyrogramType):
"""This object represents a voice note. """This object represents a voice note.
Args: Args:
@ -42,19 +47,40 @@ class Voice(Object):
Date the voice was sent in Unix time. Date the voice was sent in Unix time.
""" """
ID = 0xb0700009 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
file_id: str,
duration: int,
waveform: bytes = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
super().__init__(client)
def __init__(
self,
file_id: str,
duration: int,
waveform: bytes = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
self.file_id = file_id self.file_id = file_id
self.duration = duration self.duration = duration
self.waveform = waveform self.waveform = waveform
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
self.date = date self.date = date
@staticmethod
def _parse(client, voice: types.Document, attributes: types.DocumentAttributeAudio) -> "Voice":
return Voice(
file_id=encode(
pack(
"<iiqq",
3,
voice.dc_id,
voice.id,
voice.access_hash
)
),
duration=attributes.duration,
mime_type=voice.mime_type,
file_size=voice.size,
waveform=attributes.waveform,
date=voice.date,
client=client
)

View file

@ -0,0 +1,58 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
from collections import OrderedDict
from json import dumps, JSONEncoder
class PyrogramType:
def __init__(self, client):
self._client = client
def __str__(self):
return dumps(self, cls=Encoder, indent=4)
def __getitem__(self, item):
return getattr(self, item)
def remove_none(obj):
if isinstance(obj, (list, tuple, set)):
return type(obj)(remove_none(x) for x in obj if x is not None)
elif isinstance(obj, dict):
return type(obj)((remove_none(k), remove_none(v)) for k, v in obj.items() if k is not None and v is not None)
else:
return obj
class Encoder(JSONEncoder):
def default(self, o: PyrogramType):
try:
content = {
i: getattr(o, i)
for i in filter(lambda x: not x.startswith("_"), o.__dict__)
}
except AttributeError:
return repr(o)
return remove_none(
OrderedDict(
[("_", "pyrogram." + o.__class__.__name__)]
+ [i for i in content.items()]
)
)

View file

@ -1,94 +0,0 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object
class Update(Object):
"""This object represents an incoming update.
At most one of the optional parameters can be present in any given update.
Args:
message (:obj:`Message <pyrogram.Message>`, *optional*):
New incoming message of any kind text, photo, sticker, etc.
edited_message (:obj:`Message <pyrogram.Message>`, *optional*):
New version of a message that is known to the bot and was edited.
deleted_messages (:obj:`Messages <pyrogram.Messages>`, *optional*):
Deleted messages.
channel_post (:obj:`Message <pyrogram.Message>`, *optional*):
New incoming channel post of any kind text, photo, sticker, etc.
edited_channel_post (:obj:`Message <pyrogram.Message>`, *optional*):
New version of a channel post that is known to the bot and was edited.
deleted_channel_posts (:obj:`Messages <pyrogram.Messages>`, *optional*):
Deleted channel posts.
inline_query (:obj:`InlineQuery <pyrogram.InlineQuery>`, *optional*):
New incoming inline query.
chosen_inline_result (:obj:`ChosenInlineResult <pyrogram.ChosenInlineResult>`, *optional*):
The result of an inline query that was chosen by a user and sent to their chat partner.
Please see our documentation on the feedback collecting for details on how to enable these updates
for your bot.
callback_query (:obj:`CallbackQuery <pyrogram.CallbackQuery>`, *optional*):
New incoming callback query.
shipping_query (:obj:`ShippingQuery <pyrogram.ShippingQuery>`, *optional*):
New incoming shipping query. Only for invoices with flexible price.
pre_checkout_query (:obj:`PreCheckoutQuery <pyrogram.PreCheckoutQuery>`, *optional*):
New incoming pre-checkout query. Contains full information about checkout.
user_status (:obj:`UserStatus <pyrogram.UserStatus>`, *optional*):
User status (last seen date) update.
"""
ID = 0xb0700000
def __init__(
self,
message=None,
edited_message=None,
deleted_messages=None,
channel_post=None,
edited_channel_post=None,
deleted_channel_posts=None,
inline_query=None,
chosen_inline_result=None,
callback_query=None,
shipping_query=None,
pre_checkout_query=None,
user_status=None
):
self.message = message
self.edited_message = edited_message
self.deleted_messages = deleted_messages
self.channel_post = channel_post
self.edited_channel_post = edited_channel_post
self.deleted_channel_posts = deleted_channel_posts
self.inline_query = inline_query
self.chosen_inline_result = chosen_inline_result
self.callback_query = callback_query
self.shipping_query = shipping_query
self.pre_checkout_query = pre_checkout_query
self.user_status = user_status

View file

@ -16,10 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from .chat_photo import ChatPhoto
from ..pyrogram_type import PyrogramType
class Chat(Object): class Chat(PyrogramType):
"""This object represents a chat. """This object represents a chat.
Args: Args:
@ -74,26 +77,26 @@ class Chat(Object):
The reason why this chat might be unavailable to some users. The reason why this chat might be unavailable to some users.
""" """
ID = 0xb0700002 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
id: int,
type: str,
title: str = None,
username: str = None,
first_name: str = None,
last_name: str = None,
all_members_are_administrators: bool = None,
photo: ChatPhoto = None,
description: str = None,
invite_link: str = None,
pinned_message=None,
sticker_set_name: str = None,
can_set_sticker_set: bool = None,
members_count: int = None,
restriction_reason: str = None):
super().__init__(client)
def __init__(
self,
id: int,
type: str,
title: str = None,
username: str = None,
first_name: str = None,
last_name: str = None,
all_members_are_administrators: bool = None,
photo=None,
description: str = None,
invite_link: str = None,
pinned_message=None,
sticker_set_name: str = None,
can_set_sticker_set: bool = None,
members_count: int = None,
restriction_reason: str = None
):
self.id = id self.id = id
self.type = type self.type = type
self.title = title self.title = title
@ -109,3 +112,100 @@ class Chat(Object):
self.can_set_sticker_set = can_set_sticker_set self.can_set_sticker_set = can_set_sticker_set
self.members_count = members_count self.members_count = members_count
self.restriction_reason = restriction_reason self.restriction_reason = restriction_reason
@staticmethod
def _parse_user_chat(client, user: types.User) -> "Chat":
return Chat(
id=user.id,
type="private",
username=user.username,
first_name=user.first_name,
last_name=user.last_name,
photo=ChatPhoto._parse(client, user.photo),
restriction_reason=user.restriction_reason,
client=client
)
@staticmethod
def _parse_chat_chat(client, chat: types.Chat) -> "Chat":
admins_enabled = getattr(chat, "admins_enabled", None)
if admins_enabled is not None:
admins_enabled = not admins_enabled
return Chat(
id=-chat.id,
type="group",
title=chat.title,
all_members_are_administrators=admins_enabled,
photo=ChatPhoto._parse(client, getattr(chat, "photo", None)),
client=client
)
@staticmethod
def _parse_channel_chat(client, channel: types.Channel) -> "Chat":
return Chat(
id=int("-100" + str(channel.id)),
type="supergroup" if channel.megagroup else "channel",
title=channel.title,
username=getattr(channel, "username", None),
photo=ChatPhoto._parse(client, getattr(channel, "photo", None)),
restriction_reason=getattr(channel, "restriction_reason", None),
client=client
)
@staticmethod
def _parse(client, message: types.Message or types.MessageService, users: dict, chats: dict) -> "Chat":
if isinstance(message.to_id, types.PeerUser):
return Chat._parse_user_chat(client, users[message.to_id.user_id if message.out else message.from_id])
if isinstance(message.to_id, types.PeerChat):
return Chat._parse_chat_chat(client, chats[message.to_id.chat_id])
return Chat._parse_channel_chat(client, chats[message.to_id.channel_id])
@staticmethod
def _parse_dialog(client, peer, users: dict, chats: dict):
if isinstance(peer, types.PeerUser):
return Chat._parse_user_chat(client, users[peer.user_id])
elif isinstance(peer, types.PeerChat):
return Chat._parse_chat_chat(client, chats[peer.chat_id])
else:
return Chat._parse_channel_chat(client, chats[peer.channel_id])
@staticmethod
def _parse_full(client, chat_full: types.messages.ChatFull or types.UserFull) -> "Chat":
if isinstance(chat_full, types.UserFull):
parsed_chat = Chat._parse_user_chat(client, chat_full.user)
parsed_chat.description = chat_full.about
else:
full_chat = chat_full.full_chat
chat = None
for i in chat_full.chats:
if full_chat.id == i.id:
chat = i
if isinstance(full_chat, types.ChatFull):
parsed_chat = Chat._parse_chat_chat(client, chat)
if isinstance(full_chat.participants, types.ChatParticipants):
parsed_chat.members_count = len(full_chat.participants.participants)
else:
parsed_chat = Chat._parse_channel_chat(client, chat)
parsed_chat.members_count = full_chat.participants_count
parsed_chat.description = full_chat.about or None
# TODO: Add StickerSet type
parsed_chat.can_set_sticker_set = full_chat.can_set_stickers
parsed_chat.sticker_set_name = full_chat.stickerset
if full_chat.pinned_msg_id:
parsed_chat.pinned_message = client.get_messages(
parsed_chat.id,
message_ids=full_chat.pinned_msg_id
)
if isinstance(full_chat.exported_invite, types.ChatInviteExported):
parsed_chat.invite_link = full_chat.exported_invite.link
return parsed_chat

View file

@ -16,10 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
class ChatMember(Object): class ChatMember(PyrogramType):
"""This object contains information about one member of a chat. """This object contains information about one member of a chat.
Args: Args:
@ -78,40 +81,92 @@ class ChatMember(Object):
Restricted only. True, if user may add web page previews to his messages, implies can_send_media_messages. Restricted only. True, if user may add web page previews to his messages, implies can_send_media_messages.
""" """
ID = 0xb0700016 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
user: "pyrogram.User",
status: str,
until_date: int = None,
can_be_edited: bool = None,
can_change_info: bool = None,
can_post_messages: bool = None,
can_edit_messages: bool = None,
can_delete_messages: bool = None,
can_invite_users: bool = None,
can_restrict_members: bool = None,
can_pin_messages: bool = None,
can_promote_members: bool = None,
can_send_messages: bool = None,
can_send_media_messages: bool = None,
can_send_other_messages: bool = None,
can_add_web_page_previews: bool = None):
super().__init__(client)
def __init__( self.user = user
self, self.status = status
user, self.until_date = until_date
status: str, self.can_be_edited = can_be_edited
until_date: int = None, self.can_change_info = can_change_info
can_be_edited: bool = None, self.can_post_messages = can_post_messages
can_change_info: bool = None, self.can_edit_messages = can_edit_messages
can_post_messages: bool = None, self.can_delete_messages = can_delete_messages
can_edit_messages: bool = None, self.can_invite_users = can_invite_users
can_delete_messages: bool = None, self.can_restrict_members = can_restrict_members
can_invite_users: bool = None, self.can_pin_messages = can_pin_messages
can_restrict_members: bool = None, self.can_promote_members = can_promote_members
can_pin_messages: bool = None, self.can_send_messages = can_send_messages
can_promote_members: bool = None, self.can_send_media_messages = can_send_media_messages
can_send_messages: bool = None, self.can_send_other_messages = can_send_other_messages
can_send_media_messages: bool = None, self.can_add_web_page_previews = can_add_web_page_previews
can_send_other_messages: bool = None,
can_add_web_page_previews: bool = None @staticmethod
): def _parse(client, member, user) -> "ChatMember":
self.user = user # User user = pyrogram.User._parse(client, user)
self.status = status # string
self.until_date = until_date # flags.0?int if isinstance(member, (types.ChannelParticipant, types.ChannelParticipantSelf, types.ChatParticipant)):
self.can_be_edited = can_be_edited # flags.1?Bool return ChatMember(user=user, status="member", client=client)
self.can_change_info = can_change_info # flags.2?Bool
self.can_post_messages = can_post_messages # flags.3?Bool if isinstance(member, (types.ChannelParticipantCreator, types.ChatParticipantCreator)):
self.can_edit_messages = can_edit_messages # flags.4?Bool return ChatMember(user=user, status="creator", client=client)
self.can_delete_messages = can_delete_messages # flags.5?Bool
self.can_invite_users = can_invite_users # flags.6?Bool if isinstance(member, types.ChatParticipantAdmin):
self.can_restrict_members = can_restrict_members # flags.7?Bool return ChatMember(user=user, status="administrator", client=client)
self.can_pin_messages = can_pin_messages # flags.8?Bool
self.can_promote_members = can_promote_members # flags.9?Bool if isinstance(member, types.ChannelParticipantAdmin):
self.can_send_messages = can_send_messages # flags.10?Bool rights = member.admin_rights
self.can_send_media_messages = can_send_media_messages # flags.11?Bool
self.can_send_other_messages = can_send_other_messages # flags.12?Bool return ChatMember(
self.can_add_web_page_previews = can_add_web_page_previews # flags.13?Bool user=user,
status="administrator",
can_be_edited=member.can_edit,
can_change_info=rights.change_info,
can_post_messages=rights.post_messages,
can_edit_messages=rights.edit_messages,
can_delete_messages=rights.delete_messages,
can_invite_users=rights.invite_users or rights.invite_link,
can_restrict_members=rights.ban_users,
can_pin_messages=rights.pin_messages,
can_promote_members=rights.add_admins,
client=client
)
if isinstance(member, types.ChannelParticipantBanned):
rights = member.banned_rights
chat_member = ChatMember(
user=user,
status="kicked" if rights.view_messages else "restricted",
until_date=0 if rights.until_date == (1 << 31) - 1 else rights.until_date,
client=client
)
if chat_member.status == "restricted":
chat_member.can_send_messages = not rights.send_messages
chat_member.can_send_media_messages = not rights.send_media
chat_member.can_send_other_messages = (
not rights.send_stickers or not rights.send_gifs or
not rights.send_games or not rights.send_inline
)
chat_member.can_add_web_page_previews = not rights.embed_links
return chat_member

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List
import pyrogram
from pyrogram.api import types
from .chat_member import ChatMember
from .user import User
from ..pyrogram_type import PyrogramType
class ChatMembers(Object): class ChatMembers(PyrogramType):
"""This object contains information about the members list of a chat. """This object contains information about the members list of a chat.
Args: Args:
@ -30,8 +36,34 @@ class ChatMembers(Object):
Requested chat members. Requested chat members.
""" """
ID = 0xb0700030 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
total_count: int,
chat_members: List[ChatMember]):
super().__init__(client)
def __init__(self, total_count: int, chat_members: list):
self.total_count = total_count self.total_count = total_count
self.chat_members = chat_members self.chat_members = chat_members
@staticmethod
def _parse(client, members):
users = {i.id: i for i in members.users}
chat_members = []
if isinstance(members, types.channels.ChannelParticipants):
total_count = members.count
members = members.participants
else:
members = members.full_chat.participants.participants
total_count = len(members)
for member in members:
user = User._parse(client, users[member.user_id])
chat_members.append(ChatMember._parse(client, member, user))
return ChatMembers(
total_count=total_count,
chat_members=chat_members,
client=client
)

View file

@ -16,10 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from struct import pack
import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
from ...ext.utils import encode
class ChatPhoto(Object): class ChatPhoto(PyrogramType):
"""This object represents a chat photo. """This object represents a chat photo.
Args: Args:
@ -30,8 +35,43 @@ class ChatPhoto(Object):
Unique file identifier of big (640x640) chat photo. This file_id can be used only for photo download. Unique file identifier of big (640x640) chat photo. This file_id can be used only for photo download.
""" """
ID = 0xb0700015 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
small_file_id: str,
big_file_id: str):
super().__init__(client)
def __init__(self, small_file_id: str, big_file_id: str): self.small_file_id = small_file_id
self.small_file_id = small_file_id # string self.big_file_id = big_file_id
self.big_file_id = big_file_id # string
@staticmethod
def _parse(client, chat_photo: types.UserProfilePhoto or types.ChatPhoto):
if not isinstance(chat_photo, (types.UserProfilePhoto, types.ChatPhoto)):
return None
if not isinstance(chat_photo.photo_small, types.FileLocation):
return None
if not isinstance(chat_photo.photo_big, types.FileLocation):
return None
photo_id = getattr(chat_photo, "photo_id", 0)
loc_small = chat_photo.photo_small
loc_big = chat_photo.photo_big
return ChatPhoto(
small_file_id=encode(
pack(
"<iiqqqqi",
1, loc_small.dc_id, photo_id, 0, loc_small.volume_id, loc_small.secret, loc_small.local_id
)
),
big_file_id=encode(
pack(
"<iiqqqqi",
1, loc_big.dc_id, photo_id, 0, loc_big.volume_id, loc_big.secret, loc_big.local_id
)
),
client=client
)

View file

@ -16,10 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from ..pyrogram_type import PyrogramType
from ..user_and_chats import Chat
class Dialog(Object): class Dialog(PyrogramType):
"""This object represents a dialog. """This object represents a dialog.
Args: Args:
@ -41,18 +45,42 @@ class Dialog(Object):
is_pinned (``bool``): is_pinned (``bool``):
True, if the dialog is pinned. True, if the dialog is pinned.
""" """
ID = 0xb0700028
def __init__(self, def __init__(self,
chat, *,
top_message, client: "pyrogram.client.ext.BaseClient",
chat: Chat,
top_message: "pyrogram.Message",
unread_messages_count: int, unread_messages_count: int,
unread_mentions_count: int, unread_mentions_count: int,
unread_mark: bool, unread_mark: bool,
is_pinned: bool): is_pinned: bool):
super().__init__(client)
self.chat = chat self.chat = chat
self.top_message = top_message self.top_message = top_message
self.unread_messages_count = unread_messages_count self.unread_messages_count = unread_messages_count
self.unread_mentions_count = unread_mentions_count self.unread_mentions_count = unread_mentions_count
self.unread_mark = unread_mark self.unread_mark = unread_mark
self.is_pinned = is_pinned self.is_pinned = is_pinned
@staticmethod
def _parse(client, dialog, messages, users, chats) -> "Dialog":
chat_id = dialog.peer
if isinstance(chat_id, types.PeerUser):
chat_id = chat_id.user_id
elif isinstance(chat_id, types.PeerChat):
chat_id = -chat_id.chat_id
else:
chat_id = int("-100" + str(chat_id.channel_id))
return Dialog(
chat=Chat._parse_dialog(client, dialog.peer, users, chats),
top_message=messages.get(chat_id),
unread_messages_count=dialog.unread_count,
unread_mentions_count=dialog.unread_mentions_count,
unread_mark=dialog.unread_mark,
is_pinned=dialog.pinned,
client=client
)

View file

@ -16,10 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object from typing import List
import pyrogram
from pyrogram.api import types
from .dialog import Dialog
from ..messages_and_media import Message
from ..pyrogram_type import PyrogramType
class Dialogs(Object): class Dialogs(PyrogramType):
"""This object represents a user's dialogs chunk """This object represents a user's dialogs chunk
Args: Args:
@ -29,8 +35,41 @@ class Dialogs(Object):
dialogs (List of :obj:`Dialog <pyrogram.Dialog>`): dialogs (List of :obj:`Dialog <pyrogram.Dialog>`):
Requested dialogs. Requested dialogs.
""" """
ID = 0xb0700029
def __init__(self, total_count: int, dialogs: list): def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
total_count: int,
dialogs: List[Dialog]):
super().__init__(client)
self.total_count = total_count self.total_count = total_count
self.dialogs = dialogs self.dialogs = dialogs
@staticmethod
def _parse(client, dialogs) -> "Dialogs":
users = {i.id: i for i in dialogs.users}
chats = {i.id: i for i in dialogs.chats}
messages = {}
for message in dialogs.messages:
to_id = message.to_id
if isinstance(to_id, types.PeerUser):
if message.out:
chat_id = to_id.user_id
else:
chat_id = message.from_id
elif isinstance(to_id, types.PeerChat):
chat_id = -to_id.chat_id
else:
chat_id = int("-100" + str(to_id.channel_id))
messages[chat_id] = Message._parse(client, message, users, chats)
return Dialogs(
total_count=getattr(dialogs, "count", len(dialogs.dialogs)),
dialogs=[Dialog._parse(client, dialog, messages, users, chats) for dialog in dialogs.dialogs],
client=client
)

View file

@ -16,10 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api.core import Object import pyrogram
from pyrogram.api import types
from .chat_photo import ChatPhoto
from .user_status import UserStatus
from ..pyrogram_type import PyrogramType
class User(Object): class User(PyrogramType):
"""This object represents a Telegram user or bot. """This object represents a Telegram user or bot.
Args: Args:
@ -66,25 +70,25 @@ class User(Object):
The reason why this bot might be unavailable to some users. The reason why this bot might be unavailable to some users.
""" """
ID = 0xb0700001 def __init__(self,
*,
client: "pyrogram.client.ext.BaseClient",
id: int,
is_self: bool,
is_contact: bool,
is_mutual_contact: bool,
is_deleted: bool,
is_bot: bool,
first_name: str,
last_name: str = None,
status: UserStatus = None,
username: str = None,
language_code: str = None,
phone_number: str = None,
photo: ChatPhoto = None,
restriction_reason: str = None):
super().__init__(client)
def __init__(
self,
id: int,
is_self: bool,
is_contact: bool,
is_mutual_contact: bool,
is_deleted: bool,
is_bot: bool,
first_name: str,
status=None,
last_name: str = None,
username: str = None,
language_code: str = None,
phone_number: str = None,
photo=None,
restriction_reason: str = None
):
self.id = id self.id = id
self.is_self = is_self self.is_self = is_self
self.is_contact = is_contact self.is_contact = is_contact
@ -92,10 +96,33 @@ class User(Object):
self.is_deleted = is_deleted self.is_deleted = is_deleted
self.is_bot = is_bot self.is_bot = is_bot
self.first_name = first_name self.first_name = first_name
self.status = status
self.last_name = last_name self.last_name = last_name
self.status = status
self.username = username self.username = username
self.language_code = language_code self.language_code = language_code
self.phone_number = phone_number self.phone_number = phone_number
self.photo = photo self.photo = photo
self.restriction_reason = restriction_reason self.restriction_reason = restriction_reason
@staticmethod
def _parse(client, user: types.User) -> "User" or None:
if user is None:
return None
return User(
id=user.id,
is_self=user.is_self,
is_contact=user.contact,
is_mutual_contact=user.mutual_contact,
is_deleted=user.deleted,
is_bot=user.bot,
first_name=user.first_name,
last_name=user.last_name,
status=UserStatus._parse(client, user.status, user.id, user.bot),
username=user.username,
language_code=user.lang_code,
phone_number=user.phone,
photo=ChatPhoto._parse(client, user.photo),
restriction_reason=user.restriction_reason,
client=client
)

Some files were not shown because too many files have changed in this diff Show more