Merge branch 'develop' into asyncio

# Conflicts:
#	pyrogram/client/methods/messages/send_contact.py
This commit is contained in:
Dan 2018-07-16 17:39:54 +02:00
commit 8a69c2d74e
41 changed files with 897 additions and 150 deletions

View File

@ -506,6 +506,7 @@ def start():
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}\n")

View File

@ -63,3 +63,6 @@ WEBPAGE_CURL_FAILED Telegram could not fetch the provided URL
STICKERSET_INVALID The requested sticker set is invalid
PEER_FLOOD The method can't be used because your account is limited
MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters
USER_NOT_MUTUAL_CONTACT The user is not a mutual contact
USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
1 id message
63 STICKERSET_INVALID The requested sticker set is invalid
64 PEER_FLOOD The method can't be used because your account is limited
65 MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters
66 USER_NOT_MUTUAL_CONTACT The user is not a mutual contact
67 USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups
68 API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side

View File

@ -4,3 +4,4 @@ RPC_CALL_FAIL Telegram is having internal problems. Please try again later
RPC_MCGET_FAIL Telegram is having internal problems. Please try again later
PERSISTENT_TIMESTAMP_OUTDATED Telegram is having internal problems. Please try again later
HISTORY_GET_FAILED Telegram is having internal problems. Please try again later
REG_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later
1 id message
4 RPC_MCGET_FAIL Telegram is having internal problems. Please try again later
5 PERSISTENT_TIMESTAMP_OUTDATED Telegram is having internal problems. Please try again later
6 HISTORY_GET_FAILED Telegram is having internal problems. Please try again later
7 REG_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later

View File

@ -68,3 +68,9 @@ Client
get_chat
get_messages
get_history
set_chat_photo
delete_chat_photo
set_chat_title
set_chat_description
pin_chat_message
unpin_chat_message

View File

@ -35,14 +35,12 @@ __version__ = "0.8.0dev1"
from .api.errors import Error
from .client.types import (
Audio, Chat, ChatMember, ChatPhoto, Contact, Document, InputMediaPhoto,
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
InputMediaVideo, InputPhoneContact, Location, Message, MessageEntity,
Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, UserProfilePhotos,
Venue, GIF, Video, VideoNote, Voice, CallbackQuery, Messages
)
from .client.types.reply_markup import (
ForceReply, InlineKeyboardButton, InlineKeyboardMarkup,
KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
Venue, GIF, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup,
ReplyKeyboardRemove
)
from .client import (
Client, ChatAction, ParseMode, Emoji,

View File

@ -1259,8 +1259,6 @@ class Client(Methods, BaseClient):
break
f.write(chunk)
f.flush()
os.fsync(f.fileno())
offset += limit
@ -1343,8 +1341,6 @@ class Client(Methods, BaseClient):
assert h.hash == sha256(cdn_chunk).digest(), "Invalid CDN hash part {}".format(i)
f.write(decrypted_chunk)
f.flush()
os.fsync(f.fileno())
offset += limit

View File

@ -72,6 +72,7 @@ async def ainput(prompt: str = ""):
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",
@ -140,6 +141,10 @@ def parse_chat_photo(photo):
def parse_user(user: types.User) -> pyrogram_types.User or None:
return pyrogram_types.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,
@ -371,6 +376,7 @@ async def parse_messages(
phone_number=media.phone_number,
first_name=media.first_name,
last_name=media.last_name or None,
vcard=media.vcard or None,
user_id=media.user_id or None
)
elif isinstance(media, types.MessageMediaVenue):
@ -412,8 +418,7 @@ async def parse_messages(
duration=audio_attributes.duration,
mime_type=doc.mime_type,
file_size=doc.size,
thumb=parse_thumb(doc.thumb),
file_name=file_name,
waveform=audio_attributes.waveform,
date=doc.date
)
else:
@ -476,7 +481,6 @@ async def parse_messages(
duration=video_attributes.duration,
thumb=parse_thumb(doc.thumb),
file_size=doc.size,
file_name=file_name,
mime_type=doc.mime_type,
date=doc.date
)
@ -938,3 +942,103 @@ def parse_dialog_chat(peer, users: dict, chats: dict):
return parse_chat_chat(chats[peer.chat_id])
else:
return parse_channel_chat(chats[peer.channel_id])
def parse_chat_members(members: types.channels.ChannelParticipants or types.messages.ChatFull):
users = {i.id: i for i in members.users}
parsed_members = []
if isinstance(members, types.channels.ChannelParticipants):
members = members.participants
for member in members:
user = parse_user(users[member.user_id])
if isinstance(member, (types.ChannelParticipant, types.ChannelParticipantSelf)):
parsed_members.append(
pyrogram_types.ChatMember(
user=user,
status="member"
)
)
elif isinstance(member, types.ChannelParticipantCreator):
parsed_members.append(
pyrogram_types.ChatMember(
user=user,
status="creator"
)
)
elif isinstance(member, types.ChannelParticipantAdmin):
rights = member.admin_rights # type: types.ChannelAdminRights
parsed_members.append(
pyrogram_types.ChatMember(
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
)
)
elif isinstance(member, types.ChannelParticipantBanned):
rights = member.banned_rights # type: types.ChannelBannedRights
chat_member = pyrogram_types.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
)
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
parsed_members.append(chat_member)
return pyrogram_types.ChatMembers(
total_count=members.count,
chat_members=parsed_members
)
else:
members = members.full_chat.participants.participants
for member in members:
user = parse_user(users[member.user_id])
if isinstance(member, types.ChatParticipant):
parsed_members.append(
pyrogram_types.ChatMember(
user=user,
status="member"
)
)
elif isinstance(member, types.ChatParticipantCreator):
parsed_members.append(
pyrogram_types.ChatMember(
user=user,
status="creator"
)
)
elif isinstance(member, types.ChatParticipantAdmin):
parsed_members.append(
pyrogram_types.ChatMember(
user=user,
status="administrator"
)
)
return pyrogram_types.ChatMembers(
total_count=len(members),
chat_members=parsed_members
)

View File

@ -16,14 +16,21 @@
# 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 .delete_chat_photo import DeleteChatPhoto
from .export_chat_invite_link import ExportChatInviteLink
from .get_chat import GetChat
from .get_chat_members import GetChatMembers
from .join_chat import JoinChat
from .kick_chat_member import KickChatMember
from .leave_chat import LeaveChat
from .pin_chat_message import PinChatMessage
from .promote_chat_member import PromoteChatMember
from .restrict_chat_member import RestrictChatMember
from .set_chat_description import SetChatDescription
from .set_chat_photo import SetChatPhoto
from .set_chat_title import SetChatTitle
from .unban_chat_member import UnbanChatMember
from .unpin_chat_message import UnpinChatMessage
class Chats(
@ -34,6 +41,13 @@ class Chats(
KickChatMember,
UnbanChatMember,
RestrictChatMember,
PromoteChatMember
PromoteChatMember,
GetChatMembers,
SetChatPhoto,
DeleteChatPhoto,
SetChatTitle,
SetChatDescription,
PinChatMessage,
UnpinChatMessage
):
pass

View File

@ -0,0 +1,64 @@
# 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 import functions, types
from ...ext import BaseClient
class DeleteChatPhoto(BaseClient):
def delete_chat_photo(self, chat_id: int or str):
"""Use this method to delete a chat photo.
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.
Note:
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
setting is off.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
self.send(
functions.messages.EditChatPhoto(
chat_id=peer.chat_id,
photo=types.InputChatPhotoEmpty()
)
)
elif isinstance(peer, types.InputPeerChannel):
self.send(
functions.channels.EditPhoto(
channel=peer,
photo=types.InputChatPhotoEmpty()
)
)
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
return True

View File

@ -25,6 +25,11 @@ class GetChat(BaseClient):
"""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.)
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
Returns:
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.

View File

@ -0,0 +1,79 @@
# 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 import functions, types
from ...ext import BaseClient, utils
class Filters:
ALL = "all"
KICKED = "kicked"
RESTRICTED = "restricted"
BOTS = "bots"
RECENT = "recent"
ADMINISTRATORS = "administrators"
class GetChatMembers(BaseClient):
def get_chat_members(self,
chat_id: int or str,
offset: int = 0,
limit: int = 200,
query: str = "",
filter: str = Filters.ALL):
peer = self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
return utils.parse_chat_members(
self.send(
functions.messages.GetFullChat(
peer.chat_id
)
)
)
elif isinstance(peer, types.InputPeerChannel):
filter = filter.lower()
if filter == Filters.ALL:
filter = types.ChannelParticipantsSearch(q=query)
elif filter == Filters.KICKED:
filter = types.ChannelParticipantsKicked(q=query)
elif filter == Filters.RESTRICTED:
filter = types.ChannelParticipantsBanned(q=query)
elif filter == Filters.BOTS:
filter = types.ChannelParticipantsBots()
elif filter == Filters.RECENT:
filter = types.ChannelParticipantsRecent()
elif filter == Filters.ADMINISTRATORS:
filter = types.ChannelParticipantsAdmins()
else:
raise ValueError("Invalid filter \"{}\"".format(filter))
return utils.parse_chat_members(
self.send(
functions.channels.GetParticipants(
channel=peer,
filter=filter,
offset=offset,
limit=limit,
hash=0
)
)
)
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))

View File

@ -0,0 +1,63 @@
# 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 import functions, types
from ...ext import BaseClient
class PinChatMessage(BaseClient):
def pin_chat_message(self, chat_id: int or str, message_id: int, disable_notification: bool = None):
"""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
the supergroup or "can_edit_messages" admin right in the channel.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_id (``int``):
Identifier of a message to pin.
disable_notification (``bool``):
Pass True, if it is not necessary to send a notification to all chat members about the new pinned
message. Notifications are always disabled in channels.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
"""
peer = self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
self.send(
functions.channels.UpdatePinnedMessage(
channel=peer,
id=message_id,
silent=disable_notification or None
)
)
elif isinstance(peer, types.InputPeerChat):
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
return True

View File

@ -0,0 +1,57 @@
# 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 import functions, types
from ...ext import BaseClient
class SetChatDescription(BaseClient):
def set_chat_description(self, chat_id: int or str, description: str):
"""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.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
description (``str``):
New chat description, 0-255 characters.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
"""
peer = self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
self.send(
functions.channels.EditAbout(
channel=peer,
about=description
)
)
elif isinstance(peer, types.InputPeerChat):
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
return True

View File

@ -0,0 +1,83 @@
# 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/>.
import os
from base64 import b64decode
from struct import unpack
from pyrogram.api import functions, types
from ...ext import BaseClient
class SetChatPhoto(BaseClient):
def set_chat_photo(self, chat_id: int or str, photo: str):
"""Use this method to set a new profile photo for the chat.
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.
Note:
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
setting is off.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
photo (``str``):
New chat photo. You can pass a :class:`Photo` id or a file path to upload a new photo.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)
if os.path.exists(photo):
photo = types.InputChatUploadedPhoto(file=self.save_file(photo))
else:
s = unpack("<qq", b64decode(photo + "=" * (-len(photo) % 4), "-_"))
photo = types.InputChatPhoto(
id=types.InputPhoto(
id=s[0],
access_hash=s[1]
)
)
if isinstance(peer, types.InputPeerChat):
self.send(
functions.messages.EditChatPhoto(
chat_id=peer.chat_id,
photo=photo
)
)
elif isinstance(peer, types.InputPeerChannel):
self.send(
functions.channels.EditPhoto(
channel=peer,
photo=photo
)
)
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
return True

View File

@ -0,0 +1,67 @@
# 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 import functions, types
from ...ext import BaseClient
class SetChatTitle(BaseClient):
def set_chat_title(self, chat_id: int or str, title: str):
"""Use this method to change the title of a chat.
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.
Note:
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
setting is off.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
title (``str``):
New chat title, 1-255 characters.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
self.send(
functions.messages.EditChatTitle(
chat_id=peer.chat_id,
title=title
)
)
elif isinstance(peer, types.InputPeerChannel):
self.send(
functions.channels.EditTitle(
channel=peer,
title=title
)
)
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
return True

View File

@ -0,0 +1,55 @@
# 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 import functions, types
from ...ext import BaseClient
class UnpinChatMessage(BaseClient):
def unpin_chat_message(self, chat_id: int or str):
"""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
right in the supergroup or "can_edit_messages" admin right in the channel.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
"""
peer = self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
self.send(
functions.channels.UpdatePinnedMessage(
channel=peer,
id=0
)
)
elif isinstance(peer, types.InputPeerChat):
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
return True

View File

@ -74,7 +74,10 @@ class DownloadMedia(BaseClient):
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If the message doesn't contain any downloadable media
"""
error_message = "This message doesn't contain any downloadable media"
if isinstance(message, pyrogram_types.Message):
if message.photo:
media = pyrogram_types.Document(
@ -98,7 +101,7 @@ class DownloadMedia(BaseClient):
elif message.gif:
media = message.gif
else:
return
raise ValueError(error_message)
elif isinstance(message, (
pyrogram_types.Photo,
pyrogram_types.PhotoSize,
@ -126,7 +129,7 @@ class DownloadMedia(BaseClient):
mime_type=""
)
else:
return
raise ValueError(error_message)
done = asyncio.Event()
path = [None]

View File

@ -26,7 +26,7 @@ class SendContact(BaseClient):
phone_number: str,
first_name: str,
last_name: str = "",
disable_notification: bool = None,
vcard: str = "", disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None):
"""Use this method to send phone contacts.
@ -47,6 +47,9 @@ class SendContact(BaseClient):
last_name (``str``, *optional*):
Contact's last name.
vcard (``str``, *optional*):
Contact's vCard information.
disable_notification (``bool``, *optional*):
Sends the message silently.
Users will receive a notification with no sound.
@ -68,9 +71,10 @@ class SendContact(BaseClient):
functions.messages.SendMedia(
peer=await self.resolve_peer(chat_id),
media=types.InputMediaContact(
phone_number,
first_name,
last_name
phone_number=phone_number,
first_name=first_name,
last_name=last_name,
vcard=vcard
),
message="",
silent=disable_notification or None,

View File

@ -16,34 +16,26 @@
# 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 .audio import Audio
from .callback_query import CallbackQuery
from .chat import Chat
from .chat_member import ChatMember
from .chat_members import ChatMembers
from .chat_photo import ChatPhoto
from .contact import Contact
from .dialog import Dialog
from .dialogs import Dialogs
from .document import Document
from .gif import GIF
from .input_media_photo import InputMediaPhoto
from .input_media_video import InputMediaVideo
from .input_phone_contact import InputPhoneContact
from .location import Location
from .media import (
Audio, Contact, Document, GIF, Location, Photo, PhotoSize,
Sticker, Venue, Video, VideoNote, Voice, UserProfilePhotos
)
from .message import Message
from .message_entity import MessageEntity
from .messages import Messages
from .photo import Photo
from .photo_size import PhotoSize
from .reply_markup import (
ForceReply, InlineKeyboardButton, InlineKeyboardMarkup,
KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
)
from .sticker import Sticker
from .update import Update
from .user import User
from .user_profile_photos import UserProfilePhotos
from .venue import Venue
from .video import Video
from .video_note import VideoNote
from .voice import Voice

View File

@ -24,15 +24,13 @@ class Chat(Object):
Args:
id (``int``):
Unique identifier for this chat. This number may be greater than 32 bits and some programming
languages may have difficulty/silent defects in interpreting it. But it is smaller than 52 bits,
so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
Unique identifier for this chat.
type (``str``):
Type of chat, can be either "private", "group", "supergroup" or "channel".
title (``str``, *optional*):
Title, for supergroups, channels and group chats.
Title, for supergroups, channels and basic group chats.
username (``str``, *optional*):
Username, for private chats, supergroups and channels if available.
@ -44,25 +42,33 @@ class Chat(Object):
Last name of the other party in a private chat.
all_members_are_administrators (``bool``, *optional*):
True if a group has 'All Members Are Admins' enabled.
True if a basic group has "All Members Are Admins" enabled.
photo (:obj:`ChatPhoto <pyrogram.ChatPhoto>`, *optional*):
Chat photo. Returned only in getChat.
Chat photo. Suitable for downloads only.
description (``str``, *optional*):
Description, for supergroups and channel chats. Returned only in getChat.
Description, for supergroups and channel chats.
Returned only in :meth:`get_chat() <pyrogram.Client.get_chat>`.
invite_link (``str``, *optional*):
Chat invite link, for supergroups and channel chats. Returned only in getChat.
Chat invite link, for supergroups and channel chats.
Returned only in :meth:`get_chat() <pyrogram.Client.get_chat>`.
pinned_message (:obj:`Message <pyrogram.Message>`, *optional*):
Pinned message, for supergroups and channel chats. Returned only in getChat.
Pinned message, for supergroups and channel chats.
Returned only in :meth:`get_chat() <pyrogram.Client.get_chat>`.
sticker_set_name (``str``, *optional*):
For supergroups, name of group sticker set. Returned only in getChat.
For supergroups, name of group sticker set.
Returned only in :meth:`get_chat() <pyrogram.Client.get_chat>`.
can_set_sticker_set (``bool``, *optional*):
True, if the bot can change the group sticker set. Returned only in getChat.
True, if the group sticker set can be changed by you.
Returned only in :meth:`get_chat() <pyrogram.Client.get_chat>`.
members_count (``int``, *optional*):
Chat members count, for groups and channels only.
"""
ID = 0xb0700002

View File

@ -0,0 +1,29 @@
# 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 ChatMembers(Object):
# TODO: Docstrings
ID = 0xb0700030
def __init__(self, total_count: int, chat_members: list):
self.total_count = total_count
self.chat_members = chat_members

View File

@ -20,6 +20,24 @@ from pyrogram.api.core import Object
class Dialog(Object):
"""This object represents a dialog
Args:
chat (:obj:`Chat <pyrogram.Chat>`):
Conversation the dialog belongs to.
top_message (:obj:`Message <pyrogram.Message>`):
The last message sent in the dialog at this time.
unread_messages_count (``int``):
Amount of unread messages in this dialogs.
unread_mentions_count (``int``):
Amount of unread messages containing a mention in this dialog.
unread_mark (``bool``):
True, if the dialog has the unread mark set.
"""
ID = 0xb0700028
def __init__(self,
@ -28,7 +46,6 @@ class Dialog(Object):
unread_messages_count: int,
unread_mentions_count: int,
unread_mark: bool):
# TODO docstrings
self.chat = chat
self.top_message = top_message
self.unread_messages_count = unread_messages_count

View File

@ -20,9 +20,17 @@ from pyrogram.api.core import Object
class Dialogs(Object):
"""This object represents a user's dialogs chunk
Args:
total_count (``int``):
Total number of dialogs the user has.
dialogs (List of :obj:`Dialog <pyrogram.Dialog>`):
Requested dialogs.
"""
ID = 0xb0700029
def __init__(self, total_count: int, dialogs: list):
# TODO docstrings
self.total_count = total_count
self.dialogs = dialogs

View File

@ -0,0 +1,31 @@
# 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 .audio import Audio
from .contact import Contact
from .document import Document
from .gif import GIF
from .location import Location
from .photo import Photo
from .photo_size import PhotoSize
from .sticker import Sticker
from .user_profile_photos import UserProfilePhotos
from .venue import Venue
from .video import Video
from .video_note import VideoNote
from .voice import Voice

View File

@ -65,12 +65,12 @@ class Audio(Object):
performer: str = None,
title: str = None
):
self.file_id = file_id # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.4?int
self.duration = duration # int
self.performer = performer # flags.5?string
self.title = title # flags.6?string
self.file_id = file_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
self.file_size = file_size
self.date = date
self.duration = duration
self.performer = performer
self.title = title

View File

@ -32,14 +32,25 @@ class Contact(Object):
last_name (``str``, *optional*):
Contact's last name.
vcard (``str``, *optional*):
Contact's vCard.
user_id (``int``, *optional*):
Contact's user identifier in Telegram.
"""
ID = 0xb0700011
def __init__(self, phone_number: str, first_name: str, last_name: str = None, user_id=None):
self.phone_number = phone_number # string
self.first_name = first_name # string
self.last_name = last_name # flags.0?string
self.user_id = user_id # flags.1?int
def __init__(
self,
phone_number: str,
first_name: str,
last_name: str = None,
vcard: str = None,
user_id: int = None
):
self.phone_number = phone_number
self.first_name = first_name
self.last_name = last_name
self.vcard = vcard
self.user_id = user_id

View File

@ -20,7 +20,7 @@ from pyrogram.api.core import Object
class Document(Object):
"""This object represents a general file (as opposed to photos, voice messages and audio files).
"""This object represents a general file (as opposed to photos, voice messages, audio files, ...).
Args:
file_id (``str``):
@ -53,9 +53,9 @@ class Document(Object):
file_size: int = None,
date: int = None
):
self.file_id = file_id # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.3?int
self.file_id = file_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
self.file_size = file_size
self.date = date

View File

@ -65,12 +65,12 @@ class GIF(Object):
file_size: int = None,
date: int = None
):
self.file_id = file_id # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.4?int
self.width = width # int
self.height = height # int
self.duration = duration # int
self.file_id = file_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
self.file_size = file_size
self.date = date
self.width = width
self.height = height
self.duration = duration

View File

@ -33,5 +33,5 @@ class Location(Object):
ID = 0xb0700012
def __init__(self, longitude: float, latitude: float):
self.longitude = longitude # double
self.latitude = latitude # double
self.longitude = longitude
self.latitude = latitude

View File

@ -27,10 +27,10 @@ class Photo(Object):
Unique identifier for this photo.
date (``int``):
Date the photo was sent in Unix time
Date the photo was sent in Unix time.
sizes (List of :obj:`PhotoSize <pyrogram.PhotoSize>`):
Available sizes of this photo
Available sizes of this photo.
"""
ID = 0xb0700027

View File

@ -20,7 +20,7 @@ from pyrogram.api.core import Object
class PhotoSize(Object):
"""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:
file_id (``str``):

View File

@ -73,14 +73,14 @@ class Sticker(Object):
set_name: str = None,
mask_position=None
):
self.file_id = file_id # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.4?int
self.width = width # int
self.height = height # int
self.emoji = emoji # flags.5?string
self.set_name = set_name # flags.6?string
self.mask_position = mask_position # flags.7?MaskPosition
self.file_id = file_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
self.file_size = file_size
self.date = date
self.width = width
self.height = height
self.emoji = emoji
self.set_name = set_name
self.mask_position = mask_position

View File

@ -40,7 +40,7 @@ class Venue(Object):
ID = 0xb0700013
def __init__(self, location, title: str, address: str, foursquare_id: str = None):
self.location = location # Location
self.title = title # string
self.address = address # string
self.foursquare_id = foursquare_id # flags.0?string
self.location = location
self.title = title
self.address = address
self.foursquare_id = foursquare_id

View File

@ -65,12 +65,12 @@ class Video(Object):
file_size: int = None,
date: int = None
):
self.file_id = file_id # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.4?int
self.width = width # int
self.height = height # int
self.duration = duration # int
self.file_id = file_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
self.file_size = file_size
self.date = date
self.width = width
self.height = height
self.duration = duration

View File

@ -35,9 +35,6 @@ class VideoNote(Object):
thumb (:obj:`PhotoSize <pyrogram.PhotoSize>`, *optional*):
Video thumbnail.
file_name (``str``, *optional*):
Video note file name.
mime_type (``str``, *optional*):
MIME type of the file as defined by sender.
@ -56,16 +53,14 @@ class VideoNote(Object):
length: 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 # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.4?int
self.length = length # int
self.duration = duration # int
self.file_id = file_id
self.thumb = thumb
self.mime_type = mime_type
self.file_size = file_size
self.date = date
self.length = length
self.duration = duration

View File

@ -29,11 +29,8 @@ class Voice(Object):
duration (``int``):
Duration of the audio in seconds as defined by sender.
thumb (:obj:`PhotoSize <pyrogram.PhotoSize>`, *optional*):
Voice thumbnail.
file_name (``str``, *optional*):
Voice file name.
waveform (``bytes``, *optional*):
Voice waveform.
mime_type (``str``, *optional*):
MIME type of the file as defined by sender.
@ -51,15 +48,13 @@ class Voice(Object):
self,
file_id: str,
duration: int,
thumb=None,
file_name: str = None,
waveform: bytes = None,
mime_type: str = None,
file_size: int = None,
date: int = None):
self.file_id = file_id # string
self.thumb = thumb # flags.0?PhotoSize
self.file_name = file_name # flags.1?string
self.mime_type = mime_type # flags.2?string
self.file_size = file_size # flags.3?int
self.date = date # flags.4?int
self.duration = duration # int
self.file_id = file_id
self.duration = duration
self.waveform = waveform
self.mime_type = mime_type
self.file_size = file_size
self.date = date

View File

@ -27,9 +27,6 @@ class Message(Object):
message_id (``int``):
Unique message identifier inside this chat.
client (:obj:`Client <pyrogram.Client>`, *optional*):
The client instance this message is bound to.
date (``int``, *optional*):
Date the message was sent in Unix time.
@ -574,3 +571,39 @@ class Message(Object):
raise ValueError("This button is not supported yet")
else:
raise ValueError("The message doesn't contain any keyboard")
def download(self, file_name: str = "", block: bool = True):
"""Use this method as a shortcut for:
.. code-block:: python
client.download_media(message)
Example:
.. code-block:: python
message.download()
Args:
file_name (``str``, *optional*):
A custom *file_name* to be used instead of the one provided by Telegram.
By default, all files are downloaded in the *downloads* folder in your working directory.
You can also specify a path for downloading files in a custom location: paths that end with "/"
are considered directories. All non-existent folders will be created automatically.
block (``bool``, *optional*):
Blocks the code execution until the file has been downloaded.
Defaults to True.
Returns:
On success, the absolute path of the downloaded file as string is returned, None otherwise.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If the message doesn't contain any downloadable media
"""
return self._client.download_media(
message=self,
file_name=file_name,
block=block
)

View File

@ -26,9 +26,9 @@ class MessageEntity(Object):
Args:
type (``str``):
Type of the entity.
Can be mention (@username), hashtag, bot_command, url, email, bold (bold text), italic (italic text),
code (monowidth string), pre (monowidth block), text_link (for clickable text URLs),
text_mention (for users without usernames).
Can be "mention" (@username), "hashtag", "cashtag", "bot_command", "url", "email", "bold" (bold text),
italic (italic text), "code" (monowidth string), "pre" (monowidth block), "text_link" (for clickable text
URLs), "text_mention" (for users without usernames).
offset (``int``):
Offset in UTF-16 code units to the start of the entity.
@ -45,9 +45,16 @@ class MessageEntity(Object):
ID = 0xb0700004
def __init__(self, type: str, offset: int, length: int, url: str = None, user=None):
self.type = type # string
self.offset = offset # int
self.length = length # int
self.url = url # flags.0?string
self.user = user # flags.1?User
def __init__(
self,
type: str,
offset: int,
length: int,
url: str = None,
user=None
):
self.type = type
self.offset = offset
self.length = length
self.url = url
self.user = user

View File

@ -33,5 +33,5 @@ class Messages(Object):
ID = 0xb0700026
def __init__(self, total_count: int, messages: list):
self.total_count = total_count # int
self.messages = messages # Vector<Vector<PhotoSize>>
self.total_count = total_count
self.messages = messages

View File

@ -26,6 +26,18 @@ class User(Object):
id (``int``):
Unique identifier for this user or bot.
is_self(``bool``):
True, if this user is you yourself.
is_contact(``bool``):
True, if this user is in your contacts.
is_mutual_contact(``bool``):
True, if you both have each other's contact.
is_deleted(``bool``):
True, if this user is deleted.
is_bot (``bool``):
True, if this user is a bot.
@ -42,10 +54,10 @@ class User(Object):
IETF language tag of the user's language.
phone_number (``str``, *optional*):
User's or bot's phone number.
User's phone number.
photo (:obj:`ChatPhoto <pyrogram.ChatPhoto>`, *optional*):
User's or bot's current profile photo.
User's or bot's current profile photo. Suitable for downloads only.
"""
ID = 0xb0700001
@ -53,6 +65,10 @@ class User(Object):
def __init__(
self,
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,
@ -62,6 +78,10 @@ class User(Object):
photo=None
):
self.id = id
self.is_self = is_self
self.is_contact = is_contact
self.is_mutual_contact = is_mutual_contact
self.is_deleted = is_deleted
self.is_bot = is_bot
self.first_name = first_name
self.last_name = last_name