mirror of
https://github.com/pyrogram/pyrogram
synced 2025-08-29 21:38:04 +00:00
Merge develop -> asyncio
This commit is contained in:
commit
ce72a7edd9
@ -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
|
||||
@ -86,7 +86,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType;
|
||||
storage.fileWebp#1081464c = storage.FileType;
|
||||
|
||||
userEmpty#200250ba id:int = User;
|
||||
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto;
|
||||
@ -101,11 +101,11 @@ userStatusLastMonth#77ebc742 = UserStatus;
|
||||
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;
|
||||
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#d31a961e 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?Vector<RestrictionReason> 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;
|
||||
|
||||
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;
|
||||
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?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#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 has_scheduled:flags.19?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;
|
||||
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
|
||||
@ -118,7 +118,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
|
||||
chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
|
||||
|
||||
messageEmpty#83e5de54 id:int = Message;
|
||||
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
|
||||
message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
|
||||
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
|
||||
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
@ -172,11 +172,10 @@ photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
|
||||
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
|
||||
|
||||
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.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
|
||||
|
||||
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;
|
||||
|
||||
@ -201,7 +200,7 @@ inputReportReasonOther#e1746d0a text:string = ReportReason;
|
||||
inputReportReasonCopyright#9b89f93a = ReportReason;
|
||||
inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
|
||||
|
||||
userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
|
||||
userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
|
||||
|
||||
contact#f911c994 user_id:int mutual:Bool = Contact;
|
||||
|
||||
@ -323,6 +322,9 @@ updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBanne
|
||||
updateFolderPeers#19360dc0 folder_peers:Vector<FolderPeer> pts:int pts_count:int = Update;
|
||||
updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update;
|
||||
updatePeerLocated#b4afcfb0 peers:Vector<PeerLocated> = Update;
|
||||
updateNewScheduledMessage#39a51dfb message:Message = Update;
|
||||
updateDeleteScheduledMessages#90866cee peer:Peer messages:Vector<int> = Update;
|
||||
updateTheme#8216fba3 theme:Theme = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -353,7 +355,7 @@ config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:fla
|
||||
|
||||
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.inviteText#18cb9f78 message:string = help.InviteText;
|
||||
@ -419,6 +421,7 @@ inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
|
||||
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
|
||||
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
|
||||
inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey;
|
||||
inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey;
|
||||
|
||||
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
|
||||
privacyKeyChatInvite#500e6dfa = PrivacyKey;
|
||||
@ -427,6 +430,7 @@ privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
|
||||
privacyKeyForwards#69ec56a3 = PrivacyKey;
|
||||
privacyKeyProfilePhoto#96151fed = PrivacyKey;
|
||||
privacyKeyPhoneNumber#d19ae46d = PrivacyKey;
|
||||
privacyKeyAddedByPhone#42ffd42b = PrivacyKey;
|
||||
|
||||
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
|
||||
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
|
||||
@ -470,7 +474,7 @@ messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMess
|
||||
|
||||
webPageEmpty#eb1477e8 id:long = WebPage;
|
||||
webPagePending#c586da1c id:long date:int = WebPage;
|
||||
webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage;
|
||||
webPage#fa64e172 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document documents:flags.11?Vector<Document> cached_page:flags.10?Page = WebPage;
|
||||
webPageNotModified#85849473 = WebPage;
|
||||
|
||||
authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
|
||||
@ -496,6 +500,7 @@ chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:f
|
||||
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = 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;
|
||||
|
||||
@ -559,8 +564,8 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
|
||||
|
||||
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
|
||||
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
|
||||
channelParticipantCreator#e3e2e1f9 user_id:int = 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;
|
||||
channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = 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;
|
||||
|
||||
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
|
||||
@ -761,7 +766,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.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;
|
||||
|
||||
@ -828,6 +833,7 @@ channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBa
|
||||
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = 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;
|
||||
|
||||
@ -1003,7 +1009,7 @@ inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
|
||||
account.wallPapersNotModified#1c199183 = 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;
|
||||
|
||||
@ -1039,6 +1045,17 @@ channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation;
|
||||
|
||||
peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated;
|
||||
|
||||
restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;
|
||||
|
||||
inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
|
||||
inputThemeSlug#f5890df1 slug:string = InputTheme;
|
||||
|
||||
themeDocumentNotModified#483d270c = Theme;
|
||||
theme#f7d90ce0 flags:# creator:flags.0?true default:flags.1?true id:long access_hash:long slug:string title:string document:flags.2?Document installs_count:int = Theme;
|
||||
|
||||
account.themesNotModified#f41eb622 = account.Themes;
|
||||
account.themes#7f676421 hash:int themes:Vector<Theme> = account.Themes;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -1050,7 +1067,7 @@ invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange 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.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.logOut#5717da40 = Bool;
|
||||
auth.resetAuthorizations#9fab0d1a = Bool;
|
||||
@ -1120,6 +1137,13 @@ account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSet
|
||||
account.resetWallPapers#bb3b9804 = Bool;
|
||||
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
|
||||
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
|
||||
account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document;
|
||||
account.createTheme#2b7ffd7f slug:string title:string document:InputDocument = Theme;
|
||||
account.updateTheme#3b8ea202 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument = Theme;
|
||||
account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool;
|
||||
account.installTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Bool;
|
||||
account.getTheme#8d9d742b format:string theme:InputTheme document_id:long = Theme;
|
||||
account.getThemes#285946f8 format:string hash:int = account.Themes;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@ -1154,9 +1178,9 @@ messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?t
|
||||
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
|
||||
messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
|
||||
messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
|
||||
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
|
||||
messages.reportSpam#cf1592db peer:InputPeer = Bool;
|
||||
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
|
||||
messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
|
||||
@ -1200,9 +1224,9 @@ messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
|
||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
||||
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
||||
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
|
||||
messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int = Updates;
|
||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
|
||||
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
|
||||
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
||||
@ -1236,7 +1260,7 @@ messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
|
||||
messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
|
||||
messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory;
|
||||
messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages;
|
||||
messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates;
|
||||
messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int = Updates;
|
||||
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
|
||||
messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
|
||||
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
|
||||
@ -1258,6 +1282,10 @@ messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter
|
||||
messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
|
||||
messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
|
||||
messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
|
||||
messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages;
|
||||
messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = messages.Messages;
|
||||
messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector<int> = Updates;
|
||||
messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector<int> = Updates;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@ -1269,7 +1297,7 @@ photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
|
||||
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.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.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;
|
||||
upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile;
|
||||
@ -1307,7 +1335,7 @@ channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channe
|
||||
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
|
||||
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.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.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
|
||||
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
|
||||
@ -1330,6 +1358,7 @@ channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
|
||||
channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool;
|
||||
channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates;
|
||||
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.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
@ -1364,4 +1393,4 @@ langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLangua
|
||||
folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
|
||||
folders.deleteFolder#1c295881 folder_id:int = Updates;
|
||||
|
||||
// LAYER 103
|
||||
// LAYER 105
|
@ -128,10 +128,10 @@ def pyrogram_api():
|
||||
utilities="""
|
||||
Utilities
|
||||
start
|
||||
stop
|
||||
restart
|
||||
idle
|
||||
stop
|
||||
run
|
||||
restart
|
||||
add_handler
|
||||
remove_handler
|
||||
stop_transmission
|
||||
@ -249,6 +249,22 @@ def pyrogram_api():
|
||||
set_game_score
|
||||
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
|
||||
send
|
||||
@ -293,6 +309,7 @@ def pyrogram_api():
|
||||
ChatMember
|
||||
ChatPermissions
|
||||
Dialog
|
||||
Restriction
|
||||
""",
|
||||
messages_media="""
|
||||
Messages & Media
|
||||
@ -349,6 +366,11 @@ def pyrogram_api():
|
||||
InputMessageContent
|
||||
InputMessageContent
|
||||
InputTextMessageContent
|
||||
""",
|
||||
authorization="""
|
||||
Authorization
|
||||
SentCode
|
||||
TermsOfService
|
||||
"""
|
||||
)
|
||||
|
||||
|
16
compiler/docs/template/methods.rst
vendored
16
compiler/docs/template/methods.rst
vendored
@ -106,10 +106,24 @@ Bots
|
||||
|
||||
{bots}
|
||||
|
||||
Authorization
|
||||
-------------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
{authorization}
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{authorization}
|
||||
|
||||
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::
|
||||
:nosignatures:
|
||||
|
15
compiler/docs/template/types.rst
vendored
15
compiler/docs/template/types.rst
vendored
@ -92,4 +92,17 @@ InputMessageContent
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{input_message_content}
|
||||
{input_message_content}
|
||||
|
||||
Authorization
|
||||
-------------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
{authorization}
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{authorization}
|
@ -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_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
|
||||
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
|
|
@ -58,7 +58,7 @@ html_show_copyright = False
|
||||
html_theme_options = {
|
||||
"canonical_url": "https://docs.pyrogram.org/",
|
||||
"collapse_navigation": True,
|
||||
"sticky_navigation": True,
|
||||
"sticky_navigation": False,
|
||||
"logo_only": True,
|
||||
"display_version": True,
|
||||
"style_external_links": True
|
||||
|
@ -19,7 +19,6 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import math
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
@ -44,13 +43,14 @@ from pyrogram.errors import (
|
||||
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
|
||||
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
|
||||
VolumeLocNotFound, UserMigrate, ChannelPrivate, PhoneNumberOccupied,
|
||||
PasswordRecoveryNa, PasswordEmpty, AuthBytesInvalid
|
||||
)
|
||||
PasswordRecoveryNa, PasswordEmpty, AuthBytesInvalid,
|
||||
BadRequest)
|
||||
from pyrogram.session import Auth, Session
|
||||
from .ext import utils, Syncer, BaseClient, Dispatcher
|
||||
from .ext.utils import ainput
|
||||
from .methods import Methods
|
||||
from .storage import Storage, FileStorage, MemoryStorage
|
||||
from .types import User, SentCode, TermsOfService
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -188,8 +188,6 @@ class Client(Methods, BaseClient):
|
||||
|
||||
"""
|
||||
|
||||
terms_of_service_displayed = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
session_name: Union[str, Storage],
|
||||
@ -286,70 +284,65 @@ class Client(Methods, BaseClient):
|
||||
self._proxy["enabled"] = bool(value.get("enabled", True))
|
||||
self._proxy.update(value)
|
||||
|
||||
async def start(self):
|
||||
"""Start the client.
|
||||
async def connect(self) -> bool:
|
||||
"""
|
||||
Connect the client to Telegram servers.
|
||||
|
||||
This method connects the client to Telegram and, in case of new sessions, automatically manages the full login
|
||||
process using an interactive prompt (by default).
|
||||
|
||||
Has no parameters.
|
||||
Returns:
|
||||
``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.
|
||||
|
||||
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()
|
||||
ConnectionError: In case you try to connect an already connected client.
|
||||
"""
|
||||
if self.is_started:
|
||||
raise ConnectionError("Client has already been started")
|
||||
if self.is_connected:
|
||||
raise ConnectionError("Client is already connected")
|
||||
|
||||
self.load_config()
|
||||
await self.load_session()
|
||||
self.load_plugins()
|
||||
|
||||
self.session = Session(self, self.storage.dc_id, self.storage.auth_key)
|
||||
|
||||
await self.session.start()
|
||||
self.is_started = True
|
||||
|
||||
try:
|
||||
if self.storage.user_id is None:
|
||||
if self.bot_token is None:
|
||||
self.storage.is_bot = False
|
||||
await self.authorize_user()
|
||||
else:
|
||||
self.storage.is_bot = True
|
||||
await self.authorize_bot()
|
||||
self.is_connected = True
|
||||
|
||||
if not self.storage.is_bot:
|
||||
if self.takeout:
|
||||
self.takeout_id = (await self.send(functions.account.InitTakeoutSession())).id
|
||||
log.warning("Takeout session {} initiated".format(self.takeout_id))
|
||||
return bool(self.storage.user_id)
|
||||
|
||||
now = time.time()
|
||||
async def disconnect(self):
|
||||
"""Disconnect the client from Telegram servers.
|
||||
|
||||
if abs(now - self.storage.date) > Client.OFFLINE_SLEEP:
|
||||
await self.get_initial_dialogs()
|
||||
await self.get_contacts()
|
||||
else:
|
||||
await self.send(functions.messages.GetPinnedDialogs(folder_id=0))
|
||||
await self.get_initial_dialogs_chunk()
|
||||
else:
|
||||
await self.send(functions.updates.GetState())
|
||||
except Exception as e:
|
||||
self.is_started = False
|
||||
await self.session.stop()
|
||||
raise e
|
||||
Raises:
|
||||
ConnectionError: In case you try to disconnect an already disconnected client or in case you try to
|
||||
disconnect a client that needs to be terminated first.
|
||||
"""
|
||||
if not self.is_connected:
|
||||
raise ConnectionError("Client is already disconnected")
|
||||
|
||||
if self.is_initialized:
|
||||
raise ConnectionError("Can't disconnect an initialized client")
|
||||
|
||||
await self.session.stop()
|
||||
self.storage.close()
|
||||
self.is_connected = False
|
||||
|
||||
async 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 _ in range(Client.UPDATES_WORKERS):
|
||||
self.updates_worker_tasks.append(
|
||||
@ -368,35 +361,21 @@ class Client(Methods, BaseClient):
|
||||
await self.dispatcher.start()
|
||||
await Syncer.add(self)
|
||||
|
||||
mimetypes.init()
|
||||
Syncer.add(self)
|
||||
|
||||
return self
|
||||
self.is_initialized = True
|
||||
|
||||
async def stop(self):
|
||||
"""Stop the Client.
|
||||
async def terminate(self):
|
||||
"""Terminate the client by shutting down workers.
|
||||
|
||||
This method disconnects the client from Telegram and stops the underlying tasks.
|
||||
|
||||
Has no parameters.
|
||||
This method does the opposite of :meth:`~Client.initialize`.
|
||||
It will stop the dispatcher and shut down updates and download workers.
|
||||
|
||||
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()
|
||||
ConnectionError: In case you try to terminate a client that is already terminated.
|
||||
"""
|
||||
if not self.is_started:
|
||||
raise ConnectionError("Client is already stopped")
|
||||
if not self.is_initialized:
|
||||
raise ConnectionError("Client is already terminated")
|
||||
|
||||
if self.takeout_id:
|
||||
await self.send(functions.account.FinishTakeoutSession())
|
||||
@ -430,8 +409,491 @@ class Client(Methods, BaseClient):
|
||||
|
||||
self.media_sessions.clear()
|
||||
|
||||
self.is_started = False
|
||||
await self.session.stop()
|
||||
self.is_initialized = False
|
||||
|
||||
async 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 = await 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:
|
||||
await self.session.stop()
|
||||
|
||||
self.storage.dc_id = e.x
|
||||
self.storage.auth_key = await Auth(self, self.storage.dc_id).create()
|
||||
self.session = Session(self, self.storage.dc_id, self.storage.auth_key)
|
||||
|
||||
await self.session.start()
|
||||
else:
|
||||
return SentCode._parse(r)
|
||||
|
||||
async 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 = await self.send(
|
||||
functions.auth.ResendCode(
|
||||
phone_number=phone_number,
|
||||
phone_code_hash=phone_code_hash
|
||||
)
|
||||
)
|
||||
|
||||
return SentCode._parse(r)
|
||||
|
||||
async 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 = await 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)
|
||||
|
||||
async 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 = await 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)
|
||||
|
||||
async 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 = await 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:
|
||||
await self.session.stop()
|
||||
|
||||
self.storage.dc_id = e.x
|
||||
self.storage.auth_key = await Auth(self, self.storage.dc_id).create()
|
||||
self.session = Session(self, self.storage.dc_id, self.storage.auth_key)
|
||||
|
||||
await self.session.start()
|
||||
else:
|
||||
self.storage.user_id = r.user.id
|
||||
self.storage.is_bot = True
|
||||
|
||||
return User._parse(self, r.user)
|
||||
|
||||
async 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 (await self.send(functions.account.GetPassword())).hint
|
||||
|
||||
async 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 = await self.send(
|
||||
functions.auth.CheckPassword(
|
||||
password=compute_check(
|
||||
await self.send(functions.account.GetPassword()),
|
||||
password
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
self.storage.user_id = r.user.id
|
||||
self.storage.is_bot = False
|
||||
|
||||
return User._parse(self, r.user)
|
||||
|
||||
async 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 (await self.send(
|
||||
functions.auth.RequestPasswordRecovery()
|
||||
)).email_pattern
|
||||
|
||||
async 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 = await 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)
|
||||
|
||||
async 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 = await self.send(
|
||||
functions.help.AcceptTermsOfService(
|
||||
id=types.DataJSON(
|
||||
data=terms_of_service_id
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
assert r
|
||||
|
||||
return True
|
||||
|
||||
async def authorize(self) -> User:
|
||||
if self.bot_token is not None:
|
||||
return await self.sign_in_bot(self.bot_token)
|
||||
|
||||
while True:
|
||||
if self.phone_number is None:
|
||||
while True:
|
||||
value = await ainput("Enter phone number or bot token: ")
|
||||
confirm = await ainput("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 await self.sign_in_bot(value)
|
||||
else:
|
||||
self.phone_number = value
|
||||
|
||||
try:
|
||||
sent_code = await 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 = await 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 = await ainput("Enter confirmation code: ")
|
||||
|
||||
try:
|
||||
signed_in = await 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(await self.get_password_hint()))
|
||||
|
||||
if self.password is None:
|
||||
self.password = await ainput("Enter password (empty to recover): ")
|
||||
|
||||
try:
|
||||
if self.password == "":
|
||||
confirm = await ainput("Confirm password recovery (y/n): ")
|
||||
|
||||
if confirm in ("y", "1"):
|
||||
email_pattern = await self.send_recovery_code()
|
||||
print("The recovery code has been sent to {}".format(email_pattern))
|
||||
|
||||
while True:
|
||||
recovery_code = await ainput("Enter recovery code: ")
|
||||
|
||||
try:
|
||||
return await 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 await 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 = await ainput("Enter first name: ")
|
||||
self.last_name = await ainput("Enter last name (empty to skip): ")
|
||||
|
||||
try:
|
||||
signed_up = await 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")
|
||||
await 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
|
||||
|
||||
@ -441,7 +903,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
|
||||
a client using a single method.
|
||||
|
||||
Has no parameters.
|
||||
Returns:
|
||||
:obj:`Client`: The restarted client itself.
|
||||
|
||||
Raises:
|
||||
ConnectionError: In case you try to restart a stopped Client.
|
||||
@ -466,6 +929,8 @@ class Client(Methods, BaseClient):
|
||||
await self.stop()
|
||||
await self.start()
|
||||
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
async def idle(stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
|
||||
"""Block the main script execution until a signal is received.
|
||||
@ -530,12 +995,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
|
||||
client in a single main script, since idle() will block after starting the own client.
|
||||
|
||||
Has no parameters.
|
||||
|
||||
Args:
|
||||
coroutine: (``Coroutine``, *optional*):
|
||||
Pass a coroutine to run it until is complete.
|
||||
|
||||
Raises:
|
||||
ConnectionError: In case you try to run an already started client.
|
||||
|
||||
@ -645,8 +1104,6 @@ class Client(Methods, BaseClient):
|
||||
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.
|
||||
|
||||
Has no parameters.
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 9
|
||||
@ -673,8 +1130,6 @@ class Client(Methods, BaseClient):
|
||||
More detailed information about session strings can be found at the dedicated page of
|
||||
:doc:`Storage Engines <../../topics/storage-engines>`.
|
||||
|
||||
Has no parameters.
|
||||
|
||||
Returns:
|
||||
``str``: The session serialized into a printable, url-safe string.
|
||||
|
||||
@ -1077,6 +1532,7 @@ class Client(Methods, BaseClient):
|
||||
access_hash=data.access_hash,
|
||||
thumb_size=data.thumb_size,
|
||||
peer_id=data.peer_id,
|
||||
peer_access_hash=data.peer_access_hash,
|
||||
volume_id=data.volume_id,
|
||||
local_id=data.local_id,
|
||||
file_size=data.file_size,
|
||||
@ -1219,8 +1675,8 @@ class Client(Methods, BaseClient):
|
||||
Raises:
|
||||
RPCError: In case of a Telegram RPC error.
|
||||
"""
|
||||
if not self.is_started:
|
||||
raise ConnectionError("Client has not been started")
|
||||
if not self.is_connected:
|
||||
raise ConnectionError("Client has not been started yet")
|
||||
|
||||
if self.no_updates:
|
||||
data = functions.InvokeWithoutUpdates(query=data)
|
||||
@ -1452,37 +1908,37 @@ class Client(Methods, BaseClient):
|
||||
log.warning('[{}] No plugin loaded from "{}"'.format(
|
||||
self.session_name, root))
|
||||
|
||||
async def get_initial_dialogs_chunk(self, offset_date: int = 0):
|
||||
while True:
|
||||
try:
|
||||
r = await self.send(
|
||||
functions.messages.GetDialogs(
|
||||
offset_date=offset_date,
|
||||
offset_id=0,
|
||||
offset_peer=types.InputPeerEmpty(),
|
||||
limit=self.DIALOGS_AT_ONCE,
|
||||
hash=0,
|
||||
exclude_pinned=True
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("get_dialogs flood: waiting {} seconds".format(e.x))
|
||||
await asyncio.sleep(e.x)
|
||||
else:
|
||||
log.info("Total peers: {}".format(self.storage.peers_count))
|
||||
return r
|
||||
|
||||
async def get_initial_dialogs(self):
|
||||
await self.send(functions.messages.GetPinnedDialogs(folder_id=0))
|
||||
|
||||
dialogs = await self.get_initial_dialogs_chunk()
|
||||
offset_date = utils.get_offset_date(dialogs)
|
||||
|
||||
while len(dialogs.dialogs) == self.DIALOGS_AT_ONCE:
|
||||
dialogs = await self.get_initial_dialogs_chunk(offset_date)
|
||||
offset_date = utils.get_offset_date(dialogs)
|
||||
|
||||
await self.get_initial_dialogs_chunk()
|
||||
# def get_initial_dialogs_chunk(self, offset_date: int = 0):
|
||||
# while True:
|
||||
# try:
|
||||
# r = self.send(
|
||||
# functions.messages.GetDialogs(
|
||||
# offset_date=offset_date,
|
||||
# offset_id=0,
|
||||
# offset_peer=types.InputPeerEmpty(),
|
||||
# limit=self.DIALOGS_AT_ONCE,
|
||||
# hash=0,
|
||||
# exclude_pinned=True
|
||||
# )
|
||||
# )
|
||||
# except FloodWait as e:
|
||||
# log.warning("get_dialogs flood: waiting {} seconds".format(e.x))
|
||||
# time.sleep(e.x)
|
||||
# else:
|
||||
# log.info("Total peers: {}".format(self.storage.peers_count))
|
||||
# return r
|
||||
#
|
||||
# def get_initial_dialogs(self):
|
||||
# self.send(functions.messages.GetPinnedDialogs(folder_id=0))
|
||||
#
|
||||
# dialogs = self.get_initial_dialogs_chunk()
|
||||
# offset_date = utils.get_offset_date(dialogs)
|
||||
#
|
||||
# while len(dialogs.dialogs) == self.DIALOGS_AT_ONCE:
|
||||
# dialogs = self.get_initial_dialogs_chunk(offset_date)
|
||||
# offset_date = utils.get_offset_date(dialogs)
|
||||
#
|
||||
# self.get_initial_dialogs_chunk()
|
||||
|
||||
async def resolve_peer(self,
|
||||
peer_id: Union[int, str]):
|
||||
@ -1504,9 +1960,11 @@ class Client(Methods, BaseClient):
|
||||
``InputPeer``: On success, the resolved peer id is returned in form of an InputPeer object.
|
||||
|
||||
Raises:
|
||||
RPCError: In case of a Telegram RPC error.
|
||||
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:
|
||||
return self.storage.get_peer_by_id(peer_id)
|
||||
except KeyError:
|
||||
@ -1698,7 +2156,7 @@ class Client(Methods, BaseClient):
|
||||
file_part += 1
|
||||
|
||||
if progress:
|
||||
await progress(self, min(file_part * part_size, file_size), file_size, *progress_args)
|
||||
await progress(min(file_part * part_size, file_size), file_size, *progress_args)
|
||||
except Client.StopTransmission:
|
||||
raise
|
||||
except Exception as e:
|
||||
@ -1733,7 +2191,7 @@ class Client(Methods, BaseClient):
|
||||
access_hash: int,
|
||||
thumb_size: str,
|
||||
peer_id: int,
|
||||
volume_id: int,
|
||||
peer_access_hash: int, volume_id: int,
|
||||
local_id: int,
|
||||
file_size: int,
|
||||
|
||||
@ -1777,7 +2235,10 @@ class Client(Methods, BaseClient):
|
||||
|
||||
if media_type == 1:
|
||||
location = types.InputPeerPhotoFileLocation(
|
||||
peer=self.resolve_peer(peer_id),
|
||||
peer=types.InputPeerUser(
|
||||
user_id=peer_id,
|
||||
access_hash=peer_access_hash
|
||||
),
|
||||
volume_id=volume_id,
|
||||
local_id=local_id,
|
||||
big=is_big or None
|
||||
@ -1833,7 +2294,6 @@ class Client(Methods, BaseClient):
|
||||
|
||||
if progress:
|
||||
await progress(
|
||||
self,
|
||||
min(offset, file_size)
|
||||
if file_size != 0
|
||||
else offset,
|
||||
@ -1919,7 +2379,6 @@ class Client(Methods, BaseClient):
|
||||
|
||||
if progress:
|
||||
await progress(
|
||||
self,
|
||||
min(offset, file_size)
|
||||
if file_size != 0
|
||||
else offset,
|
||||
|
@ -49,7 +49,6 @@ class BaseClient:
|
||||
PARENT_DIR = Path(sys.argv[0]).parent
|
||||
|
||||
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
|
||||
UPDATES_WORKERS = 1
|
||||
DOWNLOAD_WORKERS = 4
|
||||
@ -102,7 +101,8 @@ class BaseClient:
|
||||
self.media_sessions = {}
|
||||
self.media_sessions_lock = asyncio.Lock()
|
||||
|
||||
self.is_started = None
|
||||
self.is_connected = None
|
||||
self.is_initialized = None
|
||||
|
||||
self.takeout_id = None
|
||||
|
||||
|
@ -20,8 +20,9 @@
|
||||
class FileData:
|
||||
def __init__(
|
||||
self, *, media_type: int = None, dc_id: int = None, document_id: int = None, access_hash: int = None,
|
||||
thumb_size: str = None, peer_id: int = None, volume_id: int = None, local_id: int = None, is_big: bool = None,
|
||||
file_size: int = None, mime_type: str = None, file_name: str = None, date: int = None
|
||||
thumb_size: str = None, peer_id: int = None, peer_access_hash: int = None, volume_id: int = None,
|
||||
local_id: int = None, is_big: bool = None, file_size: int = None, mime_type: str = None, file_name: str = None,
|
||||
date: int = None
|
||||
):
|
||||
self.media_type = media_type
|
||||
self.dc_id = dc_id
|
||||
@ -29,6 +30,7 @@ class FileData:
|
||||
self.access_hash = access_hash
|
||||
self.thumb_size = thumb_size
|
||||
self.peer_id = peer_id
|
||||
self.peer_access_hash = peer_access_hash
|
||||
self.volume_id = volume_id
|
||||
self.local_id = local_id
|
||||
self.is_big = is_big
|
||||
|
@ -116,8 +116,8 @@ def get_input_media_from_file_id(
|
||||
raise ValueError("This file_id can only be used for download: {}".format(file_id_str))
|
||||
|
||||
if media_type == 2:
|
||||
unpacked = struct.unpack("<iiqqc", decoded)
|
||||
dc_id, file_id, access_hash, thumb_size = unpacked[1:]
|
||||
unpacked = struct.unpack("<iiqqqiiii", decoded)
|
||||
dc_id, file_id, access_hash, volume_id, _, _, type, local_id = unpacked[1:]
|
||||
|
||||
return types.InputMediaPhoto(
|
||||
id=types.InputPhoto(
|
||||
|
@ -57,6 +57,9 @@ class GetNearbyChats(BaseClient):
|
||||
)
|
||||
)
|
||||
|
||||
if not r.updates:
|
||||
return []
|
||||
|
||||
chats = pyrogram.List([pyrogram.Chat._parse_chat(self, chat) for chat in r.chats])
|
||||
peers = r.updates[0].peers
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from struct import unpack
|
||||
from typing import Union
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
@ -62,15 +61,8 @@ class SetChatPhoto(BaseClient):
|
||||
if os.path.exists(photo):
|
||||
photo = types.InputChatUploadedPhoto(file=self.save_file(photo))
|
||||
else:
|
||||
unpacked = unpack("<iiqqc", utils.decode(photo))
|
||||
|
||||
photo = types.InputChatPhoto(
|
||||
id=types.InputPhoto(
|
||||
id=unpacked[2],
|
||||
access_hash=unpacked[3],
|
||||
file_reference=b""
|
||||
)
|
||||
)
|
||||
photo = utils.get_input_media_from_file_id(photo)
|
||||
photo = types.InputChatPhoto(id=photo.id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
await self.send(
|
||||
|
@ -139,21 +139,22 @@ class DownloadMedia(BaseClient):
|
||||
media_type = decoded[0]
|
||||
|
||||
if media_type == 1:
|
||||
unpacked = struct.unpack("<iiqqib", decoded)
|
||||
dc_id, peer_id, volume_id, local_id, is_big = unpacked[1:]
|
||||
unpacked = struct.unpack("<iiqqqiiiqi", decoded)
|
||||
dc_id, photo_id, _, volume_id, size_type, peer_id, _, peer_access_hash, local_id = unpacked[1:]
|
||||
|
||||
data = FileData(
|
||||
**get_existing_attributes(),
|
||||
media_type=media_type,
|
||||
dc_id=dc_id,
|
||||
peer_id=peer_id,
|
||||
peer_access_hash=peer_access_hash,
|
||||
volume_id=volume_id,
|
||||
local_id=local_id,
|
||||
is_big=bool(is_big)
|
||||
is_big=size_type == 3
|
||||
)
|
||||
elif media_type in (0, 2, 14):
|
||||
unpacked = struct.unpack("<iiqqc", decoded)
|
||||
dc_id, document_id, access_hash, thumb_size = unpacked[1:]
|
||||
unpacked = struct.unpack("<iiqqqiiii", decoded)
|
||||
dc_id, document_id, access_hash, volume_id, _, _, thumb_size, local_id = unpacked[1:]
|
||||
|
||||
data = FileData(
|
||||
**get_existing_attributes(),
|
||||
@ -161,7 +162,7 @@ class DownloadMedia(BaseClient):
|
||||
dc_id=dc_id,
|
||||
document_id=document_id,
|
||||
access_hash=access_hash,
|
||||
thumb_size=thumb_size.decode()
|
||||
thumb_size=chr(thumb_size)
|
||||
)
|
||||
elif media_type in (3, 4, 5, 8, 9, 10, 13):
|
||||
unpacked = struct.unpack("<iiqq", decoded)
|
||||
|
@ -86,8 +86,7 @@ class Parser(HTMLParser):
|
||||
|
||||
for entities in self.tag_entities.values():
|
||||
for entity in entities:
|
||||
entity.offset += len(data) - len(data.lstrip()) # Ignore left whitespaces for offsets
|
||||
entity.length += len(data.strip()) # Ignore all whitespaces (left + right) for lengths
|
||||
entity.length += len(data)
|
||||
|
||||
self.text += data
|
||||
|
||||
|
@ -23,5 +23,6 @@ from .input_message_content import *
|
||||
from .list import List
|
||||
from .messages_and_media import *
|
||||
from .object import Object
|
||||
from .authorization import *
|
||||
from .update import *
|
||||
from .user_and_chats import *
|
||||
|
22
pyrogram/client/types/authorization/__init__.py
Normal file
22
pyrogram/client/types/authorization/__init__.py
Normal 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"]
|
86
pyrogram/client/types/authorization/sent_code.py
Normal file
86
pyrogram/client/types/authorization/sent_code.py
Normal 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
|
||||
)
|
56
pyrogram/client/types/authorization/terms_of_service.py
Normal file
56
pyrogram/client/types/authorization/terms_of_service.py
Normal 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
|
||||
]
|
||||
)
|
@ -2743,7 +2743,7 @@ class Message(Object, Update):
|
||||
revoke=revoke
|
||||
)
|
||||
|
||||
async def click(self, x: int or str, y: int = 0, quote: bool = None, timeout: int = 10):
|
||||
async def click(self, x: int or str = 0, y: int = None, quote: bool = None, timeout: int = 10):
|
||||
"""Bound method *click* of :obj:`Message`.
|
||||
|
||||
Use as a shortcut for clicking a button attached to the message instead of:
|
||||
|
@ -77,10 +77,10 @@ class Photo(Object):
|
||||
return Photo(
|
||||
file_id=encode(
|
||||
pack(
|
||||
"<iiqqc",
|
||||
2, photo.dc_id,
|
||||
photo.id, photo.access_hash,
|
||||
big.type.encode()
|
||||
"<iiqqqiiii",
|
||||
2, photo.dc_id, photo.id, photo.access_hash,
|
||||
big.location.volume_id, 1, 2, ord(big.type),
|
||||
big.location.local_id
|
||||
)
|
||||
),
|
||||
width=big.w,
|
||||
|
@ -66,7 +66,7 @@ class Thumbnail(Object):
|
||||
) -> Union[List[Union[StrippedThumbnail, "Thumbnail"]], None]:
|
||||
if isinstance(media, types.Photo):
|
||||
raw_thumbnails = media.sizes[:-1]
|
||||
media_type = 0
|
||||
media_type = 2
|
||||
elif isinstance(media, types.Document):
|
||||
raw_thumbnails = media.thumbs
|
||||
media_type = 14
|
||||
@ -87,10 +87,10 @@ class Thumbnail(Object):
|
||||
Thumbnail(
|
||||
file_id=encode(
|
||||
pack(
|
||||
"<iiqqc",
|
||||
media_type, media.dc_id,
|
||||
media.id, media.access_hash,
|
||||
thumbnail.type.encode()
|
||||
"<iiqqqiiii",
|
||||
media_type, media.dc_id, media.id, media.access_hash,
|
||||
thumbnail.location.volume_id, 1, 2, ord(thumbnail.type),
|
||||
thumbnail.location.local_id
|
||||
)
|
||||
),
|
||||
width=thumbnail.w,
|
||||
|
@ -16,12 +16,13 @@
|
||||
# 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 Union
|
||||
from typing import Union, List
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import types
|
||||
from .chat_permissions import ChatPermissions
|
||||
from .chat_photo import ChatPhoto
|
||||
from .restriction import Restriction
|
||||
from ..object import Object
|
||||
from ...ext import utils
|
||||
|
||||
@ -87,8 +88,8 @@ class Chat(Object):
|
||||
members_count (``int``, *optional*):
|
||||
Chat members count, for groups, supergroups and channels only.
|
||||
|
||||
restriction_reason (``str``, *optional*):
|
||||
The reason why this chat might be unavailable to some users.
|
||||
restrictions (List of :obj:`Restriction`, *optional*):
|
||||
The list of reasons why this chat might be unavailable to some users.
|
||||
This field is available only in case *is_restricted* is True.
|
||||
|
||||
permissions (:obj:`ChatPermissions` *optional*):
|
||||
@ -120,7 +121,7 @@ class Chat(Object):
|
||||
sticker_set_name: str = None,
|
||||
can_set_sticker_set: bool = None,
|
||||
members_count: int = None,
|
||||
restriction_reason: str = None,
|
||||
restrictions: List[Restriction] = None,
|
||||
permissions: "pyrogram.ChatPermissions" = None,
|
||||
distance: int = None
|
||||
):
|
||||
@ -143,7 +144,7 @@ class Chat(Object):
|
||||
self.sticker_set_name = sticker_set_name
|
||||
self.can_set_sticker_set = can_set_sticker_set
|
||||
self.members_count = members_count
|
||||
self.restriction_reason = restriction_reason
|
||||
self.restrictions = restrictions
|
||||
self.permissions = permissions
|
||||
self.distance = distance
|
||||
|
||||
@ -162,7 +163,7 @@ class Chat(Object):
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
photo=ChatPhoto._parse(client, user.photo, peer_id),
|
||||
restriction_reason=user.restriction_reason,
|
||||
restrictions=pyrogram.List([Restriction._parse(r) for r in user.restriction_reason]) or None,
|
||||
client=client
|
||||
)
|
||||
|
||||
@ -183,6 +184,7 @@ class Chat(Object):
|
||||
@staticmethod
|
||||
def _parse_channel_chat(client, channel: types.Channel) -> "Chat":
|
||||
peer_id = utils.get_channel_id(channel.id)
|
||||
restriction_reason = getattr(channel, "restriction_reason", [])
|
||||
|
||||
return Chat(
|
||||
id=peer_id,
|
||||
@ -193,7 +195,7 @@ class Chat(Object):
|
||||
title=channel.title,
|
||||
username=getattr(channel, "username", None),
|
||||
photo=ChatPhoto._parse(client, getattr(channel, "photo", None), peer_id),
|
||||
restriction_reason=getattr(channel, "restriction_reason", None),
|
||||
restrictions=pyrogram.List([Restriction._parse(r) for r in restriction_reason]) or None,
|
||||
permissions=ChatPermissions._parse(getattr(channel, "default_banned_rights", None)),
|
||||
members_count=getattr(channel, "participants_count", None),
|
||||
client=client
|
||||
|
@ -54,20 +54,40 @@ class ChatPhoto(Object):
|
||||
if not isinstance(chat_photo, (types.UserProfilePhoto, types.ChatPhoto)):
|
||||
return None
|
||||
|
||||
photo_id = getattr(chat_photo, "photo_id", 0)
|
||||
loc_small = chat_photo.photo_small
|
||||
loc_big = chat_photo.photo_big
|
||||
|
||||
peer = client.resolve_peer(peer_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerUser):
|
||||
peer_id = peer.user_id
|
||||
peer_access_hash = peer.access_hash
|
||||
x = 0
|
||||
elif isinstance(peer, types.InputPeerChat):
|
||||
peer_id = -peer.chat_id
|
||||
peer_access_hash = 0
|
||||
x = -1
|
||||
else:
|
||||
peer_id += 1000727379968
|
||||
peer_access_hash = peer.access_hash
|
||||
x = -234
|
||||
|
||||
return ChatPhoto(
|
||||
small_file_id=encode(
|
||||
pack(
|
||||
"<iiqqib",
|
||||
1, chat_photo.dc_id, peer_id, loc_small.volume_id, loc_small.local_id, 0
|
||||
"<iiqqqiiiqi",
|
||||
1, chat_photo.dc_id, photo_id,
|
||||
0, loc_small.volume_id,
|
||||
2, peer_id, x, peer_access_hash, loc_small.local_id
|
||||
)
|
||||
),
|
||||
big_file_id=encode(
|
||||
pack(
|
||||
"<iiqqib",
|
||||
1, chat_photo.dc_id, peer_id, loc_big.volume_id, loc_big.local_id, 1
|
||||
"<iiqqqiiiqi",
|
||||
1, chat_photo.dc_id, photo_id,
|
||||
0, loc_big.volume_id,
|
||||
3, peer_id, x, peer_access_hash, loc_big.local_id
|
||||
)
|
||||
),
|
||||
client=client
|
||||
|
50
pyrogram/client/types/user_and_chats/restriction.py
Normal file
50
pyrogram/client/types/user_and_chats/restriction.py
Normal file
@ -0,0 +1,50 @@
|
||||
# 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 Restriction(Object):
|
||||
"""A restriction applied to bots or chats.
|
||||
|
||||
Parameters:
|
||||
platform (``str``):
|
||||
The platform the restriction is applied to, e.g. "ios", "android"
|
||||
|
||||
reason (``str``):
|
||||
The restriction reason, e.g. "porn", "copyright".
|
||||
|
||||
text (``str``):
|
||||
The restriction text.
|
||||
"""
|
||||
|
||||
def __init__(self, *, platform: str, reason: str, text: str):
|
||||
super().__init__(None)
|
||||
|
||||
self.platform = platform
|
||||
self.reason = reason
|
||||
self.text = text
|
||||
|
||||
@staticmethod
|
||||
def _parse(restriction: types.RestrictionReason) -> "Restriction":
|
||||
return Restriction(
|
||||
platform=restriction.platform,
|
||||
reason=restriction.reason,
|
||||
text=restriction.text
|
||||
)
|
@ -17,10 +17,12 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import html
|
||||
from typing import List
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import types
|
||||
from .chat_photo import ChatPhoto
|
||||
from .restriction import Restriction
|
||||
from ..object import Object
|
||||
from ..update import Update
|
||||
|
||||
@ -101,8 +103,8 @@ class User(Object, Update):
|
||||
photo (:obj:`ChatPhoto <pyrogram.ChatPhoto>`, *optional*):
|
||||
User's or bot's current profile photo. Suitable for downloads only.
|
||||
|
||||
restriction_reason (``str``, *optional*):
|
||||
The reason why this bot might be unavailable to some users.
|
||||
restrictions (List of :obj:`Restriction`, *optional*):
|
||||
The list of reasons why this bot might be unavailable to some users.
|
||||
This field is available only in case *is_restricted* is True.
|
||||
"""
|
||||
|
||||
@ -130,7 +132,7 @@ class User(Object, Update):
|
||||
dc_id: int = None,
|
||||
phone_number: str = None,
|
||||
photo: ChatPhoto = None,
|
||||
restriction_reason: str = None
|
||||
restrictions: List[Restriction] = None
|
||||
):
|
||||
super().__init__(client)
|
||||
|
||||
@ -154,7 +156,7 @@ class User(Object, Update):
|
||||
self.dc_id = dc_id
|
||||
self.phone_number = phone_number
|
||||
self.photo = photo
|
||||
self.restriction_reason = restriction_reason
|
||||
self.restrictions = restrictions
|
||||
|
||||
def __format__(self, format_spec):
|
||||
if format_spec == "mention":
|
||||
@ -186,7 +188,7 @@ class User(Object, Update):
|
||||
dc_id=getattr(user.photo, "dc_id", None),
|
||||
phone_number=user.phone,
|
||||
photo=ChatPhoto._parse(client, user.photo, user.id),
|
||||
restriction_reason=user.restriction_reason,
|
||||
restrictions=pyrogram.List([Restriction._parse(r) for r in user.restriction_reason]) or None,
|
||||
client=client
|
||||
)
|
||||
|
||||
@ -322,3 +324,26 @@ class User(Object, Update):
|
||||
"""
|
||||
|
||||
return self._client.unblock_user(self.id)
|
||||
|
||||
def get_common_chats(self):
|
||||
"""Bound method *get_common_chats* of :obj:`User`.
|
||||
|
||||
Use as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
client.get_common_chats(123456789)
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
user.get_common_chats()
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
RPCError: In case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
return self._client.get_common_chats(self.id)
|
||||
|
@ -38,6 +38,7 @@ class Connection:
|
||||
|
||||
def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 3):
|
||||
self.dc_id = dc_id
|
||||
self.test_mode = test_mode
|
||||
self.ipv6 = ipv6
|
||||
self.proxy = proxy
|
||||
self.address = DataCenter(dc_id, test_mode, ipv6)
|
||||
@ -57,7 +58,8 @@ class Connection:
|
||||
self.protocol.close()
|
||||
await asyncio.sleep(1)
|
||||
else:
|
||||
log.info("Connected! DC{} - IPv{} - {}".format(
|
||||
log.info("Connected! {} DC{} - IPv{} - {}".format(
|
||||
"Test" if self.test_mode else "Production",
|
||||
self.dc_id,
|
||||
"6" if self.ipv6 else "4",
|
||||
self.mode.__name__
|
||||
|
@ -22,11 +22,10 @@ from datetime import datetime, timedelta
|
||||
from hashlib import sha1
|
||||
from io import BytesIO
|
||||
|
||||
from pyrogram.api.all import layer
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import __copyright__, __license__, __version__
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.all import layer
|
||||
from pyrogram.api.core import TLObject, MsgContainer, Int, Long, FutureSalt, FutureSalts
|
||||
from pyrogram.connection import Connection
|
||||
from pyrogram.crypto import MTProto
|
||||
@ -413,9 +412,9 @@ class Session:
|
||||
raise e from None
|
||||
|
||||
(log.warning if retries < 2 else log.info)(
|
||||
"{}: {} Retrying {}".format(
|
||||
"[{}] Retrying {} due to {}".format(
|
||||
Session.MAX_RETRIES - retries + 1,
|
||||
datetime.now(), type(data)))
|
||||
data.QUALNAME, e))
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
return await self.send(data, retries - 1, timeout)
|
||||
|
Loading…
x
Reference in New Issue
Block a user