2
0
mirror of https://github.com/pyrogram/pyrogram synced 2025-08-30 13:57:54 +00:00

Merge branch 'layer-104' into develop

This commit is contained in:
Dan
2019-09-07 12:47:25 +02:00
13 changed files with 824 additions and 151 deletions

View File

@@ -1,4 +1,4 @@
// https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/scheme.tl // https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/Resources/tl/api.tl
/////////////////////////////// ///////////////////////////////
///////// Main application API ///////// Main application API
@@ -101,11 +101,11 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat; chatEmpty#9ba2d800 id:int = Chat;
chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#7328bdb id:int title:string = Chat; chatForbidden#7328bdb id:int title:string = Chat;
channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull; chatFull#1b7c9db3 flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
channelFull#10916653 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation pts:int = ChatFull; channelFull#2d895c74 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int pts:int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@@ -172,11 +172,10 @@ photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
geoPointEmpty#1117dd5f = GeoPoint; geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode;
auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization;
auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
@@ -353,7 +352,7 @@ config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:fla
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate; help.appUpdate#1da7158f flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate;
help.inviteText#18cb9f78 message:string = help.InviteText; help.inviteText#18cb9f78 message:string = help.InviteText;
@@ -496,6 +495,7 @@ chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:f
inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet; stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
@@ -559,8 +559,8 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = ChannelParticipant;
channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant; channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
@@ -761,7 +761,7 @@ payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password
payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo;
payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult;
payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult;
payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt;
@@ -828,6 +828,7 @@ channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBa
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction; channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@@ -1003,7 +1004,7 @@ inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
account.wallPapersNotModified#1c199183 = account.WallPapers; account.wallPapersNotModified#1c199183 = account.WallPapers;
account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers; account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings; codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings; wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings;
@@ -1050,7 +1051,7 @@ invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool; auth.logOut#5717da40 = Bool;
auth.resetAuthorizations#9fab0d1a = Bool; auth.resetAuthorizations#9fab0d1a = Bool;
@@ -1269,7 +1270,7 @@ photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.getFile#b15a9afc flags:# precise:flags.0?true location:InputFileLocation offset:int limit:int = upload.File;
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;
upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile;
@@ -1307,7 +1308,7 @@ channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channe
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates; channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates; channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
@@ -1330,6 +1331,7 @@ channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool;
channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates; channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates;
channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool;
channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
@@ -1364,4 +1366,4 @@ langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLangua
folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates; folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
folders.deleteFolder#1c295881 folder_id:int = Updates; folders.deleteFolder#1c295881 folder_id:int = Updates;
// LAYER 103 // LAYER 104

View File

@@ -128,10 +128,10 @@ def pyrogram_api():
utilities=""" utilities="""
Utilities Utilities
start start
stop
restart
idle idle
stop
run run
restart
add_handler add_handler
remove_handler remove_handler
stop_transmission stop_transmission
@@ -249,6 +249,22 @@ def pyrogram_api():
set_game_score set_game_score
get_game_high_scores get_game_high_scores
""", """,
authorization="""
Authorization
connect
disconnect
initialize
terminate
send_code
resend_code
sign_in
sign_up
get_password_hint
check_password
send_recovery_code
recover_password
accept_terms_of_service
""",
advanced=""" advanced="""
Advanced Advanced
send send
@@ -349,6 +365,11 @@ def pyrogram_api():
InputMessageContent InputMessageContent
InputMessageContent InputMessageContent
InputTextMessageContent InputTextMessageContent
""",
authorization="""
Authorization
SentCode
TermsOfService
""" """
) )

View File

@@ -106,10 +106,24 @@ Bots
{bots} {bots}
Authorization
-------------
.. autosummary::
:nosignatures:
{authorization}
.. toctree::
:hidden:
{authorization}
Advanced Advanced
-------- --------
Learn more about these methods at :doc:`Advanced Usage <../../topics/advanced-usage>`. Methods used only when dealing with the raw Telegram API.
Learn more about how to use the raw API at :doc:`Advanced Usage <../../topics/advanced-usage>`.
.. autosummary:: .. autosummary::
:nosignatures: :nosignatures:

View File

@@ -92,4 +92,17 @@ InputMessageContent
.. toctree:: .. toctree::
:hidden: :hidden:
{input_message_content} {input_message_content}
Authorization
-------------
.. autosummary::
:nosignatures:
{authorization}
.. toctree::
:hidden:
{authorization}

View File

@@ -10,4 +10,5 @@ WORKER_BUSY_TOO_LONG_RETRY Telegram is having internal problems. Please try agai
INTERDC_X_CALL_ERROR Telegram is having internal problems at DC{x}. Please try again later INTERDC_X_CALL_ERROR Telegram is having internal problems at DC{x}. Please try again later
INTERDC_X_CALL_RICH_ERROR Telegram is having internal problems at DC{x}. Please try again later INTERDC_X_CALL_RICH_ERROR Telegram is having internal problems at DC{x}. Please try again later
FOLDER_DEAC_AUTOFIX_ALL Telegram is having internal problems. Please try again later FOLDER_DEAC_AUTOFIX_ALL Telegram is having internal problems. Please try again later
MSGID_DECREASE_RETRY Telegram is having internal problems. Please try again later MSGID_DECREASE_RETRY Telegram is having internal problems. Please try again later
MEMBER_OCCUPY_PRIMARY_LOC_FAILED Telegram is having internal problems. Please try again later
1 id message
10 INTERDC_X_CALL_ERROR Telegram is having internal problems at DC{x}. Please try again later
11 INTERDC_X_CALL_RICH_ERROR Telegram is having internal problems at DC{x}. Please try again later
12 FOLDER_DEAC_AUTOFIX_ALL Telegram is having internal problems. Please try again later
13 MSGID_DECREASE_RETRY Telegram is having internal problems. Please try again later
14 MEMBER_OCCUPY_PRIMARY_LOC_FAILED Telegram is having internal problems. Please try again later

View File

@@ -18,7 +18,6 @@
import logging import logging
import math import math
import mimetypes
import os import os
import re import re
import shutil import shutil
@@ -45,12 +44,13 @@ from pyrogram.errors import (
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded, PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned, PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, ChannelPrivate, PhoneNumberOccupied, VolumeLocNotFound, UserMigrate, ChannelPrivate, PhoneNumberOccupied,
PasswordRecoveryNa, PasswordEmpty, AuthBytesInvalid PasswordRecoveryNa, PasswordEmpty, AuthBytesInvalid,
) BadRequest)
from pyrogram.session import Auth, Session from pyrogram.session import Auth, Session
from .ext import utils, Syncer, BaseClient, Dispatcher from .ext import utils, Syncer, BaseClient, Dispatcher
from .methods import Methods from .methods import Methods
from .storage import Storage, FileStorage, MemoryStorage from .storage import Storage, FileStorage, MemoryStorage
from .types import User, SentCode, TermsOfService
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -188,8 +188,6 @@ class Client(Methods, BaseClient):
""" """
terms_of_service_displayed = False
def __init__( def __init__(
self, self,
session_name: Union[str, Storage], session_name: Union[str, Storage],
@@ -280,70 +278,64 @@ class Client(Methods, BaseClient):
self._proxy["enabled"] = bool(value.get("enabled", True)) self._proxy["enabled"] = bool(value.get("enabled", True))
self._proxy.update(value) self._proxy.update(value)
def start(self): def connect(self) -> bool:
"""Start the client. """
Connect the client to Telegram servers.
This method connects the client to Telegram and, in case of new sessions, automatically manages the full login Returns:
process using an interactive prompt (by default). ``bool``: On success, in case the passed-in session is authorized, True is returned. Otherwise, in case
the session needs to be authorized, False is returned.
Has no parameters.
Raises: Raises:
ConnectionError: In case you try to start an already started client. ConnectionError: In case you try to connect an already connected client.
Example:
.. code-block:: python
:emphasize-lines: 4
from pyrogram import Client
app = Client("my_account")
app.start()
... # Call API methods
app.stop()
""" """
if self.is_started: if self.is_connected:
raise ConnectionError("Client has already been started") raise ConnectionError("Client is already connected")
self.load_config() self.load_config()
self.load_session() self.load_session()
self.load_plugins()
self.session = Session(self, self.storage.dc_id, self.storage.auth_key) self.session = Session(self, self.storage.dc_id, self.storage.auth_key)
self.session.start() self.session.start()
self.is_started = True
try: self.is_connected = True
if self.storage.user_id is None:
if self.bot_token is None:
self.storage.is_bot = False
self.authorize_user()
else:
self.storage.is_bot = True
self.authorize_bot()
if not self.storage.is_bot: return bool(self.storage.user_id)
if self.takeout:
self.takeout_id = self.send(functions.account.InitTakeoutSession()).id
log.warning("Takeout session {} initiated".format(self.takeout_id))
now = time.time() def disconnect(self):
"""Disconnect the client from Telegram servers.
if abs(now - self.storage.date) > Client.OFFLINE_SLEEP: Raises:
self.get_initial_dialogs() ConnectionError: In case you try to disconnect an already disconnected client or in case you try to
self.get_contacts() disconnect a client that needs to be terminated first.
else: """
self.send(functions.messages.GetPinnedDialogs(folder_id=0)) if not self.is_connected:
self.get_initial_dialogs_chunk() raise ConnectionError("Client is already disconnected")
else:
self.send(functions.updates.GetState()) if self.is_initialized:
except Exception as e: raise ConnectionError("Can't disconnect an initialized client")
self.is_started = False
self.session.stop() self.session.stop()
raise e self.storage.close()
self.is_connected = False
def initialize(self):
"""Initialize the client by starting up workers.
This method will start updates and download workers.
It will also load plugins and start the internal dispatcher.
Raises:
ConnectionError: In case you try to initialize a disconnected client or in case you try to initialize an
already initialized client.
"""
if not self.is_connected:
raise ConnectionError("Can't initialize a disconnected client")
if self.is_initialized:
raise ConnectionError("Client is already initialized")
self.load_plugins()
for i in range(self.UPDATES_WORKERS): for i in range(self.UPDATES_WORKERS):
self.updates_workers_list.append( self.updates_workers_list.append(
@@ -367,36 +359,21 @@ class Client(Methods, BaseClient):
self.dispatcher.start() self.dispatcher.start()
mimetypes.init()
Syncer.add(self) Syncer.add(self)
return self self.is_initialized = True
def stop(self): def terminate(self):
"""Stop the Client. """Terminate the client by shutting down workers.
This method disconnects the client from Telegram and stops the underlying tasks. This method does the opposite of :meth:`~Client.initialize`.
It will stop the dispatcher and shut down updates and download workers.
Has no parameters.
Raises: Raises:
ConnectionError: In case you try to stop an already stopped client. ConnectionError: In case you try to terminate a client that is already terminated.
Example:
.. code-block:: python
:emphasize-lines: 8
from pyrogram import Client
app = Client("my_account")
app.start()
... # Call API methods
app.stop()
""" """
if not self.is_started: if not self.is_initialized:
raise ConnectionError("Client is already stopped") raise ConnectionError("Client is already terminated")
if self.takeout_id: if self.takeout_id:
self.send(functions.account.FinishTakeoutSession()) self.send(functions.account.FinishTakeoutSession())
@@ -426,8 +403,490 @@ class Client(Methods, BaseClient):
self.media_sessions.clear() self.media_sessions.clear()
self.is_started = False self.is_initialized = False
self.session.stop()
def send_code(self, phone_number: str) -> SentCode:
"""Send the confirmation code to the given phone number.
Parameters:
phone_number (``str``):
Phone number in international format (includes the country prefix).
Returns:
:obj:`SentCode`: On success, an object containing information on the sent confirmation code is returned.
Raises:
BadRequest: In case the phone number is invalid.
"""
phone_number = phone_number.strip(" +")
while True:
try:
r = self.send(
functions.auth.SendCode(
phone_number=phone_number,
api_id=self.api_id,
api_hash=self.api_hash,
settings=types.CodeSettings()
)
)
except (PhoneMigrate, NetworkMigrate) as e:
self.session.stop()
self.storage.dc_id = e.x
self.storage.auth_key = Auth(self, self.storage.dc_id).create()
self.session = Session(self, self.storage.dc_id, self.storage.auth_key)
self.session.start()
else:
return SentCode._parse(r)
def resend_code(self, phone_number: str, phone_code_hash: str) -> SentCode:
"""Re-send the confirmation code using a different type.
The type of the code to be re-sent is specified in the *next_type* attribute of the :obj:`SentCode` object
returned by :meth:`send_code`.
Parameters:
phone_number (``str``):
Phone number in international format (includes the country prefix).
phone_code_hash (``str``):
Confirmation code identifier.
Returns:
:obj:`SentCode`: On success, an object containing information on the re-sent confirmation code is returned.
Raises:
BadRequest: In case the arguments are invalid.
"""
phone_number = phone_number.strip(" +")
r = self.send(
functions.auth.ResendCode(
phone_number=phone_number,
phone_code_hash=phone_code_hash
)
)
return SentCode._parse(r)
def sign_in(self, phone_number: str, phone_code_hash: str, phone_code: str) -> Union[User, TermsOfService, bool]:
"""Authorize a user in Telegram with a valid confirmation code.
Parameters:
phone_number (``str``):
Phone number in international format (includes the country prefix).
phone_code_hash (``str``):
Code identifier taken from the result of :meth:`~Client.send_code`.
phone_code (``str``):
The valid confirmation code you received (either as Telegram message or as SMS in your phone number).
Returns:
:obj:`User` | :obj:`TermsOfService` | bool: On success, in case the authorization completed, the user is
returned. In case the phone number needs to be registered first AND the terms of services accepted (with
:meth:`~Client.accept_terms_of_service`), an object containing them is returned. In case the phone number
needs to be registered, but the terms of services don't need to be accepted, False is returned instead.
Raises:
BadRequest: In case the arguments are invalid.
SessionPasswordNeeded: In case a password is needed to sign in.
"""
phone_number = phone_number.strip(" +")
r = self.send(
functions.auth.SignIn(
phone_number=phone_number,
phone_code_hash=phone_code_hash,
phone_code=phone_code
)
)
if isinstance(r, types.auth.AuthorizationSignUpRequired):
if r.terms_of_service:
return TermsOfService._parse(terms_of_service=r.terms_of_service)
return False
else:
self.storage.user_id = r.user.id
self.storage.is_bot = False
return User._parse(self, r.user)
def sign_up(self, phone_number: str, phone_code_hash: str, first_name: str, last_name: str = "") -> User:
"""Register a new user in Telegram.
Parameters:
phone_number (``str``):
Phone number in international format (includes the country prefix).
phone_code_hash (``str``):
Code identifier taken from the result of :meth:`~Client.send_code`.
first_name (``str``):
New user first name.
last_name (``str``, *optional*):
New user last name. Defaults to "" (empty string).
Returns:
:obj:`User`: On success, the new registered user is returned.
Raises:
BadRequest: In case the arguments are invalid.
"""
phone_number = phone_number.strip(" +")
r = self.send(
functions.auth.SignUp(
phone_number=phone_number,
first_name=first_name,
last_name=last_name,
phone_code_hash=phone_code_hash
)
)
self.storage.user_id = r.user.id
self.storage.is_bot = False
return User._parse(self, r.user)
def sign_in_bot(self, bot_token: str) -> User:
"""Authorize a bot using its bot token generated by BotFather.
Parameters:
bot_token (``str``):
The bot token generated by BotFather
Returns:
:obj:`User`: On success, the bot identity is return in form of a user object.
Raises:
BadRequest: In case the bot token is invalid.
"""
while True:
try:
r = self.send(
functions.auth.ImportBotAuthorization(
flags=0,
api_id=self.api_id,
api_hash=self.api_hash,
bot_auth_token=bot_token
)
)
except UserMigrate as e:
self.session.stop()
self.storage.dc_id = e.x
self.storage.auth_key = Auth(self, self.storage.dc_id).create()
self.session = Session(self, self.storage.dc_id, self.storage.auth_key)
self.session.start()
else:
self.storage.user_id = r.user.id
self.storage.is_bot = True
return User._parse(self, r.user)
def get_password_hint(self) -> str:
"""Get your Two-Step Verification password hint.
Returns:
``str``: On success, the password hint as string is returned.
"""
return self.send(functions.account.GetPassword()).hint
def check_password(self, password: str) -> User:
"""Check your Two-Step Verification password and log in.
Parameters:
password (``str``):
Your Two-Step Verification password.
Returns:
:obj:`User`: On success, the authorized user is returned.
Raises:
BadRequest: In case the password is invalid.
"""
r = self.send(
functions.auth.CheckPassword(
password=compute_check(
self.send(functions.account.GetPassword()),
password
)
)
)
self.storage.user_id = r.user.id
self.storage.is_bot = False
return User._parse(self, r.user)
def send_recovery_code(self) -> str:
"""Send a code to your email to recover your password.
Returns:
``str``: On success, the hidden email pattern is returned and a recovery code is sent to that email.
Raises:
BadRequest: In case no recovery email was set up.
"""
return self.send(
functions.auth.RequestPasswordRecovery()
).email_pattern
def recover_password(self, recovery_code: str) -> User:
"""Recover your password with a recovery code and log in.
Parameters:
recovery_code (``str``):
The recovery code sent via email.
Returns:
:obj:`User`: On success, the authorized user is returned and the Two-Step Verification password reset.
Raises:
BadRequest: In case the recovery code is invalid.
"""
r = self.send(
functions.auth.RecoverPassword(
code=recovery_code
)
)
self.storage.user_id = r.user.id
self.storage.is_bot = False
return User._parse(self, r.user)
def accept_terms_of_service(self, terms_of_service_id: str) -> bool:
"""Accept the given terms of service.
Parameters:
terms_of_service_id (``str``):
The terms of service identifier.
"""
r = self.send(
functions.help.AcceptTermsOfService(
id=types.DataJSON(
data=terms_of_service_id
)
)
)
assert r
return True
def authorize(self) -> User:
if self.bot_token is not None:
return self.sign_in_bot(self.bot_token)
while True:
if self.phone_number is None:
while True:
value = input("Enter phone number or bot token: ")
confirm = input("Is \"{}\" correct? (y/n): ".format(value))
if confirm in ("y", "1"):
break
elif confirm in ("n", "2"):
continue
if ":" in value:
self.bot_token = value
return self.sign_in_bot(value)
else:
self.phone_number = value
try:
sent_code = self.send_code(self.phone_number)
except BadRequest as e:
print(e.MESSAGE)
self.phone_number = None
except FloodWait as e:
print(e.MESSAGE.format(x=e.x))
time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
else:
break
if self.force_sms:
sent_code = self.resend_code(self.phone_number, sent_code.phone_code_hash)
print("The confirmation code has been sent via {}".format(
{
"app": "Telegram app",
"sms": "SMS",
"call": "phone call",
"flash_call": "phone flash call"
}[sent_code.type]
))
while True:
if self.phone_code is None:
self.phone_code = input("Enter confirmation code: ")
try:
signed_in = self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code)
except BadRequest as e:
print(e.MESSAGE)
self.phone_code = None
except SessionPasswordNeeded as e:
print(e.MESSAGE)
while True:
print("Password hint: {}".format(self.get_password_hint()))
if self.password is None:
self.password = input("Enter password (empty to recover): ")
try:
if self.password == "":
confirm = input("Confirm password recovery (y/n): ")
if confirm in ("y", "1"):
email_pattern = self.send_recovery_code()
print("The recovery code has been sent to {}".format(email_pattern))
while True:
recovery_code = input("Enter recovery code: ")
try:
return self.recover_password(recovery_code)
except BadRequest as e:
print(e.MESSAGE)
except FloodWait as e:
print(e.MESSAGE.format(x=e.x))
time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
raise
elif confirm in ("n", "2"):
self.password = None
else:
return self.check_password(self.password)
except BadRequest as e:
print(e.MESSAGE)
self.password = None
except FloodWait as e:
print(e.MESSAGE.format(x=e.x))
time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
raise
except FloodWait as e:
print(e.MESSAGE.format(x=e.x))
time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
else:
break
if isinstance(signed_in, User):
return signed_in
while True:
self.first_name = input("Enter first name: ")
self.last_name = input("Enter last name (empty to skip): ")
try:
signed_up = self.sign_up(
self.phone_number,
sent_code.phone_code_hash,
self.first_name,
self.last_name
)
except BadRequest as e:
print(e.MESSAGE)
self.first_name = None
self.last_name = None
except FloodWait as e:
print(e.MESSAGE.format(x=e.x))
time.sleep(e.x)
else:
break
if isinstance(signed_in, TermsOfService):
print("\n" + signed_in.text + "\n")
self.accept_terms_of_service(signed_in.id)
return signed_up
def start(self):
"""Start the client.
This method connects the client to Telegram and, in case of new sessions, automatically manages the full
authorization process using an interactive prompt.
Returns:
:obj:`Client`: The started client itself.
Raises:
ConnectionError: In case you try to start an already started client.
Example:
.. code-block:: python
:emphasize-lines: 4
from pyrogram import Client
app = Client("my_account")
app.start()
... # Call API methods
app.stop()
"""
is_authorized = self.connect()
try:
if not is_authorized:
self.authorize()
if not self.storage.is_bot and self.takeout:
self.takeout_id = self.send(functions.account.InitTakeoutSession()).id
log.warning("Takeout session {} initiated".format(self.takeout_id))
self.send(functions.updates.GetState())
except Exception as e:
self.disconnect()
raise e
else:
self.initialize()
return self
def stop(self):
"""Stop the Client.
This method disconnects the client from Telegram and stops the underlying tasks.
Returns:
:obj:`Client`: The stopped client itself.
Raises:
ConnectionError: In case you try to stop an already stopped client.
Example:
.. code-block:: python
:emphasize-lines: 8
from pyrogram import Client
app = Client("my_account")
app.start()
... # Call API methods
app.stop()
"""
self.terminate()
self.disconnect()
return self return self
@@ -437,7 +896,8 @@ class Client(Methods, BaseClient):
This method will first call :meth:`~Client.stop` and then :meth:`~Client.start` in a row in order to restart This method will first call :meth:`~Client.stop` and then :meth:`~Client.start` in a row in order to restart
a client using a single method. a client using a single method.
Has no parameters. Returns:
:obj:`Client`: The restarted client itself.
Raises: Raises:
ConnectionError: In case you try to restart a stopped Client. ConnectionError: In case you try to restart a stopped Client.
@@ -462,6 +922,8 @@ class Client(Methods, BaseClient):
self.stop() self.stop()
self.start() self.start()
return self
@staticmethod @staticmethod
def idle(stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)): def idle(stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
"""Block the main script execution until a signal is received. """Block the main script execution until a signal is received.
@@ -525,8 +987,6 @@ class Client(Methods, BaseClient):
sequence. It makes running a client less verbose, but is not suitable in case you want to run more than one sequence. It makes running a client less verbose, but is not suitable in case you want to run more than one
client in a single main script, since idle() will block after starting the own client. client in a single main script, since idle() will block after starting the own client.
Has no parameters.
Raises: Raises:
ConnectionError: In case you try to run an already started client. ConnectionError: In case you try to run an already started client.
@@ -628,8 +1088,6 @@ class Client(Methods, BaseClient):
This method must be called inside a progress callback function in order to stop the transmission at the This method must be called inside a progress callback function in order to stop the transmission at the
desired time. The progress callback is called every time a file chunk is uploaded/downloaded. desired time. The progress callback is called every time a file chunk is uploaded/downloaded.
Has no parameters.
Example: Example:
.. code-block:: python .. code-block:: python
:emphasize-lines: 9 :emphasize-lines: 9
@@ -656,8 +1114,6 @@ class Client(Methods, BaseClient):
More detailed information about session strings can be found at the dedicated page of More detailed information about session strings can be found at the dedicated page of
:doc:`Storage Engines <../../topics/storage-engines>`. :doc:`Storage Engines <../../topics/storage-engines>`.
Has no parameters.
Returns: Returns:
``str``: The session serialized into a printable, url-safe string. ``str``: The session serialized into a printable, url-safe string.
@@ -1211,8 +1667,8 @@ class Client(Methods, BaseClient):
Raises: Raises:
RPCError: In case of a Telegram RPC error. RPCError: In case of a Telegram RPC error.
""" """
if not self.is_started: if not self.is_connected:
raise ConnectionError("Client has not been started") raise ConnectionError("Client has not been started yet")
if self.no_updates: if self.no_updates:
data = functions.InvokeWithoutUpdates(query=data) data = functions.InvokeWithoutUpdates(query=data)
@@ -1444,37 +1900,37 @@ class Client(Methods, BaseClient):
log.warning('[{}] No plugin loaded from "{}"'.format( log.warning('[{}] No plugin loaded from "{}"'.format(
self.session_name, root)) self.session_name, root))
def get_initial_dialogs_chunk(self, offset_date: int = 0): # def get_initial_dialogs_chunk(self, offset_date: int = 0):
while True: # while True:
try: # try:
r = self.send( # r = self.send(
functions.messages.GetDialogs( # functions.messages.GetDialogs(
offset_date=offset_date, # offset_date=offset_date,
offset_id=0, # offset_id=0,
offset_peer=types.InputPeerEmpty(), # offset_peer=types.InputPeerEmpty(),
limit=self.DIALOGS_AT_ONCE, # limit=self.DIALOGS_AT_ONCE,
hash=0, # hash=0,
exclude_pinned=True # exclude_pinned=True
) # )
) # )
except FloodWait as e: # except FloodWait as e:
log.warning("get_dialogs flood: waiting {} seconds".format(e.x)) # log.warning("get_dialogs flood: waiting {} seconds".format(e.x))
time.sleep(e.x) # time.sleep(e.x)
else: # else:
log.info("Total peers: {}".format(self.storage.peers_count)) # log.info("Total peers: {}".format(self.storage.peers_count))
return r # return r
#
def get_initial_dialogs(self): # def get_initial_dialogs(self):
self.send(functions.messages.GetPinnedDialogs(folder_id=0)) # self.send(functions.messages.GetPinnedDialogs(folder_id=0))
#
dialogs = self.get_initial_dialogs_chunk() # dialogs = self.get_initial_dialogs_chunk()
offset_date = utils.get_offset_date(dialogs) # offset_date = utils.get_offset_date(dialogs)
#
while len(dialogs.dialogs) == self.DIALOGS_AT_ONCE: # while len(dialogs.dialogs) == self.DIALOGS_AT_ONCE:
dialogs = self.get_initial_dialogs_chunk(offset_date) # dialogs = self.get_initial_dialogs_chunk(offset_date)
offset_date = utils.get_offset_date(dialogs) # offset_date = utils.get_offset_date(dialogs)
#
self.get_initial_dialogs_chunk() # self.get_initial_dialogs_chunk()
def resolve_peer(self, peer_id: Union[int, str]): def resolve_peer(self, peer_id: Union[int, str]):
"""Get the InputPeer of a known peer id. """Get the InputPeer of a known peer id.
@@ -1495,9 +1951,11 @@ class Client(Methods, BaseClient):
``InputPeer``: On success, the resolved peer id is returned in form of an InputPeer object. ``InputPeer``: On success, the resolved peer id is returned in form of an InputPeer object.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
KeyError: In case the peer doesn't exist in the internal database. KeyError: In case the peer doesn't exist in the internal database.
""" """
if not self.is_connected:
raise ConnectionError("Client has not been started yet")
try: try:
return self.storage.get_peer_by_id(peer_id) return self.storage.get_peer_by_id(peer_id)
except KeyError: except KeyError:
@@ -1678,7 +2136,7 @@ class Client(Methods, BaseClient):
file_part += 1 file_part += 1
if progress: if progress:
progress(self, min(file_part * part_size, file_size), file_size, *progress_args) progress(min(file_part * part_size, file_size), file_size, *progress_args)
except Client.StopTransmission: except Client.StopTransmission:
raise raise
except Exception as e: except Exception as e:
@@ -1813,7 +2271,6 @@ class Client(Methods, BaseClient):
if progress: if progress:
progress( progress(
self,
min(offset, file_size) min(offset, file_size)
if file_size != 0 if file_size != 0
else offset, else offset,
@@ -1896,7 +2353,6 @@ class Client(Methods, BaseClient):
if progress: if progress:
progress( progress(
self,
min(offset, file_size) min(offset, file_size)
if file_size != 0 if file_size != 0
else offset, else offset,

View File

@@ -50,7 +50,6 @@ class BaseClient:
PARENT_DIR = Path(sys.argv[0]).parent PARENT_DIR = Path(sys.argv[0]).parent
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$") INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
DIALOGS_AT_ONCE = 100 DIALOGS_AT_ONCE = 100
UPDATES_WORKERS = 1 UPDATES_WORKERS = 1
DOWNLOAD_WORKERS = 1 DOWNLOAD_WORKERS = 1
@@ -103,7 +102,8 @@ class BaseClient:
self.media_sessions = {} self.media_sessions = {}
self.media_sessions_lock = Lock() self.media_sessions_lock = Lock()
self.is_started = None self.is_connected = None
self.is_initialized = None
self.takeout_id = None self.takeout_id = None

View File

@@ -23,5 +23,6 @@ from .input_message_content import *
from .list import List from .list import List
from .messages_and_media import * from .messages_and_media import *
from .object import Object from .object import Object
from .authorization import *
from .update import * from .update import *
from .user_and_chats import * from .user_and_chats import *

View File

@@ -0,0 +1,22 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 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 .terms_of_service import TermsOfService
from .sent_code import SentCode
__all__ = ["TermsOfService", "SentCode"]

View File

@@ -0,0 +1,86 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 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 types
from ..object import Object
class SentCode(Object):
"""Contains info on a sent confirmation code.
Parameters:
type (``str``):
Type of the current sent code.
Can be *"app"* (code sent via Telegram), *"sms"* (code sent via SMS), *"call"* (code sent via voice call) or
*"flash_call"* (code is in the last 5 digits of the caller's phone number).
phone_code_hash (``str``):
Confirmation code identifier useful for the next authorization steps (either :meth:`~Client.sign_in` or
:meth:`~Client.sign_up`).
next_type (``str``):
Type of the next code to be sent with :meth:`~Client.resend_code`.
Can be *"sms"* (code will be sent via SMS), *"call"* (code will be sent via voice call) or *"flash_call"*
(code will be in the last 5 digits of caller's phone number).
timeout (``int``):
Delay in seconds before calling :meth:`~Client.resend_code`.
"""
def __init__(
self, *,
type: str,
phone_code_hash: str,
next_type: str = None,
timeout: int = None
):
super().__init__()
self.type = type
self.phone_code_hash = phone_code_hash
self.next_type = next_type
self.timeout = timeout
@staticmethod
def _parse(sent_code: types.auth.SentCode) -> "SentCode":
type = sent_code.type
if isinstance(type, types.auth.SentCodeTypeApp):
type = "app"
elif isinstance(type, types.auth.SentCodeTypeSms):
type = "sms"
elif isinstance(type, types.auth.SentCodeTypeCall):
type = "call"
elif isinstance(type, types.auth.SentCodeTypeFlashCall):
type = "flash_call"
next_type = sent_code.next_type
if isinstance(next_type, types.auth.CodeTypeSms):
next_type = "sms"
elif isinstance(next_type, types.auth.CodeTypeCall):
next_type = "call"
elif isinstance(next_type, types.auth.CodeTypeFlashCall):
next_type = "flash_call"
return SentCode(
type=type,
phone_code_hash=sent_code.phone_code_hash,
next_type=next_type,
timeout=sent_code.timeout
)

View File

@@ -0,0 +1,56 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 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 typing import List
from pyrogram.api import types
from ..messages_and_media import MessageEntity
from ..object import Object
class TermsOfService(Object):
"""Telegram's Terms of Service returned by :meth:`~Client.sign_in`.
Parameters:
id (``str``):
Terms of Service identifier.
text (``str``):
Terms of Service text.
entities (List of :obj:`MessageEntity`):
Special entities like URLs that appear in the text.
"""
def __init__(self, *, id: str, text: str, entities: List[MessageEntity]):
super().__init__()
self.id = id
self.text = text
self.entities = entities
@staticmethod
def _parse(terms_of_service: types.help.TermsOfService) -> "TermsOfService":
return TermsOfService(
id=terms_of_service.id.data,
text=terms_of_service.text,
entities=[
MessageEntity._parse(None, entity, {})
for entity in terms_of_service.entities
]
)

View File

@@ -39,6 +39,7 @@ class Connection:
def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 3): def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 3):
self.dc_id = dc_id self.dc_id = dc_id
self.test_mode = test_mode
self.ipv6 = ipv6 self.ipv6 = ipv6
self.proxy = proxy self.proxy = proxy
self.address = DataCenter(dc_id, test_mode, ipv6) self.address = DataCenter(dc_id, test_mode, ipv6)
@@ -59,7 +60,8 @@ class Connection:
self.connection.close() self.connection.close()
time.sleep(1) time.sleep(1)
else: else:
log.info("Connected! DC{} - IPv{} - {}".format( log.info("Connected! {} DC{} - IPv{} - {}".format(
"Test" if self.test_mode else "Production",
self.dc_id, self.dc_id,
"6" if self.ipv6 else "4", "6" if self.ipv6 else "4",
self.mode.__name__ self.mode.__name__

View File

@@ -26,11 +26,10 @@ from os import urandom
from queue import Queue from queue import Queue
from threading import Event, Thread from threading import Event, Thread
from pyrogram.api.all import layer
import pyrogram import pyrogram
from pyrogram import __copyright__, __license__, __version__ from pyrogram import __copyright__, __license__, __version__
from pyrogram.api import functions, types, core from pyrogram.api import functions, types, core
from pyrogram.api.all import layer
from pyrogram.api.core import Message, TLObject, MsgContainer, Long, FutureSalt, Int from pyrogram.api.core import Message, TLObject, MsgContainer, Long, FutureSalt, Int
from pyrogram.connection import Connection from pyrogram.connection import Connection
from pyrogram.crypto import AES, KDF from pyrogram.crypto import AES, KDF
@@ -440,9 +439,9 @@ class Session:
raise e from None raise e from None
(log.warning if retries < 2 else log.info)( (log.warning if retries < 2 else log.info)(
"{}: {} Retrying {}".format( "[{}] Retrying {} due to {}".format(
Session.MAX_RETRIES - retries + 1, Session.MAX_RETRIES - retries + 1,
datetime.now(), type(data))) data.QUALNAME, e))
time.sleep(0.5) time.sleep(0.5)
return self.send(data, retries - 1, timeout) return self.send(data, retries - 1, timeout)