diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..f34f615a --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: delivrance +custom: https://docs.pyrogram.org/support-pyrogram diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py index 21348336..64e88c9d 100644 --- a/compiler/api/compiler.py +++ b/compiler/api/compiler.py @@ -333,6 +333,7 @@ def start(): docstring_args = "No parameters required." docstring_args = "Attributes:\n ID: ``{}``\n\n ".format(c.id) + docstring_args + docstring_args = "Attributes:\n LAYER: ``{}``\n\n ".format(layer) + docstring_args if c.section == "functions": docstring_args += "\n\n Returns:\n " + get_docstring_arg_type(c.return_type) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 61c9faf6..43b02e80 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -22,10 +22,13 @@ inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; +inputPeerUserFromMessage#17bae2e6 peer:InputPeer msg_id:int user_id:int = InputPeer; +inputPeerChannelFromMessage#9c95f7bb peer:InputPeer msg_id:int channel_id:int = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; +inputUserFromMessage#2d117597 peer:InputPeer msg_id:int user_id:int = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; @@ -60,9 +63,12 @@ inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation; +inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; +inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; +inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; +inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; @@ -79,14 +85,11 @@ storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; -fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; -fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation; - 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 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#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; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; +userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; @@ -98,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 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 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; -chatFull#22a235da 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 pinned_msg_id:flags.6?int = ChatFull; -channelFull#1c87a71a 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 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 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 = 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 pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull; +channelFull#9882e516 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 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 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.13?int pts:int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -112,11 +115,11 @@ chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0? chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = 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 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 views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = 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 id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = 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 views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = 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; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; @@ -147,7 +150,7 @@ messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; -messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; +messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; @@ -155,10 +158,11 @@ messageActionSecureValuesSentMe#1b287353 values:Vector credentials: messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; -dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; +dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; +dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; photoEmpty#2331b22d id:long = Photo; -photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector = Photo; +photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector dc_id:int = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; @@ -196,7 +200,7 @@ inputReportReasonChildAbuse#adf44ee3 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; -userFull#8ea4a881 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 link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; +userFull#745559cc 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 link:contacts.Link 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; @@ -221,7 +225,7 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector< messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector chats:Vector users:Vector = messages.Messages; +messages.messagesSlice#c8edce1e flags:# inexact:flags.1?true count:int next_rate:flags.0?int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; @@ -271,14 +275,14 @@ updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; -updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; +updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; +updateReadChannelInbox#330b5424 flags:# folder_id:flags.0?int channel_id:int max_id:int still_unread_count:int pts:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; @@ -300,8 +304,8 @@ updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; +updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; +updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; @@ -318,6 +322,7 @@ updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; +updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -344,7 +349,7 @@ upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; -config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; +config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; @@ -413,6 +418,7 @@ inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; +inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; @@ -420,6 +426,7 @@ privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; privacyKeyForwards#69ec56a3 = PrivacyKey; privacyKeyProfilePhoto#96151fed = PrivacyKey; +privacyKeyPhoneNumber#d19ae46d = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; @@ -427,6 +434,8 @@ inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; +inputPrivacyValueAllowChatParticipants#4c81c1ba chats:Vector = InputPrivacyRule; +inputPrivacyValueDisallowChatParticipants#d82363af chats:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; @@ -434,8 +443,10 @@ privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; +privacyValueAllowChatParticipants#18be796b chats:Vector = PrivacyRule; +privacyValueDisallowChatParticipants#acae0690 chats:Vector = PrivacyRule; -account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; +account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; @@ -459,7 +470,6 @@ messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMess contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; -contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; @@ -485,13 +495,13 @@ chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; +chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -stickerSet#6a90bcb7 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize count:int hash:int = StickerSet; +stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?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; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; @@ -507,6 +517,8 @@ keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; +keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; +inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; @@ -533,13 +545,14 @@ messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; +inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; +updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; @@ -628,6 +641,8 @@ topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; +topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; +topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; @@ -767,11 +782,11 @@ inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_co inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; +phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; +phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; +phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; +phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int = PhoneCall; +phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; @@ -797,7 +812,7 @@ langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:fl channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; +channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; @@ -812,6 +827,7 @@ channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputSticker channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; +channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; @@ -843,8 +859,10 @@ inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; +inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; +dialogPeerFolder#514519e2 folder_id:int = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; @@ -1000,6 +1018,22 @@ emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int k emojiURL#a575739d url:string = EmojiURL; +emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; + +fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation; + +folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; + +inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; + +folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; + +messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; + +urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult; +urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult; +urlAuthResultDefault#a9d6db1f = UrlAuthResult; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1098,14 +1132,14 @@ contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; -contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; +contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; +messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; @@ -1152,7 +1186,7 @@ messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_par messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; -messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; +messages.searchGlobal#f79c611 q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; @@ -1185,8 +1219,8 @@ messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = message messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; -messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; +messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; +messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; @@ -1212,7 +1246,11 @@ messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; +messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; +messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector = Vector; +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; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1281,6 +1319,9 @@ channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; +channels.getGroupsForDiscussion#f5dad378 = messages.Chats; +channels.getBroadcastsForDiscussion#1a87f304 = messages.Chats; +channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -1298,11 +1339,11 @@ stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = mes stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; +phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; +phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; @@ -1312,7 +1353,7 @@ langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:i langpack.getLanguages#42c6978f lang_pack:string = Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; -// LAYER 97 +folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; +folders.deleteFolder#1c295881 folder_id:int = Updates; -// Ports -channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; \ No newline at end of file +// LAYER 100 \ No newline at end of file diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 2c67e66c..b167fa57 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -18,6 +18,7 @@ import ast import os +import re import shutil HOME = "compiler/docs" @@ -29,8 +30,10 @@ TYPES_PATH = "pyrogram/api/types" FUNCTIONS_BASE = "functions" TYPES_BASE = "types" -shutil.rmtree(TYPES_BASE, ignore_errors=True) -shutil.rmtree(FUNCTIONS_BASE, ignore_errors=True) + +def snek(s: str): + s = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", s) + return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s).lower() def generate(source_path, base): @@ -50,9 +53,11 @@ def generate(source_path, base): for node in ast.walk(p): if isinstance(node, ast.ClassDef): name = node.name + break + else: + continue - # name = "".join([str(j.title()) for j in os.path.splitext(i)[0].split("_")]) - full_path = os.path.basename(path) + "/" + name + ".rst" + full_path = os.path.basename(path) + "/" + snek(name).replace("_", "-") + ".rst" if level: full_path = base + "/" + full_path @@ -65,7 +70,7 @@ def generate(source_path, base): title=name, title_markup="=" * len(name), full_class_path="pyrogram.api.{}".format( - os.path.splitext(full_path)[0].replace("/", ".") + ".".join(full_path.split("/")[:-1]) + "." + name ) ) ) @@ -82,7 +87,7 @@ def generate(source_path, base): entities = [] for i in v: - entities.append(i) + entities.append(snek(i).replace("_", "-")) if k != base: inner_path = base + "/" + k + "/index" + ".rst" @@ -98,6 +103,7 @@ def generate(source_path, base): with open(DESTINATION + "/" + inner_path, "w", encoding="utf-8") as f: if k == base: f.write(":tocdepth: 1\n\n") + k = "Raw " + k f.write( toctree.format( @@ -115,6 +121,8 @@ def start(): global page_template global toctree + shutil.rmtree(DESTINATION, ignore_errors=True) + with open(HOME + "/template/page.txt", encoding="utf-8") as f: page_template = f.read() diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index cbea977a..fa6ff67e 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -98,4 +98,5 @@ RESULTS_TOO_MUCH The result contains too many items RESULT_ID_DUPLICATE The result contains items with duplicated identifiers ACCESS_TOKEN_INVALID The bot access token is invalid INVITE_HASH_EXPIRED The chat invite link is no longer valid -USER_BANNED_IN_CHANNEL You are limited, check @SpamBot for details \ No newline at end of file +USER_BANNED_IN_CHANNEL You are limited, check @SpamBot for details +MESSAGE_EDIT_TIME_EXPIRED You can no longer edit this message \ No newline at end of file diff --git a/compiler/error/source/401_UNAUTHORIZED.tsv b/compiler/error/source/401_UNAUTHORIZED.tsv index 54b24dd7..e5cd3874 100644 --- a/compiler/error/source/401_UNAUTHORIZED.tsv +++ b/compiler/error/source/401_UNAUTHORIZED.tsv @@ -2,6 +2,7 @@ id message AUTH_KEY_UNREGISTERED The key is not registered in the system AUTH_KEY_INVALID The key is invalid USER_DEACTIVATED The user has been deleted/deactivated +USER_DEACTIVATED_BAN The user has been deleted/deactivated SESSION_REVOKED The authorization has been invalidated, because of the user terminating all sessions SESSION_EXPIRED The authorization has expired ACTIVE_USER_REQUIRED The method is only available to already activated users diff --git a/docs/sitemap.py b/docs/sitemap.py index 87c27849..4def886f 100644 --- a/docs/sitemap.py +++ b/docs/sitemap.py @@ -23,11 +23,11 @@ canonical = "https://docs.pyrogram.org/" dirs = { ".": ("weekly", 1.0), - "intro": ("weekly", 0.8), - "start": ("weekly", 0.8), - "api": ("weekly", 0.6), - "topics": ("weekly", 0.6), - "telegram": ("weekly", 0.4) + "intro": ("weekly", 0.9), + "start": ("weekly", 0.9), + "api": ("weekly", 0.8), + "topics": ("weekly", 0.8), + "telegram": ("weekly", 0.6) } diff --git a/docs/source/api/bound-methods.rst b/docs/source/api/bound-methods.rst index d93497fe..0622e6b8 100644 --- a/docs/source/api/bound-methods.rst +++ b/docs/source/api/bound-methods.rst @@ -22,43 +22,65 @@ some of the required arguments. .. currentmodule:: pyrogram -- Message_ -- CallbackQuery_ -- InlineQuery_ - -.. _Message: +Index +----- Message +^^^^^^^ + +.. hlist:: + :columns: 3 + + - :meth:`~Message.click` + - :meth:`~Message.delete` + - :meth:`~Message.download` + - :meth:`~Message.edit` + - :meth:`~Message.edit_caption` + - :meth:`~Message.edit_media` + - :meth:`~Message.edit_reply_markup` + - :meth:`~Message.forward` + - :meth:`~Message.pin` + - :meth:`~Message.reply` + - :meth:`~Message.reply_animation` + - :meth:`~Message.reply_audio` + - :meth:`~Message.reply_cached_media` + - :meth:`~Message.reply_chat_action` + - :meth:`~Message.reply_contact` + - :meth:`~Message.reply_document` + - :meth:`~Message.reply_game` + - :meth:`~Message.reply_inline_bot_result` + - :meth:`~Message.reply_location` + - :meth:`~Message.reply_media_group` + - :meth:`~Message.reply_photo` + - :meth:`~Message.reply_poll` + - :meth:`~Message.reply_sticker` + - :meth:`~Message.reply_venue` + - :meth:`~Message.reply_video` + - :meth:`~Message.reply_video_note` + - :meth:`~Message.reply_voice` + +CallbackQuery +^^^^^^^^^^^^^ + +.. hlist:: + :columns: 2 + + - :meth:`~CallbackQuery.answer` + +InlineQuery +^^^^^^^^^^^ + +.. hlist:: + :columns: 2 + + - :meth:`~InlineQuery.answer` + +----- + +Details ------- -- :meth:`Message.click()` -- :meth:`Message.delete()` -- :meth:`Message.download()` -- :meth:`Message.edit()` -- :meth:`Message.edit_caption()` -- :meth:`Message.edit_media()` -- :meth:`Message.edit_reply_markup()` -- :meth:`Message.forward()` -- :meth:`Message.pin()` -- :meth:`Message.reply()` -- :meth:`Message.reply_animation()` -- :meth:`Message.reply_audio()` -- :meth:`Message.reply_cached_media()` -- :meth:`Message.reply_chat_action()` -- :meth:`Message.reply_contact()` -- :meth:`Message.reply_document()` -- :meth:`Message.reply_game()` -- :meth:`Message.reply_inline_bot_result()` -- :meth:`Message.reply_location()` -- :meth:`Message.reply_media_group()` -- :meth:`Message.reply_photo()` -- :meth:`Message.reply_poll()` -- :meth:`Message.reply_sticker()` -- :meth:`Message.reply_venue()` -- :meth:`Message.reply_video()` -- :meth:`Message.reply_video_note()` -- :meth:`Message.reply_voice()` - +.. Message .. automethod:: Message.click() .. automethod:: Message.delete() .. automethod:: Message.download() @@ -87,16 +109,8 @@ Message .. automethod:: Message.reply_video_note() .. automethod:: Message.reply_voice() -.. _CallbackQuery: - -CallbackQuery -------------- - +.. CallbackQuery .. automethod:: CallbackQuery.answer() -.. _InlineQuery: - -InlineQuery ------------ - -.. automethod:: InlineQuery.answer() \ No newline at end of file +.. InlineQuery +.. automethod:: InlineQuery.answer() diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index be8376f5..ff31cb27 100644 --- a/docs/source/api/decorators.rst +++ b/docs/source/api/decorators.rst @@ -1,13 +1,13 @@ Decorators ========== -While still being methods bound to the :obj:`Client ` class, decorators are of a special kind and thus deserve a -dedicated page. +While still being methods bound to the :class:`~pyrogram.Client` class, decorators are of a special kind and thus +deserve a dedicated page. Decorators are able to register callback functions for handling updates in a much easier and cleaner way compared to -`Handlers `_; they do so by instantiating the correct handler and calling -:meth:`add_handler() `, automatically. All you need to do is adding the decorators on top -of your functions. +:doc:`Handlers `; they do so by instantiating the correct handler and calling +:meth:`~pyrogram.Client.add_handler`, automatically. All you need to do is adding the decorators on top of your +functions. .. code-block:: python :emphasize-lines: 6 @@ -24,25 +24,34 @@ of your functions. app.run() -.. currentmodule:: pyrogram.Client +.. currentmodule:: pyrogram -.. autosummary:: - :nosignatures: +Index +----- - on_message - on_callback_query - on_inline_query - on_deleted_messages - on_user_status - on_poll - on_disconnect - on_raw_update +.. hlist:: + :columns: 3 -.. automethod:: pyrogram.Client.on_message() -.. automethod:: pyrogram.Client.on_callback_query() -.. automethod:: pyrogram.Client.on_inline_query() -.. automethod:: pyrogram.Client.on_deleted_messages() -.. automethod:: pyrogram.Client.on_user_status() -.. automethod:: pyrogram.Client.on_poll() -.. automethod:: pyrogram.Client.on_disconnect() -.. automethod:: pyrogram.Client.on_raw_update() \ No newline at end of file + - :meth:`~Client.on_message` + - :meth:`~Client.on_callback_query` + - :meth:`~Client.on_inline_query` + - :meth:`~Client.on_deleted_messages` + - :meth:`~Client.on_user_status` + - :meth:`~Client.on_poll` + - :meth:`~Client.on_disconnect` + - :meth:`~Client.on_raw_update` + +----- + +Details +------- + +.. Decorators +.. autodecorator:: pyrogram.Client.on_message() +.. autodecorator:: pyrogram.Client.on_callback_query() +.. autodecorator:: pyrogram.Client.on_inline_query() +.. autodecorator:: pyrogram.Client.on_deleted_messages() +.. autodecorator:: pyrogram.Client.on_user_status() +.. autodecorator:: pyrogram.Client.on_poll() +.. autodecorator:: pyrogram.Client.on_disconnect() +.. autodecorator:: pyrogram.Client.on_raw_update() \ No newline at end of file diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst index 90c8e614..f91dd3d5 100644 --- a/docs/source/api/handlers.rst +++ b/docs/source/api/handlers.rst @@ -3,8 +3,8 @@ Update Handlers Handlers are used to instruct Pyrogram about which kind of updates you'd like to handle with your callback functions. -For a much more convenient way of registering callback functions have a look at `Decorators `_ instead. -In case you decided to manually create a handler, use :meth:`add_handler() ` to register +For a much more convenient way of registering callback functions have a look at :doc:`Decorators ` instead. +In case you decided to manually create a handler, use :class:`~pyrogram.Client.add_handler` to register it. .. code-block:: python @@ -25,18 +25,27 @@ it. .. currentmodule:: pyrogram -.. autosummary:: - :nosignatures: +Index +----- - MessageHandler - DeletedMessagesHandler - CallbackQueryHandler - InlineQueryHandler - UserStatusHandler - PollHandler - DisconnectHandler - RawUpdateHandler +.. hlist:: + :columns: 3 + - :class:`MessageHandler` + - :class:`DeletedMessagesHandler` + - :class:`CallbackQueryHandler` + - :class:`InlineQueryHandler` + - :class:`UserStatusHandler` + - :class:`PollHandler` + - :class:`DisconnectHandler` + - :class:`RawUpdateHandler` + +----- + +Details +------- + +.. Handlers .. autoclass:: MessageHandler() .. autoclass:: DeletedMessagesHandler() .. autoclass:: CallbackQueryHandler() diff --git a/docs/source/api/methods.rst b/docs/source/api/methods.rst index 7c061d3a..b9fa180c 100644 --- a/docs/source/api/methods.rst +++ b/docs/source/api/methods.rst @@ -1,7 +1,7 @@ Available Methods ================= -All Pyrogram methods listed here are bound to a :obj:`Client ` instance. +All Pyrogram methods listed here are bound to a :class:`~pyrogram.Client` instance. .. code-block:: python :emphasize-lines: 6 @@ -13,253 +13,253 @@ All Pyrogram methods listed here are bound to a :obj:`Client ` with app: app.send_message("haskell", "hi") -.. currentmodule:: pyrogram.Client +.. currentmodule:: pyrogram + +Index +----- Utilities ---------- +^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 4 - start - stop - restart - idle - run - add_handler - remove_handler - send - resolve_peer - save_file - stop_transmission + - :meth:`~Client.start` + - :meth:`~Client.stop` + - :meth:`~Client.restart` + - :meth:`~Client.idle` + - :meth:`~Client.run` + - :meth:`~Client.add_handler` + - :meth:`~Client.remove_handler` + - :meth:`~Client.send` + - :meth:`~Client.resolve_peer` + - :meth:`~Client.save_file` + - :meth:`~Client.stop_transmission` Messages --------- +^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - send_message - forward_messages - send_photo - send_audio - send_document - send_sticker - send_video - send_animation - send_voice - send_video_note - send_media_group - send_location - send_venue - send_contact - send_cached_media - send_chat_action - edit_message_text - edit_message_caption - edit_message_reply_markup - edit_message_media - delete_messages - get_messages - get_history - get_history_count - iter_history - send_poll - vote_poll - stop_poll - retract_vote - download_media + - :meth:`~Client.send_message` + - :meth:`~Client.forward_messages` + - :meth:`~Client.send_photo` + - :meth:`~Client.send_audio` + - :meth:`~Client.send_document` + - :meth:`~Client.send_sticker` + - :meth:`~Client.send_animated_sticker` + - :meth:`~Client.send_video` + - :meth:`~Client.send_animation` + - :meth:`~Client.send_voice` + - :meth:`~Client.send_video_note` + - :meth:`~Client.send_media_group` + - :meth:`~Client.send_location` + - :meth:`~Client.send_venue` + - :meth:`~Client.send_contact` + - :meth:`~Client.send_cached_media` + - :meth:`~Client.send_chat_action` + - :meth:`~Client.edit_message_text` + - :meth:`~Client.edit_message_caption` + - :meth:`~Client.edit_message_reply_markup` + - :meth:`~Client.edit_message_media` + - :meth:`~Client.delete_messages` + - :meth:`~Client.get_messages` + - :meth:`~Client.get_history` + - :meth:`~Client.get_history_count` + - :meth:`~Client.iter_history` + - :meth:`~Client.send_poll` + - :meth:`~Client.vote_poll` + - :meth:`~Client.stop_poll` + - :meth:`~Client.retract_vote` + - :meth:`~Client.download_media` Chats ------ +^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - join_chat - leave_chat - kick_chat_member - unban_chat_member - restrict_chat_member - promote_chat_member - export_chat_invite_link - set_chat_photo - delete_chat_photo - set_chat_title - set_chat_description - pin_chat_message - unpin_chat_message - get_chat - get_chat_member - get_chat_members - get_chat_members_count - iter_chat_members - get_dialogs - iter_dialogs - get_dialogs_count - restrict_chat - update_chat_username + - :meth:`~Client.join_chat` + - :meth:`~Client.leave_chat` + - :meth:`~Client.kick_chat_member` + - :meth:`~Client.unban_chat_member` + - :meth:`~Client.restrict_chat_member` + - :meth:`~Client.promote_chat_member` + - :meth:`~Client.export_chat_invite_link` + - :meth:`~Client.set_chat_photo` + - :meth:`~Client.delete_chat_photo` + - :meth:`~Client.set_chat_title` + - :meth:`~Client.set_chat_description` + - :meth:`~Client.pin_chat_message` + - :meth:`~Client.unpin_chat_message` + - :meth:`~Client.get_chat` + - :meth:`~Client.get_chat_member` + - :meth:`~Client.get_chat_members` + - :meth:`~Client.get_chat_members_count` + - :meth:`~Client.iter_chat_members` + - :meth:`~Client.get_dialogs` + - :meth:`~Client.iter_dialogs` + - :meth:`~Client.get_dialogs_count` + - :meth:`~Client.restrict_chat` + - :meth:`~Client.update_chat_username` Users ------ +^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - get_me - get_users - get_user_profile_photos - get_user_profile_photos_count - set_user_profile_photo - delete_user_profile_photos - update_username + - :meth:`~Client.get_me` + - :meth:`~Client.get_users` + - :meth:`~Client.get_profile_photos` + - :meth:`~Client.get_profile_photos_count` + - :meth:`~Client.iter_profile_photos` + - :meth:`~Client.set_profile_photo` + - :meth:`~Client.delete_profile_photos` + - :meth:`~Client.update_username` + - :meth:`~Client.get_user_dc` Contacts --------- +^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - add_contacts - get_contacts - get_contacts_count - delete_contacts + - :meth:`~Client.add_contacts` + - :meth:`~Client.get_contacts` + - :meth:`~Client.get_contacts_count` + - :meth:`~Client.delete_contacts` Password --------- +^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - enable_cloud_password - change_cloud_password - remove_cloud_password + - :meth:`~Client.enable_cloud_password` + - :meth:`~Client.change_cloud_password` + - :meth:`~Client.remove_cloud_password` Bots ----- +^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - get_inline_bot_results - send_inline_bot_result - answer_callback_query - answer_inline_query - request_callback_answer - send_game - set_game_score - get_game_high_scores + - :meth:`~Client.get_inline_bot_results` + - :meth:`~Client.send_inline_bot_result` + - :meth:`~Client.answer_callback_query` + - :meth:`~Client.answer_inline_query` + - :meth:`~Client.request_callback_answer` + - :meth:`~Client.send_game` + - :meth:`~Client.set_game_score` + - :meth:`~Client.get_game_high_scores` + +----- + +Details +------- .. Utilities - --------- - -.. automethod:: pyrogram.Client.start() -.. automethod:: pyrogram.Client.stop() -.. automethod:: pyrogram.Client.restart() -.. automethod:: pyrogram.Client.idle() -.. automethod:: pyrogram.Client.run() -.. automethod:: pyrogram.Client.add_handler() -.. automethod:: pyrogram.Client.remove_handler() -.. automethod:: pyrogram.Client.send() -.. automethod:: pyrogram.Client.resolve_peer() -.. automethod:: pyrogram.Client.save_file() -.. automethod:: pyrogram.Client.stop_transmission() +.. automethod:: Client.start() +.. automethod:: Client.stop() +.. automethod:: Client.restart() +.. automethod:: Client.idle() +.. automethod:: Client.run() +.. automethod:: Client.add_handler() +.. automethod:: Client.remove_handler() +.. automethod:: Client.send() +.. automethod:: Client.resolve_peer() +.. automethod:: Client.save_file() +.. automethod:: Client.stop_transmission() .. Messages - -------- - -.. automethod:: pyrogram.Client.send_message() -.. automethod:: pyrogram.Client.forward_messages() -.. automethod:: pyrogram.Client.send_photo() -.. automethod:: pyrogram.Client.send_audio() -.. automethod:: pyrogram.Client.send_document() -.. automethod:: pyrogram.Client.send_sticker() -.. automethod:: pyrogram.Client.send_video() -.. automethod:: pyrogram.Client.send_animation() -.. automethod:: pyrogram.Client.send_voice() -.. automethod:: pyrogram.Client.send_video_note() -.. automethod:: pyrogram.Client.send_media_group() -.. automethod:: pyrogram.Client.send_location() -.. automethod:: pyrogram.Client.send_venue() -.. automethod:: pyrogram.Client.send_contact() -.. automethod:: pyrogram.Client.send_cached_media() -.. automethod:: pyrogram.Client.send_chat_action() -.. automethod:: pyrogram.Client.edit_message_text() -.. automethod:: pyrogram.Client.edit_message_caption() -.. automethod:: pyrogram.Client.edit_message_reply_markup() -.. automethod:: pyrogram.Client.edit_message_media() -.. automethod:: pyrogram.Client.delete_messages() -.. automethod:: pyrogram.Client.get_messages() -.. automethod:: pyrogram.Client.get_history() -.. automethod:: pyrogram.Client.get_history_count() -.. automethod:: pyrogram.Client.iter_history() -.. automethod:: pyrogram.Client.send_poll() -.. automethod:: pyrogram.Client.vote_poll() -.. automethod:: pyrogram.Client.stop_poll() -.. automethod:: pyrogram.Client.retract_vote() -.. automethod:: pyrogram.Client.download_media() +.. automethod:: Client.send_message() +.. automethod:: Client.forward_messages() +.. automethod:: Client.send_photo() +.. automethod:: Client.send_audio() +.. automethod:: Client.send_document() +.. automethod:: Client.send_sticker() +.. automethod:: Client.send_animated_sticker() +.. automethod:: Client.send_video() +.. automethod:: Client.send_animation() +.. automethod:: Client.send_voice() +.. automethod:: Client.send_video_note() +.. automethod:: Client.send_media_group() +.. automethod:: Client.send_location() +.. automethod:: Client.send_venue() +.. automethod:: Client.send_contact() +.. automethod:: Client.send_cached_media() +.. automethod:: Client.send_chat_action() +.. automethod:: Client.edit_message_text() +.. automethod:: Client.edit_message_caption() +.. automethod:: Client.edit_message_reply_markup() +.. automethod:: Client.edit_message_media() +.. automethod:: Client.delete_messages() +.. automethod:: Client.get_messages() +.. automethod:: Client.get_history() +.. automethod:: Client.get_history_count() +.. automethod:: Client.iter_history() +.. automethod:: Client.send_poll() +.. automethod:: Client.vote_poll() +.. automethod:: Client.stop_poll() +.. automethod:: Client.retract_vote() +.. automethod:: Client.download_media() .. Chats - ----- - -.. automethod:: pyrogram.Client.join_chat() -.. automethod:: pyrogram.Client.leave_chat() -.. automethod:: pyrogram.Client.kick_chat_member() -.. automethod:: pyrogram.Client.unban_chat_member() -.. automethod:: pyrogram.Client.restrict_chat_member() -.. automethod:: pyrogram.Client.promote_chat_member() -.. automethod:: pyrogram.Client.export_chat_invite_link() -.. automethod:: pyrogram.Client.set_chat_photo() -.. automethod:: pyrogram.Client.delete_chat_photo() -.. automethod:: pyrogram.Client.set_chat_title() -.. automethod:: pyrogram.Client.set_chat_description() -.. automethod:: pyrogram.Client.pin_chat_message() -.. automethod:: pyrogram.Client.unpin_chat_message() -.. automethod:: pyrogram.Client.get_chat() -.. automethod:: pyrogram.Client.get_chat_member() -.. automethod:: pyrogram.Client.get_chat_members() -.. automethod:: pyrogram.Client.get_chat_members_count() -.. automethod:: pyrogram.Client.iter_chat_members() -.. automethod:: pyrogram.Client.get_dialogs() -.. automethod:: pyrogram.Client.iter_dialogs() -.. automethod:: pyrogram.Client.get_dialogs_count() -.. automethod:: pyrogram.Client.restrict_chat() -.. automethod:: pyrogram.Client.update_chat_username() +.. automethod:: Client.join_chat() +.. automethod:: Client.leave_chat() +.. automethod:: Client.kick_chat_member() +.. automethod:: Client.unban_chat_member() +.. automethod:: Client.restrict_chat_member() +.. automethod:: Client.promote_chat_member() +.. automethod:: Client.export_chat_invite_link() +.. automethod:: Client.set_chat_photo() +.. automethod:: Client.delete_chat_photo() +.. automethod:: Client.set_chat_title() +.. automethod:: Client.set_chat_description() +.. automethod:: Client.pin_chat_message() +.. automethod:: Client.unpin_chat_message() +.. automethod:: Client.get_chat() +.. automethod:: Client.get_chat_member() +.. automethod:: Client.get_chat_members() +.. automethod:: Client.get_chat_members_count() +.. automethod:: Client.iter_chat_members() +.. automethod:: Client.get_dialogs() +.. automethod:: Client.iter_dialogs() +.. automethod:: Client.get_dialogs_count() +.. automethod:: Client.restrict_chat() +.. automethod:: Client.update_chat_username() .. Users - ----- - -.. automethod:: pyrogram.Client.get_me() -.. automethod:: pyrogram.Client.get_users() -.. automethod:: pyrogram.Client.get_user_profile_photos() -.. automethod:: pyrogram.Client.get_user_profile_photos_count() -.. automethod:: pyrogram.Client.set_user_profile_photo() -.. automethod:: pyrogram.Client.delete_user_profile_photos() -.. automethod:: pyrogram.Client.update_username() +.. automethod:: Client.get_me() +.. automethod:: Client.get_users() +.. automethod:: Client.get_profile_photos() +.. automethod:: Client.get_profile_photos_count() +.. automethod:: Client.iter_profile_photos() +.. automethod:: Client.set_profile_photo() +.. automethod:: Client.delete_profile_photos() +.. automethod:: Client.update_username() +.. automethod:: Client.get_user_dc() .. Contacts - -------- - -.. automethod:: pyrogram.Client.add_contacts() -.. automethod:: pyrogram.Client.get_contacts() -.. automethod:: pyrogram.Client.get_contacts_count() -.. automethod:: pyrogram.Client.delete_contacts() +.. automethod:: Client.add_contacts() +.. automethod:: Client.get_contacts() +.. automethod:: Client.get_contacts_count() +.. automethod:: Client.delete_contacts() .. Password - -------- - -.. automethod:: pyrogram.Client.enable_cloud_password() -.. automethod:: pyrogram.Client.change_cloud_password() -.. automethod:: pyrogram.Client.remove_cloud_password() +.. automethod:: Client.enable_cloud_password() +.. automethod:: Client.change_cloud_password() +.. automethod:: Client.remove_cloud_password() .. Bots - ---- - -.. automethod:: pyrogram.Client.get_inline_bot_results() -.. automethod:: pyrogram.Client.send_inline_bot_result() -.. automethod:: pyrogram.Client.answer_callback_query() -.. automethod:: pyrogram.Client.answer_inline_query() -.. automethod:: pyrogram.Client.request_callback_answer() -.. automethod:: pyrogram.Client.send_game() -.. automethod:: pyrogram.Client.set_game_score() -.. automethod:: pyrogram.Client.get_game_high_scores() +.. automethod:: Client.get_inline_bot_results() +.. automethod:: Client.send_inline_bot_result() +.. automethod:: Client.answer_callback_query() +.. automethod:: Client.answer_inline_query() +.. automethod:: Client.request_callback_answer() +.. automethod:: Client.send_game() +.. automethod:: Client.set_game_score() +.. automethod:: Client.get_game_high_scores() diff --git a/docs/source/api/types.rst b/docs/source/api/types.rst index d911520c..15f81ae7 100644 --- a/docs/source/api/types.rst +++ b/docs/source/api/types.rst @@ -15,102 +15,108 @@ All Pyrogram types listed here are accessible through the main package directly. .. currentmodule:: pyrogram +Index +----- + Users & Chats -------------- +^^^^^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 5 - User - UserStatus - Chat - ChatPreview - ChatPhoto - ChatMember - ChatMembers - ChatPermissions - Dialog - Dialogs + - :class:`User` + - :class:`UserStatus` + - :class:`Chat` + - :class:`ChatPreview` + - :class:`ChatPhoto` + - :class:`ChatMember` + - :class:`ChatMembers` + - :class:`ChatPermissions` + - :class:`Dialog` + - :class:`Dialogs` Messages & Media ----------------- +^^^^^^^^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 5 - Message - Messages - MessageEntity - Photo - PhotoSize - UserProfilePhotos - Audio - Document - Animation - Video - Voice - VideoNote - Contact - Location - Venue - Sticker - Game - Poll - PollOption + - :class:`Message` + - :class:`Messages` + - :class:`MessageEntity` + - :class:`Photo` + - :class:`Photos` + - :class:`Thumbnail` + - :class:`Audio` + - :class:`Document` + - :class:`Animation` + - :class:`Video` + - :class:`Voice` + - :class:`VideoNote` + - :class:`Contact` + - :class:`Location` + - :class:`Venue` + - :class:`Sticker` + - :class:`Game` + - :class:`Poll` + - :class:`PollOption` Keyboards ---------- +^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 4 - ReplyKeyboardMarkup - KeyboardButton - ReplyKeyboardRemove - InlineKeyboardMarkup - InlineKeyboardButton - ForceReply - CallbackQuery - GameHighScore - GameHighScores - CallbackGame + - :class:`ReplyKeyboardMarkup` + - :class:`KeyboardButton` + - :class:`ReplyKeyboardRemove` + - :class:`InlineKeyboardMarkup` + - :class:`InlineKeyboardButton` + - :class:`ForceReply` + - :class:`CallbackQuery` + - :class:`GameHighScore` + - :class:`GameHighScores` + - :class:`CallbackGame` Input Media ------------ +^^^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 4 - InputMedia - InputMediaPhoto - InputMediaVideo - InputMediaAudio - InputMediaAnimation - InputMediaDocument - InputPhoneContact + - :class:`InputMedia` + - :class:`InputMediaPhoto` + - :class:`InputMediaVideo` + - :class:`InputMediaAudio` + - :class:`InputMediaAnimation` + - :class:`InputMediaDocument` + - :class:`InputPhoneContact` Inline Mode ------------- +^^^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - InlineQuery - InlineQueryResult - InlineQueryResultArticle + - :class:`InlineQuery` + - :class:`InlineQueryResult` + - :class:`InlineQueryResultArticle` InputMessageContent -------------------- +^^^^^^^^^^^^^^^^^^^ -.. autosummary:: - :nosignatures: +.. hlist:: + :columns: 3 - InputMessageContent - InputTextMessageContent + - :class:`InputMessageContent` + - :class:`InputTextMessageContent` + +----- + +Details +------- .. User & Chats - ------------ - .. autoclass:: User() .. autoclass:: UserStatus() .. autoclass:: Chat() @@ -123,14 +129,12 @@ InputMessageContent .. autoclass:: Dialogs() .. Messages & Media - ---------------- - .. autoclass:: Message() .. autoclass:: Messages() .. autoclass:: MessageEntity() .. autoclass:: Photo() -.. autoclass:: PhotoSize() -.. autoclass:: UserProfilePhotos() +.. autoclass:: Photos() +.. autoclass:: Thumbnail() .. autoclass:: Audio() .. autoclass:: Document() .. autoclass:: Animation() @@ -146,8 +150,6 @@ InputMessageContent .. autoclass:: PollOption() .. Keyboards - --------- - .. autoclass:: ReplyKeyboardMarkup() .. autoclass:: KeyboardButton() .. autoclass:: ReplyKeyboardRemove() @@ -160,8 +162,6 @@ InputMessageContent .. autoclass:: CallbackGame() .. Input Media - ----------- - .. autoclass:: InputMedia() .. autoclass:: InputMediaPhoto() .. autoclass:: InputMediaVideo() @@ -171,14 +171,10 @@ InputMessageContent .. autoclass:: InputPhoneContact() .. Inline Mode - ----------- - .. autoclass:: InlineQuery() .. autoclass:: InlineQueryResult() .. autoclass:: InlineQueryResultArticle() .. InputMessageContent - ------------------- - .. autoclass:: InputMessageContent() .. autoclass:: InputTextMessageContent() diff --git a/docs/source/conf.py b/docs/source/conf.py index e079ec68..7ddeaa94 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,7 +43,6 @@ autodoc_member_order = "bysource" version = __version__ release = version -version_rst = ".. |version| replace:: {}".format(version) templates_path = ["_templates"] @@ -61,7 +60,8 @@ html_theme_options = { "collapse_navigation": True, "sticky_navigation": False, "logo_only": True, - "display_version": True + "display_version": True, + "style_external_links": True } html_logo = "_images/pyrogram.png" diff --git a/docs/source/faq.rst b/docs/source/faq.rst index b42332cd..a0fe3331 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -17,10 +17,9 @@ What is Pyrogram? **Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and C. It enables you to easily create custom applications for both user and bot identities (bot API alternative) via the -`MTProto API`_ with the Python programming language. +:doc:`MTProto API ` with the Python programming language. .. _Telegram: https://telegram.org -.. _MTProto API: topics/mtproto-vs-botapi#what-is-the-mtproto-api Where does the name come from? ------------------------------ @@ -47,19 +46,17 @@ Why Pyrogram? - **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted. - **Updated**, to make use of the latest Telegram API version and features. - **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed. -- **Pluggable**: The `Smart Plugin`_ system allows to write components with minimal boilerplate code. -- **Comprehensive**: Execute any `advanced action`_ an official client is able to do, and even more. +- **Pluggable**: The :doc:`Smart Plugin ` system allows to write components with minimal + boilerplate code. +- **Comprehensive**: Execute any :doc:`advanced action ` an official client is able to do, and + even more. .. _TgCrypto: https://github.com/pyrogram/tgcrypto -.. _Smart Plugin: topics/smart-plugins -.. _advanced action: topics/advanced-usage What can MTProto do more than the Bot API? ------------------------------------------ -For a detailed answer, please refer to the `MTProto vs. Bot API`_ page. - -.. _MTProto vs. Bot API: topics/mtproto-vs-botapi +For a detailed answer, please refer to the :doc:`MTProto vs. Bot API ` page. Why do I need an API key for bots? ---------------------------------- @@ -97,9 +94,9 @@ Telegram is slowly changing some server's internals and it's doing it in such a inevitably. Not only this, but it seems that the new, hypothetical, file ids could also possibly expire at anytime, thus losing the *persistence* feature. -This change will most likely affect the official `Bot API `_ too -(unless Telegram implements some workarounds server-side to keep backwards compatibility, which Pyrogram could in turn -make use of) and we can expect a proper notice from Telegram. +This change will most likely affect the official :doc:`Bot API ` too (unless Telegram +implements some workarounds server-side to keep backwards compatibility, which Pyrogram could in turn make use of) and +we can expect a proper notice from Telegram. Can I use multiple clients at once on the same account? ------------------------------------------------------- @@ -125,8 +122,8 @@ from the beginning every time, and use one separate session for each parallel cl I started a client and nothing happens! --------------------------------------- -If you are connecting from Russia, China or Iran `you need a proxy`_, because Telegram could be partially or -totally blocked in those countries. +If you are connecting from Russia, China or Iran :doc:`you need a proxy `, because Telegram could be +partially or totally blocked in those countries. Another possible cause might be network issues, either yours or Telegram's. To confirm this, add the following code on the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable network @@ -146,8 +143,6 @@ fails or not: - DC4: ``149.154.167.91`` - DC5: ``91.108.56.149`` -.. _you need a proxy: topics/proxy - I keep getting PEER_ID_INVALID error! ------------------------------------------- @@ -160,6 +155,15 @@ things: chats). - The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``. +My verification code expires immediately! +----------------------------------------- + +That is because you likely shared it across any of your Telegram chats. Yes, that's right: the server keeps scanning the +messages you send and if an active verification code is found it will immediately expire, automatically. + +The reason behind this is to protect unaware users from giving their account access to any potential scammer, but if you +legitimately want to share your account(s) verification codes, consider scrambling them, e.g. ``12345`` → ``1-2-3-4-5``. + My account has been deactivated/limited! ---------------------------------------- @@ -179,23 +183,15 @@ However, you might be right, and your account was deactivated/limited without an mistakes by either the automatic systems or a moderator. In such cases you can kindly email Telegram at recover@telegram.org, contact `@smstelegram`_ on Twitter or use `this form`_. +Are there any secret easter eggs? +--------------------------------- + +Yes. If you found one, `let me know`_! + +.. _let me know: https://t.me/pyrogram + .. _@smstelegram: https://twitter.com/smstelegram .. _this form: https://telegram.org/support -About the License ------------------ - -.. image:: https://www.gnu.org/graphics/lgplv3-with-text-154x68.png - :align: left - -Pyrogram is free software and is currently licensed under the terms of the -`GNU Lesser General Public License v3 or later (LGPLv3+)`_. In short: you may use, redistribute and/or modify it -provided that modifications are described and licensed for free under LGPLv3+. - -In other words: you can use and integrate Pyrogram into your own code --- either open source, under the same or -different license, or even proprietary --- without being required to release the source code of your own applications. -However, any modifications to the library itself are required to be published for free under the same LGPLv3+ license. - -.. _GNU Lesser General Public License v3 or later (LGPLv3+): https://github.com/pyrogram/pyrogram/blob/develop/COPYING.lesser .. _Bug Report: https://github.com/pyrogram/pyrogram/issues/new?labels=bug&template=bug_report.md .. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst index 5f00cbfd..72d308b7 100644 --- a/docs/source/glossary.rst +++ b/docs/source/glossary.rst @@ -18,7 +18,7 @@ general. Some words may as well link to dedicated articles in case the topic is API key A secret code used to authenticate and/or authorize a specific application to Telegram in order for it to control how the API is being used, for example, to prevent abuses of the API. - `More on API keys `_. + :doc:`More on API keys `. DC Also known as *data center*, is a place where lots of computer systems are housed and used together in order to @@ -30,21 +30,21 @@ general. Some words may as well link to dedicated articles in case the topic is RPCError An error caused by an RPC which must be returned in place of the successful result in order to let the caller - know something went wrong. `More on RPCError `_. + know something went wrong. :doc:`More on RPCError `. MTProto The name of the custom-made, open and encrypted protocol by Telegram, implemented in Pyrogram. - `More on MTProto `_. + :doc:`More on MTProto `. MTProto API The Telegram main API Pyrogram makes use of, which is able to connect both users and normal bots to Telegram using MTProto as application layer protocol and execute any method Telegram provides from its public TL-schema. - `More on MTProto API `_. + :doc:`More on MTProto API `. Bot API The Telegram Bot API that is able to only connect normal bots only to Telegram using HTTP as application layer protocol and allows to execute a sub-set of the main Telegram API. - `More on Bot API `_. + :doc:`More on Bot API `. Pyrogrammer A developer that uses Pyrogram to build Telegram applications. @@ -65,11 +65,11 @@ general. Some words may as well link to dedicated articles in case the topic is Handler An object that wraps around a callback function that is *actually meant* to be registered into the framework, which will then be able to handle a specific kind of events, such as a new incoming message, for example. - `More on Handlers `_. + :doc:`More on Handlers `. Decorator Also known as *function decorator*, in Python, is a callable object that is used to modify another function. Decorators in Pyrogram are used to automatically register callback functions for handling updates. - `More on Decorators `_. + :doc:`More on Decorators `. .. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md diff --git a/docs/source/index.rst b/docs/source/index.rst index de91015f..b99fcf3d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -42,10 +42,9 @@ Welcome to Pyrogram **Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the -`MTProto API`_. +:doc:`MTProto API `. .. _Telegram: https://telegram.org -.. _MTProto API: topics/mtproto-vs-botapi#what-is-the-mtproto-api How the Documentation is Organized ---------------------------------- @@ -60,15 +59,10 @@ First Steps .. hlist:: :columns: 2 - - `Quick Start`_: Overview to get you started quickly. - - `Calling Methods`_: How to call Pyrogram's methods. - - `Handling Updates`_: How to handle Telegram updates. - - `Error Handling`_: How to handle API errors correctly. - -.. _Quick Start: intro/quickstart -.. _Calling Methods: start/invoking -.. _Handling Updates: start/updates -.. _Error Handling: start/errors + - :doc:`Quick Start `: Overview to get you started quickly. + - :doc:`Calling Methods `: How to call Pyrogram's methods. + - :doc:`Handling Updates `: How to handle Telegram updates. + - :doc:`Error Handling `: How to handle API errors correctly. API Reference ------------- @@ -76,15 +70,10 @@ API Reference .. hlist:: :columns: 2 - - `Pyrogram Client`_: Reference details about the Client class. - - `Available Methods`_: List of available high-level methods. - - `Available Types`_: List of available high-level types. - - `Bound Methods`_: List of convenient bound methods. - -.. _Pyrogram Client: ./api/client -.. _Available Methods: api/methods -.. _Available Types: api/types -.. _Bound Methods: api/bound-methods + - :doc:`Pyrogram Client `: Reference details about the Client class. + - :doc:`Available Methods `: List of available high-level methods. + - :doc:`Available Types `: List of available high-level types. + - :doc:`Bound Methods `: List of convenient bound methods. Meta ---- @@ -92,17 +81,12 @@ Meta .. hlist:: :columns: 2 - - `Pyrogram FAQ`_: Answers to common Pyrogram questions. - - `Pyrogram Glossary`_: List of words with brief explanations. - - `Release Notes`_: Release notes for Pyrogram releases. - - `Powered by Pyrogram`_: Collection of Pyrogram Projects. - - `Support Pyrogram`_: Ways to show your appreciation. - -.. _Pyrogram FAQ: faq -.. _Pyrogram Glossary: glossary -.. _Release Notes: releases -.. _Powered by Pyrogram: powered-by -.. _Support Pyrogram: support-pyrogram + - :doc:`Pyrogram FAQ `: Answers to common Pyrogram questions. + - :doc:`Pyrogram Glossary `: List of words with brief explanations. + - :doc:`Release Notes `: Release notes for Pyrogram releases. + - :doc:`Powered by Pyrogram `: Collection of Pyrogram Projects. + - :doc:`Support Pyrogram `: Ways to show your appreciation. + - :doc:`About the License `: Information about the Project license. .. toctree:: :hidden: @@ -163,10 +147,13 @@ Meta releases powered-by support-pyrogram + license .. toctree:: :hidden: :caption: Telegram API telegram/functions/index - telegram/types/index \ No newline at end of file + telegram/types/index + +Last updated on |today| \ No newline at end of file diff --git a/docs/source/intro/install.rst b/docs/source/intro/install.rst index fe804e79..82ab4c0b 100644 --- a/docs/source/intro/install.rst +++ b/docs/source/intro/install.rst @@ -20,7 +20,7 @@ Install Pyrogram $ pip3 install -U pyrogram -- or, with TgCrypto_ as extra requirement (recommended): +- or, with :doc:`TgCrypto <../topics/tgcrypto>` as extra requirement (recommended): .. code-block:: text @@ -89,5 +89,4 @@ If no error shows up you are good to go. >>> pyrogram.__version__ '|version|' -.. _TgCrypto: ../topics/tgcrypto .. _`Github repo`: http://github.com/pyrogram/pyrogram diff --git a/docs/source/intro/quickstart.rst b/docs/source/intro/quickstart.rst index 1aa7989e..a7a7e377 100644 --- a/docs/source/intro/quickstart.rst +++ b/docs/source/intro/quickstart.rst @@ -43,7 +43,7 @@ Enjoy the API That was just a quick overview that barely scratched the surface! In the next few pages of the introduction, we'll take a much more in-depth look of what we have just done above. -Feeling eager to continue? You can take a shortcut to `Calling Methods`_ and come back later to learn some more details. +Feeling eager to continue? You can take a shortcut to :doc:`Calling Methods <../start/invoking>` and come back later to +learn some more details. .. _community: //t.me/Pyrogram -.. _Calling Methods: ../start/invoking \ No newline at end of file diff --git a/docs/source/intro/setup.rst b/docs/source/intro/setup.rst index 9c0cc6d4..6273b2b2 100644 --- a/docs/source/intro/setup.rst +++ b/docs/source/intro/setup.rst @@ -1,8 +1,8 @@ Project Setup ============= -We have just `installed Pyrogram`_. In this page we'll discuss what you need to do in order to set up a project with -the library. Let's see how it's done. +We have just :doc:`installed Pyrogram `. In this page we'll discuss what you need to do in order to set up a +project with the library. Let's see how it's done. API Keys -------- @@ -26,7 +26,7 @@ The very first step requires you to obtain a valid Telegram API key (API id/hash Configuration ------------- -Having the API key from the `previous step <#api-keys>`_ in handy, we can now begin to configure a Pyrogram project. +Having the API key from the previous step in handy, we can now begin to configure a Pyrogram project. There are two ways to do so, and you can choose what fits better for you: - First option (recommended): create a new ``config.ini`` file at the root of your working directory, copy-paste the @@ -57,5 +57,3 @@ There are two ways to do so, and you can choose what fits better for you: To keep code snippets clean and concise, from now on it is assumed you are making use of the ``config.ini`` file, thus, the *api_id* and *api_hash* parameters usage won't be shown anymore. - -.. _installed Pyrogram: install.html diff --git a/docs/source/license.rst b/docs/source/license.rst new file mode 100644 index 00000000..43f59d73 --- /dev/null +++ b/docs/source/license.rst @@ -0,0 +1,15 @@ +About the License +================= + +.. image:: https://www.gnu.org/graphics/lgplv3-with-text-154x68.png + :align: left + +Pyrogram is free software and is currently licensed under the terms of the +`GNU Lesser General Public License v3 or later (LGPLv3+)`_. In short: you may use, redistribute and/or modify it +provided that modifications are described and licensed for free under LGPLv3+. + +In other words: you can use and integrate Pyrogram into your own code --- either open source, under the same or a +different license, or even proprietary --- without being required to release the source code of your own applications. +However, any modifications to the library itself are required to be published for free under the same LGPLv3+ license. + +.. _GNU Lesser General Public License v3 or later (LGPLv3+): https://github.com/pyrogram/pyrogram/blob/develop/COPYING.lesser \ No newline at end of file diff --git a/docs/source/start/auth.rst b/docs/source/start/auth.rst index e00b08a0..79264bfa 100644 --- a/docs/source/start/auth.rst +++ b/docs/source/start/auth.rst @@ -1,7 +1,7 @@ Authorization ============= -Once a `project is set up`_, you will still have to follow a few steps before you can actually use Pyrogram to make +Once a :doc:`project is set up <../intro/setup>`, you will still have to follow a few steps before you can actually use Pyrogram to make API calls. This section provides all the information you need in order to authorize yourself as user or bot. User Authorization @@ -9,8 +9,8 @@ User Authorization In order to use the API, Telegram requires that users be authorized via their phone numbers. Pyrogram automatically manages this process, all you need to do is create an instance of the -:class:`Client ` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call -the :meth:`run() ` method: +:class:`~pyrogram.Client` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call +the :meth:`~pyrogram.Client.run` method: .. code-block:: python @@ -47,7 +47,7 @@ Bot Authorization Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by the `Bot Father`_. Bot tokens replace the users' phone numbers only — you still need to -`configure a Telegram API key <../intro/setup#configuration>`_ with Pyrogram, even when using bots. +:doc:`configure a Telegram API key <../intro/setup>` with Pyrogram, even when using bots. The authorization process is automatically managed. All you need to do is choose a ``session_name`` (can be anything, usually your bot username) and pass your bot token using the ``bot_token`` parameter. The session file will be named @@ -64,6 +64,5 @@ after the session name, which will be ``my_bot.session`` for the example below. app.run() -.. _project is set up: ../intro/setup .. _Country Code: https://en.wikipedia.org/wiki/List_of_country_calling_codes .. _Bot Father: https://t.me/botfather \ No newline at end of file diff --git a/docs/source/start/invoking.rst b/docs/source/start/invoking.rst index ef9bc373..1357cd7b 100644 --- a/docs/source/start/invoking.rst +++ b/docs/source/start/invoking.rst @@ -1,8 +1,8 @@ Calling Methods =============== -At this point, we have successfully `installed Pyrogram`_ and authorized_ our account; we are now aiming towards the -core of the library. It's time to start playing with the API! +At this point, we have successfully :doc:`installed Pyrogram <../intro/install>` and :doc:`authorized ` our +account; we are now aiming towards the core of the library. It's time to start playing with the API! Basic Usage ----------- @@ -63,8 +63,8 @@ Context Manager --------------- You can also use Pyrogram's Client in a context manager with the ``with`` statement. The client will automatically -:meth:`start() ` and :meth:`stop() ` gracefully, even in case of unhandled -exceptions in your code. The example above can be therefore rewritten in a much nicer way: +:meth:`~pyrogram.Client.start` and :meth:`~pyrogram.Client.stop` gracefully, even in case of unhandled exceptions in +your code. The example above can be therefore rewritten in a much nicer way: .. code-block:: python @@ -79,6 +79,3 @@ exceptions in your code. The example above can be therefore rewritten in a much app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") More examples can be found on `GitHub `_. - -.. _installed Pyrogram: ../intro/install.html -.. _authorized: ../intro/setup.html diff --git a/docs/source/start/updates.rst b/docs/source/start/updates.rst index a0f2ca0c..b6838ad3 100644 --- a/docs/source/start/updates.rst +++ b/docs/source/start/updates.rst @@ -1,8 +1,8 @@ Handling Updates ================ -Calling `API methods`_ sequentially is cool, but how to react when, for example, a new message arrives? This page deals -with updates and how to handle such events in Pyrogram. Let's have a look at how they work. +Calling :doc:`API methods ` sequentially is cool, but how to react when, for example, a new message arrives? +This page deals with updates and how to handle such events in Pyrogram. Let's have a look at how they work. Defining Updates ---------------- @@ -10,7 +10,7 @@ Defining Updates First, let's define what are these updates. As hinted already, updates are simply events that happen in your Telegram account (incoming messages, new members join, bot button presses, etc...), which are meant to notify you about a new specific state that has changed. These updates are handled by registering one or more callback functions in your app -using `Handlers <../api/handlers>`_. +using :doc:`Handlers <../api/handlers>`. Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback function will be called back by the framework and its body executed. @@ -18,17 +18,16 @@ function will be called back by the framework and its body executed. Registering a Handler --------------------- -To explain how handlers work let's have a look at the most used one, the -:obj:`MessageHandler `, which will be in charge for handling :obj:`Message ` -updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles -settings them up once you learn from this section. +To explain how handlers work let's have a look at the most used one, the :class:`~pyrogram.MessageHandler`, which will +be in charge for handling :class:`~pyrogram.Message` updates coming from all around your chats. Every other handler shares +the same setup logic; you should not have troubles settings them up once you learn from this section. Using add_handler() ------------------- -The :meth:`add_handler() ` method takes any handler instance that wraps around your defined -callback function and registers it in your Client. Here's a full example that prints out the content of a message as -soon as it arrives: +The :meth:`~pyrogram.Client.add_handler` method takes any handler instance that wraps around your defined callback +function and registers it in your Client. Here's a full example that prints out the content of a message as soon as it +arrives: .. code-block:: python @@ -55,24 +54,23 @@ call that function by passing the client instance and the new message instance a def my_function(client, message): print(message) -Second one: the :obj:`MessageHandler `. This object tells Pyrogram the function we defined -above must only handle updates that are in form of a :obj:`Message `: +Second one: the :class:`~pyrogram.MessageHandler`. This object tells Pyrogram the function we defined above must only +handle updates that are in form of a :class:`~pyrogram.Message`: .. code-block:: python my_handler = MessageHandler(my_function) -Third: the method :meth:`add_handler() `. This method is used to actually register the -handler and let Pyrogram know it needs to be taken into consideration when new updates arrive and the internal -dispatching phase begins. +Third: the method :meth:`~pyrogram.Client.add_handler`. This method is used to actually register the handler and let +Pyrogram know it needs to be taken into consideration when new updates arrive and the internal dispatching phase begins. .. code-block:: python app.add_handler(my_handler) -Last one, the :meth:`run() ` method. What this does is simply call -:meth:`start() ` and a special method :meth:`idle() ` that keeps your main -scripts alive until you press ``CTRL+C``; the client will be automatically stopped after that. +Last one, the :meth:`~pyrogram.Client.run` method. What this does is simply call :meth:`~pyrogram.Client.start` and a +special method :meth:`~pyrogram.Client.idle` that keeps your main scripts alive until you press ``CTRL+C``; the client +will be automatically stopped after that. .. code-block:: python @@ -82,7 +80,7 @@ Using Decorators ---------------- All of the above will become quite verbose, especially in case you have lots of handlers to register. A much nicer way -to do so is by decorating your callback function with the :meth:`on_message() ` decorator. +to do so is by decorating your callback function with the :meth:`~pyrogram.Client.on_message` decorator. .. code-block:: python @@ -108,5 +106,3 @@ to do so is by decorating your callback function with the :meth:`on_message()

` and facade +:doc:`types <../api/types>`, exists to provide a much easier interface to the undocumented and often confusing Telegram +API. In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main "raw" Telegram API with its functions and types. @@ -11,7 +12,7 @@ Telegram Raw API ---------------- If you can't find a high-level method for your needs or if you want complete, low-level access to the whole -Telegram API, you have to use the raw :mod:`functions ` and :mod:`types `. +Telegram API, you have to use the raw :mod:`~pyrogram.api.functions` and :mod:`~pyrogram.api.types`. As already hinted, raw functions and types can be really confusing, mainly because people don't realize soon enough they accept *only* the right types and that all required parameters must be filled in. This section will therefore explain @@ -21,24 +22,25 @@ some pitfalls to take into consideration when working with the raw API. Every available high-level methods in Pyrogram is built on top of these raw functions. - Nothing stops you from using the raw functions only, but they are rather complex and `plenty of them`_ are already - re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API (yet much more - powerful). + Nothing stops you from using the raw functions only, but they are rather complex and + :doc:`plenty of them <../api/methods>` are already re-implemented by providing a much simpler and cleaner interface + which is very similar to the Bot API (yet much more powerful). If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_! Invoking Functions ^^^^^^^^^^^^^^^^^^ -Unlike the methods_ found in Pyrogram's API, which can be called in the usual simple way, functions to be invoked from -the raw Telegram API have a different way of usage and are more complex. +Unlike the :doc:`methods <../api/methods>` found in Pyrogram's API, which can be called in the usual simple way, +functions to be invoked from the raw Telegram API have a different way of usage and are more complex. -First of all, both `raw functions`_ and `raw types`_ live in their respective packages (and sub-packages): -``pyrogram.api.functions``, ``pyrogram.api.types``. They all exist as Python classes, meaning you need to create an -instance of each every time you need them and fill them in with the correct values using named arguments. +First of all, both :doc:`raw functions <../telegram/functions/index>` and :doc:`raw types <../telegram/types/index>` live in their +respective packages (and sub-packages): ``pyrogram.api.functions``, ``pyrogram.api.types``. They all exist as Python +classes, meaning you need to create an instance of each every time you need them and fill them in with the correct +values using named arguments. -Next, to actually invoke the raw function you have to use the :meth:`send() ` method provided by -the Client class and pass the function object you created. +Next, to actually invoke the raw function you have to use the :meth:`~pyrogram.Client.send` method provided by the +Client class and pass the function object you created. Here's some examples: @@ -101,12 +103,12 @@ sending messages with IDs only thanks to cached access hashes. There are three different InputPeer types, one for each kind of Telegram entity. Whenever an InputPeer is needed you must pass one of these: - - :obj:`InputPeerUser <../telegram/types/InputPeerUser>` - Users - - :obj:`InputPeerChat <../telegram/types/InputPeerChat>` - Basic Chats - - :obj:`InputPeerChannel <../telegram/types/InputPeerChannel>` - Either Channels or Supergroups + - :class:`~pyrogram.api.types.InputPeerUser` - Users + - :class:`~pyrogram.api.types.InputPeerChat` - Basic Chats + - :class:`~pyrogram.api.types.InputPeerChannel` - Either Channels or Supergroups But you don't necessarily have to manually instantiate each object because, luckily for you, Pyrogram already provides -:meth:`resolve_peer() ` as a convenience utility method that returns the correct InputPeer +:meth:`~pyrogram.Client.resolve_peer` as a convenience utility method that returns the correct InputPeer by accepting a peer ID only. Another thing to take into consideration about chat IDs is the way they are represented: they are all integers and @@ -125,9 +127,4 @@ For example, given the ID *123456789*, here's how Pyrogram can tell entities apa So, every time you take a raw ID, make sure to translate it into the correct ID when you want to use it with an high-level method. -.. _methods: ../api/methods -.. _types: ../api/types -.. _plenty of them: ../api/methods -.. _raw functions: ../telegram/functions -.. _raw types: ../telegram/types .. _Community: https://t.me/Pyrogram \ No newline at end of file diff --git a/docs/source/topics/auto-auth.rst b/docs/source/topics/auto-auth.rst index b5f3a94a..abeaf1fb 100644 --- a/docs/source/topics/auto-auth.rst +++ b/docs/source/topics/auto-auth.rst @@ -3,7 +3,7 @@ Auto Authorization Manually writing phone number, phone code and password on the terminal every time you want to login can be tedious. Pyrogram is able to automate both **Log In** and **Sign Up** processes, all you need to do is pass the relevant -parameters when creating a new :class:`Client `. +parameters when creating a new :class:`~pyrogram.Client`. .. note:: If you omit any of the optional parameter required for the authorization, Pyrogram will ask you to manually write it. For instance, if you don't want to set a ``last_name`` when creating a new account you diff --git a/docs/source/topics/bots-interaction.rst b/docs/source/topics/bots-interaction.rst index de7925a2..ad993050 100644 --- a/docs/source/topics/bots-interaction.rst +++ b/docs/source/topics/bots-interaction.rst @@ -7,8 +7,7 @@ Inline Bots ----------- - If a bot accepts inline queries, you can call it by using - :meth:`get_inline_bot_results() ` to get the list of its inline results - for a query: + :meth:`~pyrogram.Client.get_inline_bot_results` to get the list of its inline results for a query: .. code-block:: python @@ -24,7 +23,7 @@ Inline Bots results list. - After you retrieved the bot results, you can use - :meth:`send_inline_bot_result() ` to send a chosen result to any chat: + :meth:`~pyrogram.Client.send_inline_bot_result` to send a chosen result to any chat: .. code-block:: python diff --git a/docs/source/topics/filters.rst b/docs/source/topics/filters.rst index cb2e2a4c..7ff02ffc 100644 --- a/docs/source/topics/filters.rst +++ b/docs/source/topics/filters.rst @@ -4,7 +4,7 @@ Using Filters So far we've seen how to register a callback function that executes every time a specific update comes from the server, but there's much more than that to come. -Here we'll discuss about :class:`Filters `. Filters enable a fine-grain control over what kind of +Here we'll discuss about :class:`~pyrogram.Filters`. Filters enable a fine-grain control over what kind of updates are allowed or not to be passed in your callback functions, based on their inner details. Single Filters @@ -12,7 +12,7 @@ Single Filters Let's start right away with a simple example: -- This example will show you how to **only** handle messages containing an :obj:`Audio ` object and +- This example will show you how to **only** handle messages containing an :class:`~pyrogram.Audio` object and ignore any other message. Filters are passed as the first argument of the decorator: .. code-block:: python @@ -69,7 +69,7 @@ Here are some examples: Advanced Filters ---------------- -Some filters, like :meth:`command() ` or :meth:`regex() ` +Some filters, like :meth:`~pyrogram.Filters.command` or :meth:`~pyrogram.Filters.regex` can also accept arguments: - Message is either a */start* or */help* **command**. @@ -109,18 +109,18 @@ More handlers using different filters can also live together. Custom Filters -------------- -Pyrogram already provides lots of built-in :class:`Filters ` to work with, but in case you can't find +Pyrogram already provides lots of built-in :class:`~pyrogram.Filters` to work with, but in case you can't find a specific one for your needs or want to build a custom filter by yourself (to be used in a different kind of handler, -for example) you can use :meth:`Filters.create() `. +for example) you can use :meth:`~pyrogram.Filters.create`. .. note:: - At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler ` - only. + + At the moment, the built-in filters are intended to be used with the :class:`~pyrogram.MessageHandler` only. An example to demonstrate how custom filters work is to show how to create and use one for the -:obj:`CallbackQueryHandler `. Note that callback queries updates are only received by -bots; create and `authorize your bot <../start/Setup.html#bot-authorization>`_, then send a message with an inline -keyboard to yourself. This allows you to test your filter by pressing the inline button: +:class:`~pyrogram.CallbackQueryHandler`. Note that callback queries updates are only received by bots; create and +:doc:`authorize your bot <../start/auth>`, then send a message with an inline keyboard to yourself. This allows you to +test your filter by pressing the inline button: .. code-block:: python @@ -137,7 +137,7 @@ keyboard to yourself. This allows you to test your filter by pressing the inline Basic Filters ^^^^^^^^^^^^^ -For this basic filter we will be using only the first two parameters of :meth:`Filters.create() `. +For this basic filter we will be using only the first two parameters of :meth:`~pyrogram.Filters.create`. The code below creates a simple filter for hardcoded, static callback data. This filter will only allow callback queries containing "Pyrogram" as data, that is, the function *func* you pass returns True in case the callback query data @@ -175,7 +175,7 @@ Filters with Arguments ^^^^^^^^^^^^^^^^^^^^^^ A much cooler filter would be one that accepts "Pyrogram" or any other data as argument at usage time. -A dynamic filter like this will make use of the third parameter of :meth:`Filters.create() `. +A dynamic filter like this will make use of the third parameter of :meth:`~pyrogram.Filters.create`. This is how a dynamic custom filter looks like: diff --git a/docs/source/topics/more-on-updates.rst b/docs/source/topics/more-on-updates.rst index cb319ee1..c3737b38 100644 --- a/docs/source/topics/more-on-updates.rst +++ b/docs/source/topics/more-on-updates.rst @@ -1,7 +1,8 @@ More on Updates =============== -Here we'll show some advanced usages when working with `update handlers`_ and `filters`_. +Here we'll show some advanced usages when working with :doc:`update handlers <../start/updates>` and +:doc:`filters `. Handler Groups -------------- @@ -44,7 +45,7 @@ Or, if you want ``just_text`` to be fired *before* ``text_or_sticker`` (note ``- def just_text(client, message): print("Just Text") -With :meth:`add_handler() ` (without decorators) the same can be achieved with: +With :meth:`~pyrogram.Client.add_handler` (without decorators) the same can be achieved with: .. code-block:: python @@ -217,6 +218,3 @@ The output of both (equivalent) examples will be: 0 1 2 - -.. _`update handlers`: ../start/updates -.. _`filters`: filters \ No newline at end of file diff --git a/docs/source/topics/serialize.rst b/docs/source/topics/serialize.rst index 32208199..a238f8dc 100644 --- a/docs/source/topics/serialize.rst +++ b/docs/source/topics/serialize.rst @@ -9,7 +9,8 @@ For Humans - str(obj) --------------------- If you want a nicely formatted, human readable JSON representation of any object in the API -- namely, any object from -`Pyrogram types`_, `raw functions`_ and `raw types`_ -- you can use use ``str(obj)``. +:doc:`Pyrogram types <../api/types>`, :doc:`raw functions <../telegram/functions/index>` and +:doc:`raw types <../telegram/types/index>` -- you can use use ``str(obj)``. .. code-block:: python @@ -25,10 +26,6 @@ If you want a nicely formatted, human readable JSON representation of any object When using ``print()`` you don't actually need to use ``str()`` on the object because it is called automatically, we have done that above just to show you how to explicitly convert a Pyrogram object to JSON. -.. _Pyrogram types: ../api/types -.. _raw functions: ../telegram/functions -.. _raw types: ../telegram/types - For Machines - repr(obj) ------------------------ diff --git a/docs/source/topics/session-settings.rst b/docs/source/topics/session-settings.rst index 91e3f050..dd777bda 100644 --- a/docs/source/topics/session-settings.rst +++ b/docs/source/topics/session-settings.rst @@ -5,7 +5,7 @@ As you may probably know, Telegram allows users (and bots) having more than one in the system at the same time. Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official -app (or by invoking `GetAuthorizations <../telegram/functions/account/GetAuthorizations.html>`_ with Pyrogram). They +app (or by invoking :class:`~pyrogram.api.functions.account.GetAuthorizations` with Pyrogram). They store some useful information such as the client who's using them and from which country and IP address. .. figure:: https://i.imgur.com/YaqtMLO.png diff --git a/docs/source/topics/smart-plugins.rst b/docs/source/topics/smart-plugins.rst index 9f1592d1..8e59b971 100644 --- a/docs/source/topics/smart-plugins.rst +++ b/docs/source/topics/smart-plugins.rst @@ -65,8 +65,8 @@ after importing your modules, like this: app.run() This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to -manually ``import``, manually :meth:`add_handler() ` and manually instantiate each -:obj:`MessageHandler ` object because **you can't use those cool decorators** for your +manually ``import``, manually :meth:`~pyrogram.Client.add_handler` and manually instantiate each +:class:`~pyrogram.MessageHandler` object because **you can't use those cool decorators** for your functions. So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically. Using Smart Plugins @@ -80,7 +80,7 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight .. note:: - This is the same example application `as shown above <#introduction>`_, written using the Smart Plugin system. + This is the same example application as shown above, written using the Smart Plugin system. .. code-block:: text :emphasize-lines: 2, 3 @@ -156,7 +156,7 @@ found inside each module will be, instead, loaded in the order they are defined, .. note:: Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping - filters included a second time will not work. Learn more at `More on Updates `_. + filters included a second time will not work. Learn more at :doc:`More on Updates `. This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude`` @@ -288,9 +288,8 @@ also organized in subfolders: Load/Unload Plugins at Runtime ------------------------------ -In the `previous section <#specifying-the-plugins-to-include>`_ we've explained how to specify which plugins to load and -which to ignore before your Client starts. Here we'll show, instead, how to unload and load again a previously -registered plugin at runtime. +In the previous section we've explained how to specify which plugins to load and which to ignore before your Client +starts. Here we'll show, instead, how to unload and load again a previously registered plugin at runtime. Each function decorated with the usual ``on_message`` decorator (or any other decorator that deals with Telegram updates ) will be modified in such a way that, when you reference them later on, they will be actually pointing to a tuple of @@ -318,7 +317,7 @@ Unloading ^^^^^^^^^ In order to unload a plugin, or any other handler, all you need to do is obtain a reference to it by importing the -relevant module and call :meth:`remove_handler() ` Client's method with your function +relevant module and call :meth:`~pyrogram.Client.remove_handler` Client's method with your function name preceded by the star ``*`` operator as argument. Example: - ``main.py`` @@ -343,7 +342,7 @@ Loading ^^^^^^^ Similarly to the unloading process, in order to load again a previously unloaded plugin you do the same, but this time -using :meth:`add_handler() ` instead. Example: +using :meth:`~pyrogram.Client.add_handler` instead. Example: - ``main.py`` diff --git a/docs/source/topics/text-formatting.rst b/docs/source/topics/text-formatting.rst index 8f2292d0..bc74d562 100644 --- a/docs/source/topics/text-formatting.rst +++ b/docs/source/topics/text-formatting.rst @@ -12,7 +12,7 @@ Markdown Style -------------- To use this mode, pass "markdown" in the *parse_mode* field when using -:obj:`send_message() `. Use the following syntax in your message: +:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message: .. code-block:: text @@ -34,7 +34,7 @@ To use this mode, pass "markdown" in the *parse_mode* field when using HTML Style ---------- -To use this mode, pass "html" in the *parse_mode* field when using :obj:`send_message() `. +To use this mode, pass "html" in the *parse_mode* field when using :meth:`~pyrogram.Client.send_message`. The following tags are currently supported: .. code-block:: text diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 317e9df2..1269174c 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -24,7 +24,7 @@ if sys.version_info[:3] in [(3, 5, 0), (3, 5, 1), (3, 5, 2)]: # Monkey patch the standard "typing" module because Python versions from 3.5.0 to 3.5.2 have a broken one. sys.modules["typing"] = typing -__version__ = "0.13.0.async" +__version__ = "0.13.0-asyncio" __license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)" __copyright__ = "Copyright (C) 2017-2019 Dan " diff --git a/pyrogram/api/core/__init__.py b/pyrogram/api/core/__init__.py index daba6b7c..bf596446 100644 --- a/pyrogram/api/core/__init__.py +++ b/pyrogram/api/core/__init__.py @@ -19,6 +19,7 @@ from .future_salt import FutureSalt from .future_salts import FutureSalts from .gzip_packed import GzipPacked +from .list import List from .message import Message from .msg_container import MsgContainer from .object import Object diff --git a/pyrogram/api/core/future_salt.py b/pyrogram/api/core/future_salt.py index 4ee8197b..c4ccea3d 100644 --- a/pyrogram/api/core/future_salt.py +++ b/pyrogram/api/core/future_salt.py @@ -16,7 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from datetime import datetime from io import BytesIO from .object import Object @@ -30,15 +29,15 @@ class FutureSalt(Object): QUALNAME = "FutureSalt" - def __init__(self, valid_since: int or datetime, valid_until: int or datetime, salt: int): + def __init__(self, valid_since: int, valid_until: int, salt: int): self.valid_since = valid_since self.valid_until = valid_until self.salt = salt @staticmethod def read(b: BytesIO, *args) -> "FutureSalt": - valid_since = datetime.fromtimestamp(Int.read(b)) - valid_until = datetime.fromtimestamp(Int.read(b)) + valid_since = Int.read(b) + valid_until = Int.read(b) salt = Long.read(b) return FutureSalt(valid_since, valid_until, salt) diff --git a/pyrogram/api/core/future_salts.py b/pyrogram/api/core/future_salts.py index cf6a9902..91ee7b51 100644 --- a/pyrogram/api/core/future_salts.py +++ b/pyrogram/api/core/future_salts.py @@ -16,7 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from datetime import datetime from io import BytesIO from . import FutureSalt @@ -31,7 +30,7 @@ class FutureSalts(Object): QUALNAME = "FutureSalts" - def __init__(self, req_msg_id: int, now: int or datetime, salts: list): + def __init__(self, req_msg_id: int, now: int, salts: list): self.req_msg_id = req_msg_id self.now = now self.salts = salts @@ -39,7 +38,7 @@ class FutureSalts(Object): @staticmethod def read(b: BytesIO, *args) -> "FutureSalts": req_msg_id = Long.read(b) - now = datetime.fromtimestamp(Int.read(b)) + now = Int.read(b) count = Int.read(b) salts = [FutureSalt.read(b) for _ in range(count)] diff --git a/pyrogram/api/core/list.py b/pyrogram/api/core/list.py new file mode 100644 index 00000000..922ec64d --- /dev/null +++ b/pyrogram/api/core/list.py @@ -0,0 +1,28 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 . + +from .object import Object + + +class List(list, Object): + __slots__ = [] + + def __repr__(self): + return "pyrogram.api.core.List([{}])".format( + ",".join(Object.__repr__(i) for i in self) + ) diff --git a/pyrogram/api/core/object.py b/pyrogram/api/core/object.py index ace7a59a..9d1a4852 100644 --- a/pyrogram/api/core/object.py +++ b/pyrogram/api/core/object.py @@ -17,7 +17,6 @@ # along with Pyrogram. If not, see . from collections import OrderedDict -from datetime import datetime from io import BytesIO from json import dumps @@ -36,32 +35,22 @@ class Object: def write(self, *args) -> bytes: pass - def __eq__(self, other: "Object") -> bool: - for attr in self.__slots__: - try: - if getattr(self, attr) != getattr(other, attr): - return False - except AttributeError: - return False + @staticmethod + def default(obj: "Object"): + if isinstance(obj, bytes): + return repr(obj) - return True + return OrderedDict( + [("_", obj.QUALNAME)] + + [ + (attr, getattr(obj, attr)) + for attr in obj.__slots__ + if getattr(obj, attr) is not None + ] + ) def __str__(self) -> str: - def default(obj: Object): - try: - return OrderedDict( - [("_", obj.QUALNAME)] - + [(attr, getattr(obj, attr)) - for attr in obj.__slots__ - if getattr(obj, attr) is not None] - ) - except AttributeError: - if isinstance(obj, datetime): - return obj.strftime("%d-%b-%Y %H:%M:%S") - else: - return repr(obj) - - return dumps(self, indent=4, default=default, ensure_ascii=False) + return dumps(self, indent=4, default=Object.default, ensure_ascii=False) def __repr__(self) -> str: return "pyrogram.api.{}({})".format( @@ -73,6 +62,16 @@ class Object: ) ) + def __eq__(self, other: "Object") -> bool: + for attr in self.__slots__: + try: + if getattr(self, attr) != getattr(other, attr): + return False + except AttributeError: + return False + + return True + def __len__(self) -> int: return len(self.write()) diff --git a/pyrogram/api/core/primitives/vector.py b/pyrogram/api/core/primitives/vector.py index cd24ec35..720486f2 100644 --- a/pyrogram/api/core/primitives/vector.py +++ b/pyrogram/api/core/primitives/vector.py @@ -19,6 +19,7 @@ from io import BytesIO from . import Int +from ..list import List from ..object import Object @@ -37,11 +38,11 @@ class Vector(Object): @staticmethod def read(b: BytesIO, t: Object = None) -> list: - return [ + return List( t.read(b) if t else Vector._read(b) for _ in range(Int.read(b)) - ] + ) def __new__(cls, value: list, t: Object = None) -> bytes: return b"".join( diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index dd9cc3dd..2e80a917 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -18,7 +18,6 @@ import asyncio import base64 -import binascii import inspect import json import logging @@ -27,7 +26,6 @@ import mimetypes import os import re import shutil -import struct import tempfile import time from configparser import ConfigParser @@ -49,7 +47,7 @@ from pyrogram.errors import ( PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty, PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded, PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned, - VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied, + VolumeLocNotFound, UserMigrate, ChannelPrivate, PhoneNumberOccupied, PasswordRecoveryNa, PasswordEmpty ) from pyrogram.session import Auth, Session @@ -320,7 +318,7 @@ class Client(Methods, BaseClient): await self.get_initial_dialogs() await self.get_contacts() else: - await self.send(functions.messages.GetPinnedDialogs()) + await self.send(functions.messages.GetPinnedDialogs(folder_id=0)) await self.get_initial_dialogs_chunk() else: await self.send(functions.updates.GetState()) @@ -430,9 +428,9 @@ class Client(Methods, BaseClient): def run(self, coroutine=None): """Start the Client and automatically idle the main script. - This is a convenience method that literally just calls :meth:`start` and :meth:`idle`. 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 :meth:`idle` will block. + This is a convenience method that literally just calls :meth:`~Client.start` and :meth:`~Client.idle`. 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 :meth:`~Client.idle` will block. Args: coroutine: (``Coroutine``, *optional*): @@ -484,7 +482,7 @@ class Client(Methods, BaseClient): """Remove a previously-registered update handler. Make sure to provide the right group that the handler was added in. You can use - the return value of the :meth:`add_handler` method, a tuple of (handler, group), and + the return value of the :meth:`~Client.add_handler` method, a tuple of (handler, group), and pass it directly. Parameters: @@ -777,7 +775,9 @@ class Client(Methods, BaseClient): types.Channel, types.ChannelForbidden ] ] - ): + ) -> bool: + is_min = False + for entity in entities: if isinstance(entity, types.User): user_id = entity.id @@ -785,6 +785,7 @@ class Client(Methods, BaseClient): access_hash = entity.access_hash if access_hash is None: + is_min = True continue username = entity.username @@ -820,6 +821,7 @@ class Client(Methods, BaseClient): access_hash = entity.access_hash if access_hash is None: + is_min = True continue username = getattr(entity, "username", None) @@ -834,87 +836,62 @@ class Client(Methods, BaseClient): if username is not None: self.peers_by_username[username.lower()] = input_peer + return is_min + async def download_worker(self): while True: - media = await self.download_queue.get() + packet = await self.download_queue.get() - if media is None: + if packet is None: break temp_file_path = "" final_file_path = "" try: - media, file_name, done, progress, progress_args, path = media - - file_id = media.file_id - size = media.file_size + data, file_name, done, progress, progress_args, path = packet directory, file_name = os.path.split(file_name) directory = directory or "downloads" - try: - decoded = utils.decode(file_id) - fmt = " 24 else " 24: - volume_id = unpacked[4] - secret = unpacked[5] - local_id = unpacked[6] + if not data.file_name: + guessed_extension = self.guess_extension(data.mime_type) - media_type_str = Client.MEDIA_TYPE_ID.get(media_type, None) - - if media_type_str is None: - raise FileIdInvalid("Unknown media type: {}".format(unpacked[0])) - - file_name = file_name or getattr(media, "file_name", None) - - if not file_name: - guessed_extension = self.guess_extension(media.mime_type) - - if media_type in (0, 1, 2): + if data.media_type in (0, 1, 2, 14): extension = ".jpg" - elif media_type == 3: + elif data.media_type == 3: extension = guessed_extension or ".ogg" - elif media_type in (4, 10, 13): + elif data.media_type in (4, 10, 13): extension = guessed_extension or ".mp4" - elif media_type == 5: + elif data.media_type == 5: extension = guessed_extension or ".zip" - elif media_type == 8: + elif data.media_type == 8: extension = guessed_extension or ".webp" - elif media_type == 9: + elif data.media_type == 9: extension = guessed_extension or ".mp3" else: continue file_name = "{}_{}_{}{}".format( media_type_str, - datetime.fromtimestamp( - getattr(media, "date", None) or time.time() - ).strftime("%Y-%m-%d_%H-%M-%S"), + datetime.fromtimestamp(data.date or time.time()).strftime("%Y-%m-%d_%H-%M-%S"), self.rnd_id(), extension ) temp_file_path = await self.get_file( - dc_id=dc_id, - id=id, - access_hash=access_hash, - volume_id=volume_id, - local_id=local_id, - secret=secret, - size=size, + media_type=data.media_type, + dc_id=data.dc_id, + file_id=data.file_id, + access_hash=data.access_hash, + thumb_size=data.thumb_size, + peer_id=data.peer_id, + volume_id=data.volume_id, + local_id=data.local_id, + file_size=data.file_size, + is_big=data.is_big, progress=progress, progress_args=progress_args ) @@ -949,8 +926,10 @@ class Client(Methods, BaseClient): try: if isinstance(updates, (types.Update, types.UpdatesCombined)): - self.fetch_peers(updates.users) - self.fetch_peers(updates.chats) + is_min = self.fetch_peers(updates.users) or self.fetch_peers(updates.chats) + + users = {u.id: u for u in updates.users} + chats = {c.id: c for c in updates.chats} for update in updates.updates: channel_id = getattr( @@ -967,7 +946,7 @@ class Client(Methods, BaseClient): if isinstance(update, types.UpdateChannelTooLong): log.warning(update) - if isinstance(update, types.UpdateNewChannelMessage): + if isinstance(update, types.UpdateNewChannelMessage) and is_min: message = update.message if not isinstance(message, types.MessageEmpty): @@ -989,22 +968,10 @@ class Client(Methods, BaseClient): pass else: if not isinstance(diff, types.updates.ChannelDifferenceEmpty): - updates.users += diff.users - updates.chats += diff.chats + users.update({u.id: u for u in diff.users}) + chats.update({c.id: c for c in diff.chats}) - if channel_id and pts: - if channel_id not in self.channels_pts: - self.channels_pts[channel_id] = [] - - if pts in self.channels_pts[channel_id]: - continue - - self.channels_pts[channel_id].append(pts) - - if len(self.channels_pts[channel_id]) > 50: - self.channels_pts[channel_id] = self.channels_pts[channel_id][25:] - - self.dispatcher.updates_queue.put_nowait((update, updates.users, updates.chats)) + self.dispatcher.updates_queue.put_nowait((update, users, chats)) elif isinstance(updates, (types.UpdateShortMessage, types.UpdateShortChatMessage)): diff = await self.send( functions.updates.GetDifference( @@ -1021,13 +988,13 @@ class Client(Methods, BaseClient): pts=updates.pts, pts_count=updates.pts_count ), - diff.users, - diff.chats + {u.id: u for u in diff.users}, + {c.id: c for c in diff.chats} )) else: - self.dispatcher.updates_queue.put_nowait((diff.other_updates[0], [], [])) + self.dispatcher.updates_queue.put_nowait((diff.other_updates[0], {}, {})) elif isinstance(updates, types.UpdateShort): - self.dispatcher.updates_queue.put_nowait((updates.update, [], [])) + self.dispatcher.updates_queue.put_nowait((updates.update, {}, {})) elif isinstance(updates, types.UpdatesTooLong): log.warning(updates) except Exception as e: @@ -1333,7 +1300,7 @@ class Client(Methods, BaseClient): return r async def get_initial_dialogs(self): - await self.send(functions.messages.GetPinnedDialogs()) + await self.send(functions.messages.GetPinnedDialogs(folder_id=0)) dialogs = await self.get_initial_dialogs_chunk() offset_date = utils.get_offset_date(dialogs) @@ -1424,7 +1391,7 @@ class Client(Methods, BaseClient): file_part: int = 0, progress: callable = None, progress_args: tuple = () - ): + ): """Upload a file onto Telegram servers, without actually sending the message to anyone. Useful whenever an InputFile type is required. @@ -1575,16 +1542,18 @@ class Client(Methods, BaseClient): for session in pool: await session.stop() - async def get_file(self, + async def get_file(self, media_type: int, dc_id: int, - id: int = None, - access_hash: int = None, - volume_id: int = None, - local_id: int = None, - secret: int = None, + file_id: int, + access_hash: int, + thumb_size: str, + peer_id: int, + volume_id: int, + local_id: int, + file_size: int, - size: int = None, - progress: callable = None, + is_big: bool, + progress: callable, progress_args: tuple = ()) -> str: with await self.media_sessions_lock: session = self.media_sessions.get(dc_id, None) @@ -1626,18 +1595,33 @@ class Client(Methods, BaseClient): self.media_sessions[dc_id] = session - if volume_id: # Photos are accessed by volume_id, local_id, secret - location = types.InputFileLocation( + if media_type == 1: + location = types.InputPeerPhotoFileLocation( + peer=self.resolve_peer(peer_id), volume_id=volume_id, local_id=local_id, - secret=secret, - file_reference=b"" + big=is_big or None ) - else: # Any other file can be more easily accessed by id and access_hash - location = types.InputDocumentFileLocation( - id=id, + elif media_type in (0, 2): + location = types.InputPhotoFileLocation( + id=file_id, access_hash=access_hash, - file_reference=b"" + file_reference=b"", + thumb_size=thumb_size + ) + elif media_type == 14: + location = types.InputDocumentFileLocation( + id=file_id, + access_hash=access_hash, + file_reference=b"", + thumb_size=thumb_size + ) + else: + location = types.InputDocumentFileLocation( + id=file_id, + access_hash=access_hash, + file_reference=b"", + thumb_size="" ) limit = 1024 * 1024 @@ -1668,7 +1652,14 @@ class Client(Methods, BaseClient): offset += limit if progress: - await progress(self, min(offset, size) if size != 0 else offset, size, *progress_args) + await progress( + self, + min(offset, file_size) + if file_size != 0 + else offset, + file_size, + *progress_args + ) r = await session.send( functions.upload.GetFile( @@ -1750,7 +1741,14 @@ class Client(Methods, BaseClient): offset += limit if progress: - await progress(self, min(offset, size) if size != 0 else offset, size, *progress_args) + await progress( + self, + min(offset, file_size) + if file_size != 0 + else offset, + file_size, + *progress_args + ) if len(chunk) < limit: break diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py index 9377cce8..276e65fc 100644 --- a/pyrogram/client/ext/base_client.py +++ b/pyrogram/client/ext/base_client.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import os import asyncio +import os import platform import re +from collections import namedtuple from pyrogram import __version__ from ..style import Markdown, HTML @@ -55,7 +56,7 @@ class BaseClient: CONFIG_FILE = "./config.ini" MEDIA_TYPE_ID = { - 0: "thumbnail", + 0: "photo_thumbnail", 1: "chat_photo", 2: "photo", 3: "voice", @@ -64,7 +65,8 @@ class BaseClient: 8: "sticker", 9: "audio", 10: "animation", - 13: "video_note" + 13: "video_note", + 14: "document_thumbnail" } mime_types_to_extensions = {} @@ -81,6 +83,10 @@ class BaseClient: mime_types_to_extensions[mime_type] = " ".join(extensions) + fields = ("media_type", "dc_id", "file_id", "access_hash", "thumb_size", "peer_id", "volume_id", "local_id", + "is_big", "file_size", "mime_type", "file_name", "date") + FileData = namedtuple("FileData", fields, defaults=(None,) * len(fields)) + def __init__(self): self.is_bot = None self.dc_id = None @@ -89,7 +95,6 @@ class BaseClient: self.date = None self.rnd_id = MsgId - self.channels_pts = {} self.peers_by_id = {} self.peers_by_username = {} @@ -152,3 +157,6 @@ class BaseClient: def guess_extension(self, *args, **kwargs): pass + + def get_profile_photos(self, *args, **kwargs): + pass diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py index 0ad52d0a..5b2894d4 100644 --- a/pyrogram/client/ext/dispatcher.py +++ b/pyrogram/client/ext/dispatcher.py @@ -124,16 +124,13 @@ class Dispatcher: async def update_worker(self): while True: - update = await self.updates_queue.get() + packet = await self.updates_queue.get() - if update is None: + if packet is None: break try: - users = {i.id: i for i in update[1]} - chats = {i.id: i for i in update[2]} - update = update[0] - + update, users, chats = packet parser = self.update_parsers.get(type(update), None) parsed_update, handler_type = ( diff --git a/pyrogram/client/ext/mime.types b/pyrogram/client/ext/mime.types index 4db43cae..50ec065d 100644 --- a/pyrogram/client/ext/mime.types +++ b/pyrogram/client/ext/mime.types @@ -1852,4 +1852,7 @@ video/x-ms-wvx wvx video/x-msvideo avi video/x-sgi-movie movie video/x-smv smv -x-conference/x-cooltalk ice \ No newline at end of file +x-conference/x-cooltalk ice + +# Telegram animated stickers +application/x-tgsticker tgs \ No newline at end of file diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py index b9f90d26..a9fc4221 100644 --- a/pyrogram/client/ext/syncer.py +++ b/pyrogram/client/ext/syncer.py @@ -92,7 +92,7 @@ class Syncer: auth_key=auth_key, user_id=client.user_id, date=int(time.time()), - is_bot=client.is_bot, + is_bot=bool(client.is_bot), peers_by_id={ k: getattr(v, "access_hash", None) for k, v in client.peers_by_id.copy().items() diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index baf6fe94..cd5c919c 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -17,10 +17,13 @@ # along with Pyrogram. If not, see . import asyncio +import struct import sys from base64 import b64decode, b64encode from concurrent.futures.thread import ThreadPoolExecutor +from typing import Union +from . import BaseClient from ...api import types @@ -94,3 +97,53 @@ def get_offset_date(dialogs): return m.date else: return 0 + + +def get_input_media_from_file_id( + file_id_str: str, + expected_media_type: int = None +) -> Union[types.InputMediaPhoto, types.InputMediaDocument]: + try: + decoded = decode(file_id_str) + except Exception: + raise ValueError("Failed to decode file_id: {}".format(file_id_str)) + else: + media_type = decoded[0] + + if expected_media_type is not None: + if media_type != expected_media_type: + media_type_str = BaseClient.MEDIA_TYPE_ID.get(media_type, None) + expected_media_type_str = BaseClient.MEDIA_TYPE_ID.get(expected_media_type, None) + + raise ValueError( + 'Expected: "{}", got "{}" file_id instead'.format(expected_media_type_str, media_type_str) + ) + + if media_type in (0, 1, 14): + raise ValueError("This file_id can only be used for download: {}".format(file_id_str)) + + if media_type == 2: + unpacked = struct.unpack(" type: **kwargs (``any``, *optional*): Any keyword argument you would like to pass. Useful for custom filters that accept parameters (e.g.: - :meth:`Filters.command`, :meth:`Filters.regex`). + :meth:`~Filters.command`, :meth:`~Filters.regex`). """ # TODO: unpack kwargs using **kwargs into the dict itself. For Python 3.5+ only d = {"__call__": func} @@ -56,7 +56,7 @@ class Filters: The Filters listed here are intended to be used with the :obj:`MessageHandler` only. At the moment, if you want to filter updates coming from different `Handlers `_ you have to create - your own filters with :meth:`Filters.create` and use them in the same way. + your own filters with :meth:`~Filters.create` and use them in the same way. """ create = create @@ -219,7 +219,7 @@ class Filters: The command or list of commands as string the filter should look for. Examples: "start", ["start", "help", "settings"]. When a message text containing a command arrives, the command itself and its arguments will be stored in the *command* - field of the :class:`Message`. + field of the :obj:`Message`. prefix (``str`` | ``list``, *optional*): A prefix or a list of prefixes as string the filter should look for. @@ -263,7 +263,7 @@ class Filters: pattern (``str``): The RegEx pattern as string, it will be applied to the text of a message. When a pattern matches, all the `Match Objects `_ - are stored in the *matches* field of the :class:`Message` itself. + are stored in the *matches* field of the :obj:`Message` itself. flags (``int``, *optional*): RegEx flags. @@ -339,4 +339,15 @@ class Filters: and message.from_user.is_self and not message.outgoing))) + @staticmethod + def callback_data(data: str or bytes): + """Filter callback queries for their data. + + Parameters: + data (``str`` | ``bytes``): + Pass the data you want to filter for. + """ + + return create("CallbackData", lambda flt, cb: cb.data == flt.data, data=data) + dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162)) diff --git a/pyrogram/client/handlers/callback_query_handler.py b/pyrogram/client/handlers/callback_query_handler.py index feb46cb0..9e17296b 100644 --- a/pyrogram/client/handlers/callback_query_handler.py +++ b/pyrogram/client/handlers/callback_query_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class CallbackQueryHandler(Handler): """The CallbackQuery handler class. Used to handle callback queries coming from inline buttons. - It is intended to be used with :meth:`add_handler() ` + It is intended to be used with :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_callback_query() ` decorator. + :meth:`~Client.on_callback_query` decorator. Parameters: callback (``callable``): diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py index f37caaed..b6651fba 100644 --- a/pyrogram/client/handlers/deleted_messages_handler.py +++ b/pyrogram/client/handlers/deleted_messages_handler.py @@ -22,10 +22,10 @@ from .handler import Handler class DeletedMessagesHandler(Handler): """The deleted Messages handler class. Used to handle deleted messages coming from any chat (private, group, channel). It is intended to be used with - :meth:`add_handler() ` + :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_deleted_messages() ` decorator. + :meth:`~Client.on_deleted_messages` decorator. Parameters: callback (``callable``): diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py index b9e6350a..1b4801b2 100644 --- a/pyrogram/client/handlers/disconnect_handler.py +++ b/pyrogram/client/handlers/disconnect_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class DisconnectHandler(Handler): """The Disconnect handler class. Used to handle disconnections. It is intended to be used with - :meth:`add_handler() ` + :meth:~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_disconnect() ` decorator. + :meth:`~Client.on_disconnect` decorator. Parameters: callback (``callable``): diff --git a/pyrogram/client/handlers/inline_query_handler.py b/pyrogram/client/handlers/inline_query_handler.py index 98a25652..dbd86df7 100644 --- a/pyrogram/client/handlers/inline_query_handler.py +++ b/pyrogram/client/handlers/inline_query_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class InlineQueryHandler(Handler): """The InlineQuery handler class. Used to handle inline queries. - It is intended to be used with :meth:`add_handler() ` + It is intended to be used with :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_inline_query() ` decorator. + :meth:`~Client.on_inline_query` decorator. Parameters: callback (``callable``): diff --git a/pyrogram/client/handlers/message_handler.py b/pyrogram/client/handlers/message_handler.py index 10fff479..ea091ca4 100644 --- a/pyrogram/client/handlers/message_handler.py +++ b/pyrogram/client/handlers/message_handler.py @@ -21,11 +21,10 @@ from .handler import Handler class MessageHandler(Handler): """The Message handler class. Used to handle text, media and service messages coming from - any chat (private, group, channel). It is intended to be used with - :meth:`add_handler() ` + any chat (private, group, channel). It is intended to be used with :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_message() ` decorator. + :meth:`~Client.on_message` decorator. Parameters: callback (``callable``): diff --git a/pyrogram/client/handlers/poll_handler.py b/pyrogram/client/handlers/poll_handler.py index 9e97f2ac..d46fb5be 100644 --- a/pyrogram/client/handlers/poll_handler.py +++ b/pyrogram/client/handlers/poll_handler.py @@ -22,25 +22,25 @@ from .handler import Handler class PollHandler(Handler): """The Poll handler class. Used to handle polls updates. - It is intended to be used with :meth:`add_handler() ` + It is intended to be used with :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_poll() ` decorator. + :meth:`~Client.on_poll` decorator. Parameters: callback (``callable``): Pass a function that will be called when a new poll update arrives. It takes *(client, poll)* as positional arguments (look at the section below for a detailed description). - filters (:obj:`Filters `): + filters (:obj:`Filters`): Pass one or more filters to allow only a subset of polls to be passed in your callback function. Other parameters: - client (:obj:`Client `): + client (:obj:`Client`): The Client itself, useful when you want to call other API methods inside the poll handler. - poll (:obj:`Poll `): + poll (:obj:`Poll`): The received poll. """ diff --git a/pyrogram/client/handlers/raw_update_handler.py b/pyrogram/client/handlers/raw_update_handler.py index f54d59b6..485c6339 100644 --- a/pyrogram/client/handlers/raw_update_handler.py +++ b/pyrogram/client/handlers/raw_update_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class RawUpdateHandler(Handler): """The Raw Update handler class. Used to handle raw updates. It is intended to be used with - :meth:`add_handler() ` + :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_raw_update() ` decorator. + :meth:`~Client.on_raw_update` decorator. Parameters: callback (``callable``): @@ -33,7 +33,7 @@ class RawUpdateHandler(Handler): a detailed description). Other Parameters: - client (:class:`Client`): + client (:obj:`Client`): The Client itself, useful when you want to call other API methods inside the update handler. update (``Update``): diff --git a/pyrogram/client/handlers/user_status_handler.py b/pyrogram/client/handlers/user_status_handler.py index 1250cb19..9b39aab6 100644 --- a/pyrogram/client/handlers/user_status_handler.py +++ b/pyrogram/client/handlers/user_status_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class UserStatusHandler(Handler): """The UserStatus handler class. Used to handle user status updates (user going online or offline). - It is intended to be used with :meth:`add_handler() ` + It is intended to be used with :meth:`~Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`on_user_status() ` decorator. + :meth:`~Client.on_user_status` decorator. Parameters: callback (``callable``): diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py index 1e533097..78962501 100644 --- a/pyrogram/client/methods/chats/export_chat_invite_link.py +++ b/pyrogram/client/methods/chats/export_chat_invite_link.py @@ -35,8 +35,8 @@ class ExportChatInviteLink(BaseClient): Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link - using this method – after this the link will become available to the bot via the :meth:`get_chat` method. - If your bot needs to generate a new invite link replacing its previous one, use this method again. + using this method – after this the link will become available to the bot via the :meth:`~Client.get_chat` + method. If your bot needs to generate a new invite link replacing its previous one, use this method again. Parameters: chat_id (``int`` | ``str``): diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py index 28877b6d..8bc0d000 100644 --- a/pyrogram/client/methods/chats/get_chat_members.py +++ b/pyrogram/client/methods/chats/get_chat_members.py @@ -51,7 +51,7 @@ class GetChatMembers(BaseClient): You can get up to 200 chat members at once. A chat can be either a basic group, a supergroup or a channel. You must be admin to retrieve the members list of a channel (also known as "subscribers"). - For a more convenient way of getting chat members see :meth:`iter_chat_members`. + For a more convenient way of getting chat members see :meth:`~Client.iter_chat_members`. Parameters: chat_id (``int`` | ``str``): diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py index cf522dc0..6f6af700 100644 --- a/pyrogram/client/methods/chats/get_dialogs.py +++ b/pyrogram/client/methods/chats/get_dialogs.py @@ -37,7 +37,7 @@ class GetDialogs(BaseClient): """Get a chunk of the user's dialogs. You can get up to 100 dialogs at once. - For a more convenient way of getting a user's dialogs see :meth:`iter_dialogs`. + For a more convenient way of getting a user's dialogs see :meth:`~Client.iter_dialogs`. Parameters: offset_date (``int``): @@ -62,7 +62,7 @@ class GetDialogs(BaseClient): while True: try: if pinned_only: - r = await self.send(functions.messages.GetPinnedDialogs()) + r = await self.send(functions.messages.GetPinnedDialogs(folder_id=0)) else: r = await self.send( functions.messages.GetDialogs( diff --git a/pyrogram/client/methods/chats/get_dialogs_count.py b/pyrogram/client/methods/chats/get_dialogs_count.py index 5142211e..9a645e9f 100644 --- a/pyrogram/client/methods/chats/get_dialogs_count.py +++ b/pyrogram/client/methods/chats/get_dialogs_count.py @@ -36,7 +36,7 @@ class GetDialogsCount(BaseClient): """ if pinned_only: - return len((await self.send(functions.messages.GetPinnedDialogs())).dialogs) + return len((await self.send(functions.messages.GetPinnedDialogs(folder_id=0))).dialogs) else: r = await self.send( functions.messages.GetDialogs( diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py index 79f5e8c3..78e7c01a 100644 --- a/pyrogram/client/methods/chats/iter_chat_members.py +++ b/pyrogram/client/methods/chats/iter_chat_members.py @@ -50,7 +50,7 @@ class IterChatMembers(BaseClient): ) -> Optional[AsyncGenerator["pyrogram.ChatMember", None]]: """Iterate through the members of a chat sequentially. - This convenience method does the same as repeatedly calling :meth:`get_chat_members` in a loop, thus saving you + This convenience method does the same as repeatedly calling :meth:`~Client.get_chat_members` in a loop, thus saving you from the hassle of setting up boilerplate code. It is useful for getting the whole members list of a chat with a single call. diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py index e916bd47..a7075072 100644 --- a/pyrogram/client/methods/chats/iter_dialogs.py +++ b/pyrogram/client/methods/chats/iter_dialogs.py @@ -29,12 +29,13 @@ class IterDialogs(BaseClient): async def iter_dialogs( self, limit: int = 0, - offset_date: int = 0 + offset_date: int = None ) -> Optional[AsyncGenerator["pyrogram.Dialog", None]]: """Iterate through a user's dialogs sequentially. - This convenience method does the same as repeatedly calling :meth:`get_dialogs` in a loop, thus saving you from - the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a single call. + This convenience method does the same as repeatedly calling :meth:`~Client.get_dialogs` in a loop, thus saving + you from the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a + single call. Parameters: limit (``str``, *optional*): diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py index 4d2b175a..7b71009c 100644 --- a/pyrogram/client/methods/chats/set_chat_photo.py +++ b/pyrogram/client/methods/chats/set_chat_photo.py @@ -44,14 +44,14 @@ class SetChatPhoto(BaseClient): Unique identifier (int) or username (str) of the target chat. photo (``str``): - New chat photo. You can pass a :class:`Photo` id or a file path to upload a new photo. + New chat photo. You can pass a :obj:`Photo` id or a file path to upload a new photo. Returns: ``bool``: True on success. Raises: RPCError: In case of a Telegram RPC error. - ``ValueError`` if a chat_id belongs to user. + ValueError: if a chat_id belongs to user. """ peer = await self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/update_chat_username.py b/pyrogram/client/methods/chats/update_chat_username.py index d5cdfac4..a531bf63 100644 --- a/pyrogram/client/methods/chats/update_chat_username.py +++ b/pyrogram/client/methods/chats/update_chat_username.py @@ -30,7 +30,7 @@ class UpdateChatUsername(BaseClient): ) -> bool: """Update a channel or a supergroup username. - To update your own username (for users only, not bots) you can use :meth:`update_username`. + To update your own username (for users only, not bots) you can use :meth:`~Client.update_username`. Parameters: chat_id (``int`` | ``str``) diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/client/methods/decorators/on_callback_query.py index b76655fb..5057f59f 100644 --- a/pyrogram/client/methods/decorators/on_callback_query.py +++ b/pyrogram/client/methods/decorators/on_callback_query.py @@ -32,7 +32,7 @@ class OnCallbackQuery(BaseClient): ) -> callable: """Decorator for handling callback queries. - This does the same thing as :meth:`add_handler` using the :class:`CallbackQueryHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`CallbackQueryHandler`. Parameters: filters (:obj:`Filters`): diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py index 7637e6eb..53457b55 100644 --- a/pyrogram/client/methods/decorators/on_deleted_messages.py +++ b/pyrogram/client/methods/decorators/on_deleted_messages.py @@ -32,7 +32,7 @@ class OnDeletedMessages(BaseClient): ) -> callable: """Decorator for handling deleted messages. - This does the same thing as :meth:`add_handler` using the :class:`DeletedMessagesHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`DeletedMessagesHandler`. Parameters: filters (:obj:`Filters`): diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/client/methods/decorators/on_disconnect.py index 9305808e..b195ac54 100644 --- a/pyrogram/client/methods/decorators/on_disconnect.py +++ b/pyrogram/client/methods/decorators/on_disconnect.py @@ -25,7 +25,7 @@ class OnDisconnect(BaseClient): def on_disconnect(self=None) -> callable: """Decorator for handling disconnections. - This does the same thing as :meth:`add_handler` using the :class:`DisconnectHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`DisconnectHandler`. """ def decorator(func: callable) -> Handler: diff --git a/pyrogram/client/methods/decorators/on_inline_query.py b/pyrogram/client/methods/decorators/on_inline_query.py index 58837398..ee7175eb 100644 --- a/pyrogram/client/methods/decorators/on_inline_query.py +++ b/pyrogram/client/methods/decorators/on_inline_query.py @@ -32,7 +32,7 @@ class OnInlineQuery(BaseClient): ) -> callable: """Decorator for handling inline queries. - This does the same thing as :meth:`add_handler` using the :class:`InlineQueryHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`InlineQueryHandler`. Parameters: filters (:obj:`Filters `): diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/client/methods/decorators/on_message.py index f590fd12..0f5c836c 100644 --- a/pyrogram/client/methods/decorators/on_message.py +++ b/pyrogram/client/methods/decorators/on_message.py @@ -32,7 +32,7 @@ class OnMessage(BaseClient): ) -> callable: """Decorator for handling messages. - This does the same thing as :meth:`add_handler` using the :class:`MessageHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`MessageHandler`. Parameters: filters (:obj:`Filters`): diff --git a/pyrogram/client/methods/decorators/on_poll.py b/pyrogram/client/methods/decorators/on_poll.py index de1c1d3d..7442858d 100644 --- a/pyrogram/client/methods/decorators/on_poll.py +++ b/pyrogram/client/methods/decorators/on_poll.py @@ -32,10 +32,10 @@ class OnPoll(BaseClient): ) -> callable: """Decorator for handling poll updates. - This does the same thing as :meth:`add_handler` using the :class:`PollHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`PollHandler`. Parameters: - filters (:obj:`Filters `): + filters (:obj:`Filters`): Pass one or more filters to allow only a subset of polls to be passed in your function. diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/client/methods/decorators/on_raw_update.py index 53a0f4cf..e03402ca 100644 --- a/pyrogram/client/methods/decorators/on_raw_update.py +++ b/pyrogram/client/methods/decorators/on_raw_update.py @@ -30,7 +30,7 @@ class OnRawUpdate(BaseClient): ) -> callable: """Decorator for handling raw updates. - This does the same thing as :meth:`add_handler` using the :class:`RawUpdateHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`RawUpdateHandler`. Parameters: group (``int``, *optional*): diff --git a/pyrogram/client/methods/decorators/on_user_status.py b/pyrogram/client/methods/decorators/on_user_status.py index e7db7b74..bcdcf024 100644 --- a/pyrogram/client/methods/decorators/on_user_status.py +++ b/pyrogram/client/methods/decorators/on_user_status.py @@ -31,7 +31,7 @@ class OnUserStatus(BaseClient): group: int = 0 ) -> callable: """Decorator for handling user status updates. - This does the same thing as :meth:`add_handler` using the :class:`UserStatusHandler`. + This does the same thing as :meth:`~Client.add_handler` using the :obj:`UserStatusHandler`. Parameters: filters (:obj:`Filters`): diff --git a/pyrogram/client/methods/messages/__init__.py b/pyrogram/client/methods/messages/__init__.py index e843aa7c..9ed6e33b 100644 --- a/pyrogram/client/methods/messages/__init__.py +++ b/pyrogram/client/methods/messages/__init__.py @@ -28,6 +28,7 @@ from .get_history_count import GetHistoryCount from .get_messages import GetMessages from .iter_history import IterHistory from .retract_vote import RetractVote +from .send_animated_sticker import SendAnimatedSticker from .send_animation import SendAnimation from .send_audio import SendAudio from .send_cached_media import SendCachedMedia @@ -78,6 +79,7 @@ class Messages( DownloadMedia, IterHistory, SendCachedMedia, - GetHistoryCount + GetHistoryCount, + SendAnimatedSticker ): pass diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/client/methods/messages/download_media.py index b91ac9a4..ba78f580 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/client/methods/messages/download_media.py @@ -17,10 +17,13 @@ # along with Pyrogram. If not, see . import asyncio +import binascii +import struct from typing import Union import pyrogram -from pyrogram.client.ext import BaseClient +from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FileIdInvalid class DownloadMedia(BaseClient): @@ -74,74 +77,98 @@ class DownloadMedia(BaseClient): Returns: ``str`` | ``None``: On success, the absolute path of the downloaded file is returned, otherwise, in case - the download failed or was deliberately stopped with :meth:`stop_transmission`, None is returned. + the download failed or was deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. ``ValueError`` if the message doesn't contain any downloadable media """ error_message = "This message doesn't contain any downloadable media" + available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note") + + file_size = None + mime_type = None + date = None if isinstance(message, pyrogram.Message): - if message.photo: - media = pyrogram.Document( - file_id=message.photo.sizes[-1].file_id, - file_size=message.photo.sizes[-1].file_size, - mime_type="", - date=message.photo.date, - client=self - ) - elif message.audio: - media = message.audio - elif message.document: - media = message.document - elif message.video: - media = message.video - elif message.voice: - media = message.voice - elif message.video_note: - media = message.video_note - elif message.sticker: - media = message.sticker - elif message.animation: - media = message.animation + for kind in available_media: + media = getattr(message, kind, None) + + if media is not None: + break else: raise ValueError(error_message) - elif isinstance(message, ( - pyrogram.Photo, - pyrogram.PhotoSize, - pyrogram.Audio, - pyrogram.Document, - pyrogram.Video, - pyrogram.Voice, - pyrogram.VideoNote, - pyrogram.Sticker, - pyrogram.Animation - )): - if isinstance(message, pyrogram.Photo): - media = pyrogram.Document( - file_id=message.sizes[-1].file_id, - file_size=message.sizes[-1].file_size, - mime_type="", - date=message.date, - client=self + else: + media = message + + if isinstance(media, str): + file_id_str = media + else: + file_id_str = media.file_id + file_name = getattr(media, "file_name", "") + file_size = getattr(media, "file_size", None) + mime_type = getattr(media, "mime_type", None) + date = getattr(media, "date", None) + + data = self.FileData( + file_name=file_name, + file_size=file_size, + mime_type=mime_type, + date=date + ) + + def get_existing_attributes() -> dict: + return dict(filter(lambda x: x[1] is not None, data._asdict().items())) + + try: + decoded = utils.decode(file_id_str) + media_type = decoded[0] + + if media_type == 1: + unpacked = struct.unpack(". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid from pyrogram.client.ext import BaseClient, utils from pyrogram.client.types import ( InputMediaPhoto, InputMediaVideo, InputMediaAudio, @@ -94,28 +91,7 @@ class EditMessageMedia(BaseClient): url=media.media ) else: - try: - decoded = utils.decode(media.media) - fmt = " 24 else " 24 else " 24 else " 24 else " 24 else " Optional[AsyncGenerator["pyrogram.Message", None]]: """Iterate through a chat history sequentially. - This convenience method does the same as repeatedly calling :meth:`get_history` in a loop, thus saving you from - the hassle of setting up boilerplate code. It is useful for getting the whole chat history with a single call. + This convenience method does the same as repeatedly calling :meth:`~Client.get_history` in a loop, thus saving + you from the hassle of setting up boilerplate code. It is useful for getting the whole chat history with a + single call. Parameters: chat_id (``int`` | ``str``): diff --git a/pyrogram/client/methods/messages/send_animated_sticker.py b/pyrogram/client/methods/messages/send_animated_sticker.py new file mode 100644 index 00000000..6fd0c647 --- /dev/null +++ b/pyrogram/client/methods/messages/send_animated_sticker.py @@ -0,0 +1,141 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 . + +import os +from typing import Union + +import pyrogram +from pyrogram.api import functions, types +from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing + + +class SendAnimatedSticker(BaseClient): + def send_animated_sticker( + self, + chat_id: Union[int, str], + animated_sticker: str, + disable_notification: bool = None, + reply_to_message_id: int = None, + reply_markup: Union[ + "pyrogram.InlineKeyboardMarkup", + "pyrogram.ReplyKeyboardMarkup", + "pyrogram.ReplyKeyboardRemove", + "pyrogram.ForceReply" + ] = None, + progress: callable = None, + progress_args: tuple = () + ) -> Union["pyrogram.Message", None]: + """Send .tgs animated stickers. + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + animated_sticker (``str``): + Animated sticker to send. + Pass a file_id as string to send a animated sticker that exists on the Telegram servers, + pass an HTTP URL as a string for Telegram to get a .webp animated sticker file from the Internet, or + pass a file path as string to upload a new animated sticker that exists on your local machine. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_message_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + Additional interface options. An object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + + progress (``callable``, *optional*): + Pass a callback function to view the upload progress. + The function must take *(client, current, total, \*args)* as positional arguments (look at the section + below for a detailed description). + + progress_args (``tuple``, *optional*): + Extra custom arguments for the progress callback function. Useful, for example, if you want to pass + a chat_id and a message_id in order to edit a message with the updated progress. + + Other Parameters: + client (:obj:`Client`): + The Client itself, useful when you want to call other API methods inside the callback function. + + current (``int``): + The amount of bytes uploaded so far. + + total (``int``): + The size of the file. + + *args (``tuple``, *optional*): + Extra custom arguments as defined in the *progress_args* parameter. + You can either keep *\*args* or add every single extra argument in your function signature. + + Returns: + :obj:`Message` | ``None``: On success, the sent animated sticker message is returned, otherwise, in case the + upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + Raises: + RPCError: In case of a Telegram RPC error. + """ + file = None + + try: + if os.path.exists(animated_sticker): + file = self.save_file(animated_sticker, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(animated_sticker) or "application/x-tgsticker", + file=file, + attributes=[ + types.DocumentAttributeFilename(file_name=os.path.basename(animated_sticker)) + ] + ) + elif animated_sticker.startswith("http"): + media = types.InputMediaDocumentExternal( + url=animated_sticker + ) + else: + media = utils.get_input_media_from_file_id(animated_sticker, 5) + + while True: + try: + r = self.send( + functions.messages.SendMedia( + peer=self.resolve_peer(chat_id), + media=media, + silent=disable_notification or None, + reply_to_msg_id=reply_to_message_id, + random_id=self.rnd_id(), + reply_markup=reply_markup.write() if reply_markup else None, + message="" + ) + ) + except FilePartMissing as e: + self.save_file(animated_sticker, file_id=file.id, file_part=e.x) + else: + for i in r.updates: + if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): + return pyrogram.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats} + ) + except BaseClient.StopTransmission: + return None diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index 7c6e7742..1fcf8b78 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -16,15 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendAnimation(BaseClient): @@ -121,7 +119,7 @@ class SendAnimation(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent animation message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -153,28 +151,7 @@ class SendAnimation(BaseClient): url=animation ) else: - try: - decoded = utils.decode(animation) - fmt = " 24 else ". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendAudio(BaseClient): @@ -122,7 +120,7 @@ class SendAudio(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent audio message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -152,28 +150,7 @@ class SendAudio(BaseClient): url=audio ) else: - try: - decoded = utils.decode(audio) - fmt = " 24 else ". -import binascii -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid from pyrogram.client.ext import BaseClient, utils @@ -84,39 +81,10 @@ class SendCachedMedia(BaseClient): """ style = self.html if parse_mode.lower() == "html" else self.markdown - try: - decoded = utils.decode(file_id) - fmt = " 24 else ". +import json from typing import Union from pyrogram.api import functions, types from pyrogram.client.ext import BaseClient -import json class ChatAction: diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index ab0a16b6..ee7ede89 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -16,15 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendDocument(BaseClient): @@ -108,7 +106,7 @@ class SendDocument(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent document message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -133,28 +131,7 @@ class SendDocument(BaseClient): url=document ) else: - try: - decoded = utils.decode(document) - fmt = " 24 else ". -import binascii +import asyncio import logging import os -import struct from typing import Union, List -import asyncio import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FloodWait from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FloodWait log = logging.getLogger(__name__) @@ -96,28 +94,7 @@ class SendMediaGroup(BaseClient): ) ) else: - try: - decoded = utils.decode(i.media) - fmt = " 24 else " 24 else ". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendPhoto(BaseClient): @@ -108,7 +106,7 @@ class SendPhoto(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent photo message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -129,29 +127,7 @@ class SendPhoto(BaseClient): ttl_seconds=ttl_seconds ) else: - try: - decoded = utils.decode(photo) - fmt = " 24 else ". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendSticker(BaseClient): @@ -93,7 +91,7 @@ class SendSticker(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. """ @@ -114,28 +112,7 @@ class SendSticker(BaseClient): url=sticker ) else: - try: - decoded = utils.decode(sticker) - fmt = " 24 else ". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendVideo(BaseClient): @@ -125,7 +123,7 @@ class SendVideo(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent video message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -156,28 +154,7 @@ class SendVideo(BaseClient): url=video ) else: - try: - decoded = utils.decode(video) - fmt = " 24 else ". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendVideoNote(BaseClient): @@ -108,7 +106,7 @@ class SendVideoNote(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent video note message is returned, otherwise, in case the - pload is deliberately stopped with :meth:`stop_transmission`, None is returned. + pload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -133,28 +131,7 @@ class SendVideoNote(BaseClient): ] ) else: - try: - decoded = utils.decode(video_note) - fmt = " 24 else ". -import binascii import os -import struct from typing import Union import pyrogram from pyrogram.api import functions, types -from pyrogram.errors import FileIdInvalid, FilePartMissing from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing class SendVoice(BaseClient): @@ -106,7 +104,7 @@ class SendVoice(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent voice message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`stop_transmission`, None is returned. + is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -132,28 +130,7 @@ class SendVoice(BaseClient): url=voice ) else: - try: - decoded = utils.decode(voice) - fmt = " 24 else ". -from .delete_user_profile_photos import DeleteUserProfilePhotos +from .delete_profile_photos import DeleteProfilePhotos from .get_me import GetMe -from .get_user_profile_photos import GetUserProfilePhotos -from .get_user_profile_photos_count import GetUserProfilePhotosCount +from .get_profile_photos import GetProfilePhotos +from .get_profile_photos_count import GetProfilePhotosCount +from .get_user_dc import GetUserDC from .get_users import GetUsers -from .set_user_profile_photo import SetUserProfilePhoto +from .iter_profile_photos import IterProfilePhotos +from .set_profile_photo import SetProfilePhoto from .update_username import UpdateUsername class Users( - GetUserProfilePhotos, - SetUserProfilePhoto, - DeleteUserProfilePhotos, + GetProfilePhotos, + SetProfilePhoto, + DeleteProfilePhotos, GetUsers, GetMe, UpdateUsername, - GetUserProfilePhotosCount + GetProfilePhotosCount, + GetUserDC, + IterProfilePhotos ): pass diff --git a/pyrogram/client/methods/users/delete_user_profile_photos.py b/pyrogram/client/methods/users/delete_profile_photos.py similarity index 95% rename from pyrogram/client/methods/users/delete_user_profile_photos.py rename to pyrogram/client/methods/users/delete_profile_photos.py index 7f6d433a..322b537d 100644 --- a/pyrogram/client/methods/users/delete_user_profile_photos.py +++ b/pyrogram/client/methods/users/delete_profile_photos.py @@ -24,8 +24,8 @@ from pyrogram.api import functions, types from ...ext import BaseClient -class DeleteUserProfilePhotos(BaseClient): - async def delete_user_profile_photos( +class DeleteProfilePhotos(BaseClient): + async def delete_profile_photos( self, id: Union[str, List[str]] ) -> bool: diff --git a/pyrogram/client/methods/users/get_profile_photos.py b/pyrogram/client/methods/users/get_profile_photos.py new file mode 100644 index 00000000..6796275b --- /dev/null +++ b/pyrogram/client/methods/users/get_profile_photos.py @@ -0,0 +1,92 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 . + +from typing import Union + +import pyrogram +from pyrogram.api import functions, types +from ...ext import BaseClient + + +class GetProfilePhotos(BaseClient): + async def get_profile_photos( + self, + chat_id: Union[int, str], + offset: int = 0, + limit: int = 100 + ) -> "pyrogram.Photos": + """Get a list of profile pictures for a user or a chat. + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + offset (``int``, *optional*): + Sequential number of the first photo to be returned. + By default, all photos are returned. + + limit (``int``, *optional*): + Limits the number of photos to be retrieved. + Values between 1—100 are accepted. Defaults to 100. + + Returns: + :obj:`Photos`: On success, an object containing a list of the profile photos is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + peer_id = await self.resolve_peer(chat_id) + + if isinstance(peer_id, types.InputPeerUser): + return pyrogram.Photos._parse( + self, + await self.send( + functions.photos.GetUserPhotos( + user_id=peer_id, + offset=offset, + max_id=0, + limit=limit + ) + ) + ) + else: + new_chat_photos = pyrogram.Messages._parse( + self, + await self.send( + functions.messages.Search( + peer=peer_id, + q="", + filter=types.InputMessagesFilterChatPhotos(), + min_date=0, + max_date=0, + offset_id=0, + add_offset=offset, + limit=limit, + max_id=0, + min_id=0, + hash=0 + ) + ) + ) + + return pyrogram.Photos( + total_count=new_chat_photos.total_count, + photos=[m.new_chat_photo for m in new_chat_photos.messages][:limit] + ) diff --git a/pyrogram/client/methods/users/get_user_profile_photos_count.py b/pyrogram/client/methods/users/get_profile_photos_count.py similarity index 71% rename from pyrogram/client/methods/users/get_user_profile_photos_count.py rename to pyrogram/client/methods/users/get_profile_photos_count.py index cd9d9434..4104b7ce 100644 --- a/pyrogram/client/methods/users/get_user_profile_photos_count.py +++ b/pyrogram/client/methods/users/get_profile_photos_count.py @@ -18,16 +18,15 @@ from typing import Union -from pyrogram.api import functions, types from ...ext import BaseClient -class GetUserProfilePhotosCount(BaseClient): - async def get_user_profile_photos_count(self, user_id: Union[int, str]) -> int: +class GetProfilePhotosCount(BaseClient): + async def get_profile_photos_count(self, chat_id: Union[int, str]) -> int: """Get the total count of profile pictures for a user. Parameters: - user_id (``int`` | ``str``): + chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). @@ -39,16 +38,4 @@ class GetUserProfilePhotosCount(BaseClient): RPCError: In case of a Telegram RPC error. """ - r = await self.send( - functions.photos.GetUserPhotos( - user_id=await self.resolve_peer(user_id), - offset=0, - max_id=0, - limit=1 - ) - ) - - if isinstance(r, types.photos.Photos): - return len(r.photos) - else: - return r.count + return await self.get_profile_photos(chat_id, limit=1).total_count diff --git a/pyrogram/client/methods/users/get_user_profile_photos.py b/pyrogram/client/methods/users/get_user_dc.py similarity index 53% rename from pyrogram/client/methods/users/get_user_profile_photos.py rename to pyrogram/client/methods/users/get_user_dc.py index 3cfb8295..0e1643bf 100644 --- a/pyrogram/client/methods/users/get_user_profile_photos.py +++ b/pyrogram/client/methods/users/get_user_dc.py @@ -18,19 +18,13 @@ from typing import Union -import pyrogram -from pyrogram.api import functions +from pyrogram.api import functions, types from ...ext import BaseClient -class GetUserProfilePhotos(BaseClient): - async def get_user_profile_photos( - self, - user_id: Union[int, str], - offset: int = 0, - limit: int = 100 - ) -> "pyrogram.UserProfilePhotos": - """Get a list of profile pictures for a user. +class GetUserDC(BaseClient): + async def get_user_dc(self, user_id: Union[int, str]) -> Union[int, None]: + """Get the assigned data center (DC) of a user. Parameters: user_id (``int`` | ``str``): @@ -38,28 +32,20 @@ class GetUserProfilePhotos(BaseClient): For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - offset (``int``, *optional*): - Sequential number of the first photo to be returned. - By default, all photos are returned. - - limit (``int``, *optional*): - Limits the number of photos to be retrieved. - Values between 1—100 are accepted. Defaults to 100. - Returns: - :obj:`UserProfilePhotos`: On success, an object containing a list of the profile photos is returned. + ``int`` | ``None``: The DC identifier as integer, or None in case it wasn't possible to get it. Raises: RPCError: In case of a Telegram RPC error. """ - return pyrogram.UserProfilePhotos._parse( - self, - await self.send( - functions.photos.GetUserPhotos( - user_id=await self.resolve_peer(user_id), - offset=offset, - max_id=0, - limit=limit - ) - ) - ) + + r = await self.send(functions.users.GetUsers(id=[await self.resolve_peer(user_id)])) + + if r: + r = r[0] + + if r.photo: + if isinstance(r.photo, types.UserProfilePhoto): + return r.photo.dc_id + + return None diff --git a/pyrogram/client/methods/users/iter_profile_photos.py b/pyrogram/client/methods/users/iter_profile_photos.py new file mode 100644 index 00000000..e32e2a18 --- /dev/null +++ b/pyrogram/client/methods/users/iter_profile_photos.py @@ -0,0 +1,82 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 . + +from typing import Union, Generator + +from async_generator import async_generator, yield_ + +import pyrogram +from ...ext import BaseClient + + +class IterProfilePhotos(BaseClient): + @async_generator + async def iter_profile_photos( + self, + chat_id: Union[int, str], + offset: int = 0, + limit: int = 0, + ) -> Generator["pyrogram.Photo", None, None]: + """Iterate through a chat or a user profile photos sequentially. + + This convenience method does the same as repeatedly calling :meth:`~Client.get_profile_photos` in a loop, thus + saving you from the hassle of setting up boilerplate code. It is useful for getting all the profile photos with + a single call. + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + limit (``int``, *optional*): + Limits the number of profile photos to be retrieved. + By default, no limit is applied and all profile photos are returned. + + offset (``int``, *optional*): + Sequential number of the first profile photo to be returned. + + Returns: + ``Generator``: A generator yielding :obj:`Photo` objects. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + current = 0 + total = limit or (1 << 31) + limit = min(100, total) + + while True: + photos = self.get_profile_photos( + chat_id=chat_id, + offset=offset, + limit=limit + ).photos + + if not photos: + return + + offset += len(photos) + + for photo in photos: + await yield_(photo) + + current += 1 + + if current >= total: + return diff --git a/pyrogram/client/methods/users/set_user_profile_photo.py b/pyrogram/client/methods/users/set_profile_photo.py similarity index 95% rename from pyrogram/client/methods/users/set_user_profile_photo.py rename to pyrogram/client/methods/users/set_profile_photo.py index 6f6c402e..0a437534 100644 --- a/pyrogram/client/methods/users/set_user_profile_photo.py +++ b/pyrogram/client/methods/users/set_profile_photo.py @@ -20,8 +20,8 @@ from pyrogram.api import functions from ...ext import BaseClient -class SetUserProfilePhoto(BaseClient): - async def set_user_profile_photo( +class SetProfilePhoto(BaseClient): + async def set_profile_photo( self, photo: str ) -> bool: diff --git a/pyrogram/client/methods/users/update_username.py b/pyrogram/client/methods/users/update_username.py index ab8b9c59..92ee1ddd 100644 --- a/pyrogram/client/methods/users/update_username.py +++ b/pyrogram/client/methods/users/update_username.py @@ -31,7 +31,7 @@ class UpdateUsername(BaseClient): This method only works for users, not bots. Bot usernames must be changed via Bot Support or by recreating them from scratch using BotFather. To update a channel or supergroup username you can use - :meth:`update_chat_username`. + :meth:`~Client.update_chat_username`. Parameters: username (``str`` | ``None``): diff --git a/pyrogram/client/types/inline_mode/inline_query.py b/pyrogram/client/types/inline_mode/inline_query.py index 605d98cc..5a62e3a5 100644 --- a/pyrogram/client/types/inline_mode/inline_query.py +++ b/pyrogram/client/types/inline_mode/inline_query.py @@ -92,7 +92,7 @@ class InlineQuery(PyrogramType, Update): switch_pm_text: str = "", switch_pm_parameter: str = "" ): - """Bound method *answer* of :obj:`InlineQuery `. + """Bound method *answer* of :obj:`InlineQuery`. Use this method as a shortcut for: @@ -109,7 +109,7 @@ class InlineQuery(PyrogramType, Update): inline_query.answer([...]) Parameters: - results (List of :obj:`InlineQueryResult `): + results (List of :obj:`InlineQueryResult`): A list of results for the inline query. cache_time (``int``, *optional*): diff --git a/pyrogram/client/types/inline_mode/inline_query_result_article.py b/pyrogram/client/types/inline_mode/inline_query_result_article.py index 2e6dd830..94861c79 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_article.py +++ b/pyrogram/client/types/inline_mode/inline_query_result_article.py @@ -34,10 +34,10 @@ class InlineQueryResultArticle(InlineQueryResult): title (``str``): Title for the result. - input_message_content (:obj:`InputMessageContent `): + input_message_content (:obj:`InputMessageContent`): Content of the message to be sent. - reply_markup (:obj:`InlineKeyboardMarkup `, *optional*): + reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): Inline keyboard attached to the message. url (``str``, *optional*): diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py index 0ef30b20..6ca0478a 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py @@ -50,10 +50,10 @@ class InlineQueryResultAudio(PyrogramType): audio_duration (``int`` ``32-bit``, optional): Audio duration in seconds. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the audio. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py index e2873638..ad6cb9af 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py @@ -47,10 +47,10 @@ class InlineQueryResultCachedDocument(PyrogramType): parse_mode (``str``, optional): Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the file. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py index 8b523dbd..1c836f20 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py @@ -44,10 +44,10 @@ class InlineQueryResultCachedGif(PyrogramType): parse_mode (``str``, optional): Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the GIF animation. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py index 06944deb..4711cd72 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py @@ -35,10 +35,10 @@ class InlineQueryResultCachedSticker(PyrogramType): sticker_file_id (``str``): A valid file identifier of the sticker. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the sticker. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py index 3f8bb6a3..3091cf65 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py @@ -44,10 +44,10 @@ class InlineQueryResultCachedVoice(PyrogramType): parse_mode (``str``, optional): Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the voice message. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py index 148ec01d..a95dd2e9 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py @@ -50,10 +50,10 @@ class InlineQueryResultDocument(PyrogramType): description (``str``, optional): Short description of the result. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the file. thumb_url (``str``, optional): diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py index faebacea..98654463 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py @@ -35,7 +35,7 @@ class InlineQueryResultGame(PyrogramType): game_short_name (``str``): Short name of the game. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py index 3412b3f4..db6b9090 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py @@ -54,10 +54,10 @@ class InlineQueryResultPhoto(PyrogramType): Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption. - reply_markup (:obj:`InlineKeyboardMarkup `, *optional*): + reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, *optional*): + input_message_content (:obj:`InputMessageContent`, *optional*): Content of the message to be sent instead of the photo. """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py index 1dee9509..51ee8ae7 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py @@ -50,10 +50,10 @@ class InlineQueryResultVenue(PyrogramType): foursquare_type (``str``, optional): Foursquare type of the venue, if known. (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".). - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the venue. thumb_url (``str``, optional): diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py index 22d810e1..c8e27f79 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py @@ -62,10 +62,10 @@ class InlineQueryResultVideo(PyrogramType): description (``str``, optional): Short description of the result. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the video. This field is required if InlineQueryResultVideo is used to send an HTML-page as a result (e.g., a YouTube video). """ diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py index 73d7fb1d..23cc741f 100644 --- a/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py +++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py @@ -47,10 +47,10 @@ class InlineQueryResultVoice(PyrogramType): voice_duration (``int`` ``32-bit``, optional): Recording duration in seconds. - reply_markup (:obj:`InlineKeyboardMarkup `, optional): + reply_markup (:obj:`InlineKeyboardMarkup`, optional): Inline keyboard attached to the message. - input_message_content (:obj:`InputMessageContent `, optional): + input_message_content (:obj:`InputMessageContent`, optional): Content of the message to be sent instead of the voice recording. """ diff --git a/pyrogram/client/types/input_media/input_phone_contact.py b/pyrogram/client/types/input_media/input_phone_contact.py index 0b6353b7..c1627516 100644 --- a/pyrogram/client/types/input_media/input_phone_contact.py +++ b/pyrogram/client/types/input_media/input_phone_contact.py @@ -23,7 +23,7 @@ from ..pyrogram_type import PyrogramType class InputPhoneContact(PyrogramType): """A Phone Contact to be added in your Telegram address book. - It is intended to be used with :meth:`add_contacts() ` + It is intended to be used with :meth:`~Client.add_contacts() ` Parameters: phone (``str``): diff --git a/pyrogram/client/types/messages_and_media/__init__.py b/pyrogram/client/types/messages_and_media/__init__.py index ae4386d0..d312611b 100644 --- a/pyrogram/client/types/messages_and_media/__init__.py +++ b/pyrogram/client/types/messages_and_media/__init__.py @@ -26,11 +26,12 @@ from .message import Message from .message_entity import MessageEntity from .messages import Messages from .photo import Photo -from .photo_size import PhotoSize from .poll import Poll from .poll_option import PollOption from .sticker import Sticker -from .user_profile_photos import UserProfilePhotos +from .stripped_thumbnail import StrippedThumbnail +from .thumbnail import Thumbnail +from .photos import Photos from .venue import Venue from .video import Video from .video_note import VideoNote @@ -38,5 +39,5 @@ from .voice import Voice __all__ = [ "Animation", "Audio", "Contact", "Document", "Game", "Location", "Message", "MessageEntity", "Messages", "Photo", - "PhotoSize", "Poll", "PollOption", "Sticker", "UserProfilePhotos", "Venue", "Video", "VideoNote", "Voice" + "Thumbnail", "StrippedThumbnail", "Poll", "PollOption", "Sticker", "Photos", "Venue", "Video", "VideoNote", "Voice" ] diff --git a/pyrogram/client/types/messages_and_media/animation.py b/pyrogram/client/types/messages_and_media/animation.py index cd6e03ab..d729c3ac 100644 --- a/pyrogram/client/types/messages_and_media/animation.py +++ b/pyrogram/client/types/messages_and_media/animation.py @@ -17,10 +17,11 @@ # along with Pyrogram. If not, see . from struct import pack +from typing import List import pyrogram from pyrogram.api import types -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -41,9 +42,6 @@ class Animation(PyrogramType): duration (``int``): Duration of the animation in seconds as defined by sender. - thumb (:obj:`PhotoSize `, *optional*): - Animation thumbnail. - file_name (``str``, *optional*): Animation file name. @@ -55,9 +53,12 @@ class Animation(PyrogramType): date (``int``, *optional*): Date the animation was sent in Unix time. + + thumbnails (List of :obj:`Thumbnail`, *optional*): + Animation thumbnails. """ - __slots__ = ["file_id", "thumb", "file_name", "mime_type", "file_size", "date", "width", "height", "duration"] + __slots__ = ["file_id", "file_name", "mime_type", "file_size", "date", "width", "height", "duration", "thumbnails"] def __init__( self, @@ -67,16 +68,15 @@ class Animation(PyrogramType): width: int, height: int, duration: int, - thumb: PhotoSize = None, file_name: str = None, mime_type: str = None, file_size: int = None, - date: int = None + date: int = None, + thumbnails: List[Thumbnail] = None, ): super().__init__(client) self.file_id = file_id - self.thumb = thumb self.file_name = file_name self.mime_type = mime_type self.file_size = file_size @@ -84,10 +84,15 @@ class Animation(PyrogramType): self.width = width self.height = height self.duration = duration + self.thumbnails = thumbnails @staticmethod - def _parse(client, animation: types.Document, video_attributes: types.DocumentAttributeVideo, - file_name: str) -> "Animation": + def _parse( + client, + animation: types.Document, + video_attributes: types.DocumentAttributeVideo, + file_name: str + ) -> "Animation": return Animation( file_id=encode( pack( @@ -101,10 +106,10 @@ class Animation(PyrogramType): width=getattr(video_attributes, "w", 0), height=getattr(video_attributes, "h", 0), duration=getattr(video_attributes, "duration", 0), - thumb=PhotoSize._parse(client, animation.thumbs), mime_type=animation.mime_type, file_size=animation.size, file_name=file_name, date=animation.date, + thumbnails=Thumbnail._parse(client, animation), client=client ) diff --git a/pyrogram/client/types/messages_and_media/audio.py b/pyrogram/client/types/messages_and_media/audio.py index 76181a22..ccea2f3c 100644 --- a/pyrogram/client/types/messages_and_media/audio.py +++ b/pyrogram/client/types/messages_and_media/audio.py @@ -17,10 +17,11 @@ # along with Pyrogram. If not, see . from struct import pack +from typing import List import pyrogram from pyrogram.api import types -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -35,9 +36,6 @@ class Audio(PyrogramType): duration (``int``): Duration of the audio in seconds as defined by sender. - thumb (:obj:`PhotoSize`, *optional*): - Thumbnail of the music file album cover. - file_name (``str``, *optional*): Audio file name. @@ -55,9 +53,14 @@ class Audio(PyrogramType): title (``str``, *optional*): Title of the audio as defined by sender or by audio tags. + + thumbnails (List of :obj:`Thumbnail`, *optional*): + Thumbnails of the music file album cover. """ - __slots__ = ["file_id", "thumb", "file_name", "mime_type", "file_size", "date", "duration", "performer", "title"] + __slots__ = [ + "file_id", "file_name", "mime_type", "file_size", "date", "duration", "performer", "title", "thumbnails" + ] def __init__( self, @@ -65,18 +68,17 @@ class Audio(PyrogramType): client: "pyrogram.BaseClient" = None, file_id: str, duration: int, - thumb: PhotoSize = None, file_name: str = None, mime_type: str = None, file_size: int = None, date: int = None, performer: str = None, - title: str = None + title: str = None, + thumbnails: List[Thumbnail] = None, ): super().__init__(client) self.file_id = file_id - self.thumb = thumb self.file_name = file_name self.mime_type = mime_type self.file_size = file_size @@ -84,10 +86,15 @@ class Audio(PyrogramType): self.duration = duration self.performer = performer self.title = title + self.thumbnails = thumbnails @staticmethod - def _parse(client, audio: types.Document, audio_attributes: types.DocumentAttributeAudio, - file_name: str) -> "Audio": + def _parse( + client, + audio: types.Document, + audio_attributes: types.DocumentAttributeAudio, + file_name: str + ) -> "Audio": return Audio( file_id=encode( pack( @@ -103,8 +110,8 @@ class Audio(PyrogramType): title=audio_attributes.title, mime_type=audio.mime_type, file_size=audio.size, - thumb=PhotoSize._parse(client, audio.thumbs), file_name=file_name, date=audio.date, + thumbnails=Thumbnail._parse(client, audio), client=client ) diff --git a/pyrogram/client/types/messages_and_media/document.py b/pyrogram/client/types/messages_and_media/document.py index 394d5e14..a8838531 100644 --- a/pyrogram/client/types/messages_and_media/document.py +++ b/pyrogram/client/types/messages_and_media/document.py @@ -17,10 +17,11 @@ # along with Pyrogram. If not, see . from struct import pack +from typing import List import pyrogram from pyrogram.api import types -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -32,9 +33,6 @@ class Document(PyrogramType): file_id (``str``): Unique file identifier. - thumb (:obj:`PhotoSize`, *optional*): - Document thumbnail as defined by sender. - file_name (``str``, *optional*): Original filename as defined by sender. @@ -46,29 +44,32 @@ class Document(PyrogramType): date (``int``, *optional*): Date the document was sent in Unix time. + + thumbnails (List of :obj:`Thumbnail`, *optional*): + Document thumbnails as defined by sender. """ - __slots__ = ["file_id", "thumb", "file_name", "mime_type", "file_size", "date"] + __slots__ = ["file_id", "file_name", "mime_type", "file_size", "date", "thumbnails"] def __init__( self, *, client: "pyrogram.BaseClient" = None, file_id: str, - thumb: PhotoSize = None, file_name: str = None, mime_type: str = None, file_size: int = None, - date: int = None + date: int = None, + thumbnails: List[Thumbnail] = None, ): super().__init__(client) self.file_id = file_id - self.thumb = thumb self.file_name = file_name self.mime_type = mime_type self.file_size = file_size self.date = date + self.thumbnails = thumbnails @staticmethod def _parse(client, document: types.Document, file_name: str) -> "Document": @@ -82,10 +83,10 @@ class Document(PyrogramType): document.access_hash ) ), - thumb=PhotoSize._parse(client, document.thumbs), file_name=file_name, mime_type=document.mime_type, file_size=document.size, date=document.date, + thumbnails=Thumbnail._parse(client, document), client=client ) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index ebb5480a..f15d614c 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -110,7 +110,7 @@ class Message(PyrogramType, Update): new_chat_photo, delete_chat_photo, group_chat_created, supergroup_chat_created, channel_chat_created, migrate_to_chat_id, migrate_from_chat_id, pinned_message. - media (``bool`` *optional*): + media (``bool``, *optional*): The message is a media message. A media message has one and only one of these fields set: audio, document, photo, sticker, video, animation, voice, video_note, contact, location, venue. @@ -834,7 +834,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -968,7 +968,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1294,7 +1294,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1686,7 +1686,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1864,7 +1864,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2094,7 +2094,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2216,7 +2216,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2332,7 +2332,7 @@ class Message(PyrogramType, Update): Returns: On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. + In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2778,9 +2778,8 @@ class Message(PyrogramType, Update): Timeout in seconds. Returns: - - The result of :meth:`request_callback_answer() ` in case of - inline callback button clicks. - - The result of :meth:`reply() ` in case of normal button clicks. + - The result of :meth:`~Client.request_callback_answer` in case of inline callback button clicks. + - The result of :meth:`~Message.reply()` in case of normal button clicks. - A string in case the inline button is a URL, a *switch_inline_query* or a *switch_inline_query_current_chat* button. diff --git a/pyrogram/client/types/messages_and_media/messages.py b/pyrogram/client/types/messages_and_media/messages.py index 95fad2fa..6d0ed1ce 100644 --- a/pyrogram/client/types/messages_and_media/messages.py +++ b/pyrogram/client/types/messages_and_media/messages.py @@ -150,7 +150,7 @@ class Messages(PyrogramType, Update): Defaults to False. Returns: - On success, a :class:`Messages` containing forwarded messages is returned. + On success, a :obj:`Messages` containing forwarded messages is returned. Raises: RPCError: In case of a Telegram RPC error. diff --git a/pyrogram/client/types/messages_and_media/photo.py b/pyrogram/client/types/messages_and_media/photo.py index 8d60d59a..ca42c3eb 100644 --- a/pyrogram/client/types/messages_and_media/photo.py +++ b/pyrogram/client/types/messages_and_media/photo.py @@ -16,13 +16,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from base64 import b64encode from struct import pack from typing import List import pyrogram from pyrogram.api import types -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -31,74 +30,65 @@ class Photo(PyrogramType): """A Photo. Parameters: - id (``str``): + file_id (``str``): Unique identifier for this photo. + width (``int``): + Photo width. + + height (``int``): + Photo height. + + file_size (``int``): + File size. + date (``int``): Date the photo was sent in Unix time. - sizes (List of :obj:`PhotoSize`): + thumbnails (List of :obj:`Thumbnail`): Available sizes of this photo. """ - __slots__ = ["id", "date", "sizes"] + __slots__ = ["file_id", "width", "height", "file_size", "date", "thumbnails"] def __init__( self, *, client: "pyrogram.BaseClient" = None, - id: str, + file_id: str, + width: int, + height: int, + file_size: int, date: int, - sizes: List[PhotoSize] + thumbnails: List[Thumbnail] ): super().__init__(client) - self.id = id + self.file_id = file_id + self.width = width + self.height = height + self.file_size = file_size self.date = date - self.sizes = sizes + self.thumbnails = thumbnails @staticmethod - def _parse(client, photo: types.Photo): + def _parse(client, photo: types.Photo) -> "Photo": if isinstance(photo, types.Photo): - raw_sizes = photo.sizes - sizes = [] - - for raw_size in raw_sizes: - if isinstance(raw_size, (types.PhotoSize, types.PhotoCachedSize)): - if isinstance(raw_size, types.PhotoSize): - file_size = raw_size.size - elif isinstance(raw_size, types.PhotoCachedSize): - file_size = len(raw_size.bytes) - else: - file_size = 0 - - loc = raw_size.location - - if isinstance(loc, types.FileLocation): - size = PhotoSize( - file_id=encode( - pack( - " "UserProfilePhotos": - return UserProfilePhotos( + def _parse(client, photos) -> "Photos": + return Photos( total_count=getattr(photos, "count", len(photos.photos)), photos=[Photo._parse(client, photo) for photo in photos.photos], client=client diff --git a/pyrogram/client/types/messages_and_media/sticker.py b/pyrogram/client/types/messages_and_media/sticker.py index 08d56f6e..583556c5 100644 --- a/pyrogram/client/types/messages_and_media/sticker.py +++ b/pyrogram/client/types/messages_and_media/sticker.py @@ -17,13 +17,14 @@ # along with Pyrogram. If not, see . from struct import pack +from typing import List from async_lru import alru_cache import pyrogram from pyrogram.api import types, functions from pyrogram.errors import StickersetInvalid -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -41,9 +42,6 @@ class Sticker(PyrogramType): height (``int``): Sticker height. - thumb (:obj:`PhotoSize`, *optional*): - Sticker thumbnail in the .webp or .jpg format. - file_name (``str``, *optional*): Sticker file name. @@ -61,12 +59,15 @@ class Sticker(PyrogramType): set_name (``str``, *optional*): Name of the sticker set to which the sticker belongs. + + thumbnails (List of :obj:`Thumbnail`, *optional*): + Sticker thumbnails in the .webp or .jpg format. """ # TODO: Add mask position __slots__ = [ - "file_id", "thumb", "file_name", "mime_type", "file_size", "date", "width", "height", "emoji", "set_name" + "file_id", "file_name", "mime_type", "file_size", "date", "width", "height", "emoji", "set_name", "thumbnails" ] def __init__( @@ -76,18 +77,17 @@ class Sticker(PyrogramType): file_id: str, width: int, height: int, - thumb: PhotoSize = None, file_name: str = None, mime_type: str = None, file_size: int = None, date: int = None, emoji: str = None, - set_name: str = None + set_name: str = None, + thumbnails: List[Thumbnail] = None ): super().__init__(client) self.file_id = file_id - self.thumb = thumb self.file_name = file_name self.mime_type = mime_type self.file_size = file_size @@ -95,7 +95,8 @@ class Sticker(PyrogramType): self.width = width self.height = height self.emoji = emoji - self.set_name = set_name + self.set_name = set_name, + self.thumbnails = thumbnails # self.mask_position = mask_position @staticmethod @@ -136,7 +137,6 @@ class Sticker(PyrogramType): ), width=image_size_attributes.w if image_size_attributes else 0, height=image_size_attributes.h if image_size_attributes else 0, - thumb=PhotoSize._parse(client, sticker.thumbs), # TODO: mask_position set_name=set_name, emoji=sticker_attributes.alt or None, @@ -144,5 +144,6 @@ class Sticker(PyrogramType): mime_type=sticker.mime_type, file_name=file_name, date=sticker.date, + thumbnails=Thumbnail._parse(client, sticker), client=client ) diff --git a/pyrogram/client/types/messages_and_media/stripped_thumbnail.py b/pyrogram/client/types/messages_and_media/stripped_thumbnail.py new file mode 100644 index 00000000..31638fc2 --- /dev/null +++ b/pyrogram/client/types/messages_and_media/stripped_thumbnail.py @@ -0,0 +1,49 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 . + +import pyrogram +from pyrogram.api import types +from ..pyrogram_type import PyrogramType + + +class StrippedThumbnail(PyrogramType): + """A stripped thumbnail + + Parameters: + data (``bytes``): + Thumbnail data + """ + + __slots__ = ["data"] + + def __init__( + self, + *, + client: "pyrogram.BaseClient" = None, + data: bytes, + ): + super().__init__(client) + + self.data = data + + @staticmethod + def _parse(client, stripped_thumbnail: types.PhotoStrippedSize) -> "StrippedThumbnail": + return StrippedThumbnail( + data=stripped_thumbnail.bytes, + client=client + ) diff --git a/pyrogram/client/types/messages_and_media/photo_size.py b/pyrogram/client/types/messages_and_media/thumbnail.py similarity index 53% rename from pyrogram/client/types/messages_and_media/photo_size.py rename to pyrogram/client/types/messages_and_media/thumbnail.py index 9f64ae6a..0ff15e66 100644 --- a/pyrogram/client/types/messages_and_media/photo_size.py +++ b/pyrogram/client/types/messages_and_media/thumbnail.py @@ -17,15 +17,16 @@ # along with Pyrogram. If not, see . from struct import pack -from typing import List, Union +from typing import Union, List import pyrogram from pyrogram.api import types from pyrogram.client.ext.utils import encode +from .stripped_thumbnail import StrippedThumbnail from ..pyrogram_type import PyrogramType -class PhotoSize(PyrogramType): +class Thumbnail(PyrogramType): """One size of a photo or a file/sticker thumbnail. Parameters: @@ -61,30 +62,44 @@ class PhotoSize(PyrogramType): self.file_size = file_size @staticmethod - def _parse(client, thumbs: List) -> Union["PhotoSize", None]: - if not thumbs: + def _parse( + client, + media: Union[types.Photo, types.Document] + ) -> Union[List[Union[StrippedThumbnail, "Thumbnail"]], None]: + if isinstance(media, types.Photo): + raw_thumbnails = media.sizes[:-1] + media_type = 0 + elif isinstance(media, types.Document): + raw_thumbnails = media.thumbs + media_type = 14 + + if not raw_thumbnails: + return None + else: return None - photo_size = thumbs[-1] + thumbnails = [] - if not isinstance(photo_size, (types.PhotoSize, types.PhotoCachedSize, types.PhotoStrippedSize)): - return None - - loc = photo_size.location - - if not isinstance(loc, types.FileLocation): - return None - - return PhotoSize( - file_id=encode( - pack( - ". from struct import pack +from typing import List import pyrogram from pyrogram.api import types -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -41,9 +42,6 @@ class Video(PyrogramType): duration (``int``): Duration of the video in seconds as defined by sender. - thumb (:obj:`PhotoSize`, *optional*): - Video thumbnail. - file_name (``str``, *optional*): Video file name. @@ -58,11 +56,14 @@ class Video(PyrogramType): date (``int``, *optional*): Date the video was sent in Unix time. + + thumbnails (List of :obj:`Thumbnail`, *optional*): + Video thumbnails. """ __slots__ = [ - "file_id", "width", "height", "duration", "thumb", "file_name", "mime_type", "supports_streaming", "file_size", - "date" + "file_id", "width", "height", "duration", "file_name", "mime_type", "supports_streaming", "file_size", "date", + "thumbnails" ] def __init__( @@ -73,12 +74,12 @@ class Video(PyrogramType): width: int, height: int, duration: int, - thumb: PhotoSize = None, file_name: str = None, mime_type: str = None, supports_streaming: bool = None, file_size: int = None, - date: int = None + date: int = None, + thumbnails: List[Thumbnail] = None ): super().__init__(client) @@ -86,16 +87,20 @@ class Video(PyrogramType): self.width = width self.height = height self.duration = duration - self.thumb = thumb self.file_name = file_name self.mime_type = mime_type self.supports_streaming = supports_streaming self.file_size = file_size self.date = date + self.thumbnails = thumbnails @staticmethod - def _parse(client, video: types.Document, video_attributes: types.DocumentAttributeVideo, - file_name: str) -> "Video": + def _parse( + client, + video: types.Document, + video_attributes: types.DocumentAttributeVideo, + file_name: str + ) -> "Video": return Video( file_id=encode( pack( @@ -109,11 +114,11 @@ class Video(PyrogramType): width=video_attributes.w, height=video_attributes.h, duration=video_attributes.duration, - thumb=PhotoSize._parse(client, video.thumbs), file_name=file_name, mime_type=video.mime_type, supports_streaming=video_attributes.supports_streaming, file_size=video.size, date=video.date, + thumbnails=Thumbnail._parse(client, video), client=client ) diff --git a/pyrogram/client/types/messages_and_media/video_note.py b/pyrogram/client/types/messages_and_media/video_note.py index 133ccae0..34f5972f 100644 --- a/pyrogram/client/types/messages_and_media/video_note.py +++ b/pyrogram/client/types/messages_and_media/video_note.py @@ -17,10 +17,11 @@ # along with Pyrogram. If not, see . from struct import pack +from typing import List import pyrogram from pyrogram.api import types -from .photo_size import PhotoSize +from .thumbnail import Thumbnail from ..pyrogram_type import PyrogramType from ...ext.utils import encode @@ -38,9 +39,6 @@ class VideoNote(PyrogramType): duration (``int``): Duration of the video in seconds as defined by sender. - thumb (:obj:`PhotoSize`, *optional*): - Video thumbnail. - mime_type (``str``, *optional*): MIME type of the file as defined by sender. @@ -49,9 +47,12 @@ class VideoNote(PyrogramType): date (``int``, *optional*): Date the video note was sent in Unix time. + + thumbnails (List of :obj:`Thumbnail`, *optional*): + Video thumbnails. """ - __slots__ = ["file_id", "thumb", "mime_type", "file_size", "date", "length", "duration"] + __slots__ = ["file_id", "mime_type", "file_size", "date", "length", "duration", "thumbnails"] def __init__( self, @@ -60,7 +61,7 @@ class VideoNote(PyrogramType): file_id: str, length: int, duration: int, - thumb: PhotoSize = None, + thumbnails: List[Thumbnail] = None, mime_type: str = None, file_size: int = None, date: int = None @@ -68,12 +69,12 @@ class VideoNote(PyrogramType): super().__init__(client) self.file_id = file_id - self.thumb = thumb self.mime_type = mime_type self.file_size = file_size self.date = date self.length = length self.duration = duration + self.thumbnails = thumbnails @staticmethod def _parse(client, video_note: types.Document, video_attributes: types.DocumentAttributeVideo) -> "VideoNote": @@ -89,9 +90,9 @@ class VideoNote(PyrogramType): ), length=video_attributes.w, duration=video_attributes.duration, - thumb=PhotoSize._parse(client, video_note.thumbs), file_size=video_note.size, mime_type=video_note.mime_type, date=video_note.date, + thumbnails=Thumbnail._parse(client, video_note), client=client ) diff --git a/pyrogram/client/types/pyrogram_list.py b/pyrogram/client/types/pyrogram_list.py new file mode 100644 index 00000000..cb802e51 --- /dev/null +++ b/pyrogram/client/types/pyrogram_list.py @@ -0,0 +1,32 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# 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 . + +from .pyrogram_type import PyrogramType + + +class PyrogramList(list): + __slots__ = [] + + def __str__(self): + # noinspection PyCallByClass + return PyrogramType.__str__(self) + + def __repr__(self): + return "pyrogram.client.types.pyrogram_list.PyrogramList([{}])".format( + ",".join(PyrogramType.__repr__(i) for i in self) + ) diff --git a/pyrogram/client/types/pyrogram_type.py b/pyrogram/client/types/pyrogram_type.py index ed50efbc..9a04c636 100644 --- a/pyrogram/client/types/pyrogram_type.py +++ b/pyrogram/client/types/pyrogram_type.py @@ -17,6 +17,7 @@ # along with Pyrogram. If not, see . from collections import OrderedDict +from datetime import datetime from json import dumps import pyrogram @@ -46,9 +47,15 @@ class PyrogramType: try: return OrderedDict( [("_", "pyrogram." + obj.__class__.__name__)] - + [(attr, getattr(obj, attr)) - for attr in obj.__slots__ - if getattr(obj, attr) is not None] + + [ + (attr, "*" * len(getattr(obj, attr))) + if attr == "phone_number" + else (attr, str(datetime.fromtimestamp(getattr(obj, attr)))) + if attr.endswith("date") + else (attr, getattr(obj, attr)) + for attr in obj.__slots__ + if getattr(obj, attr) is not None + ] ) except AttributeError: return repr(obj) diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index 85b29ac6..05fb6d0b 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -35,6 +35,16 @@ class Chat(PyrogramType): type (``str``): Type of chat, can be either "private", "bot", "group", "supergroup" or "channel". + is_verified (``bool``, *optional*): + True, if this chat has been verified by Telegram. Supergroups and channels only. + + is_restricted (``bool``, *optional*): + True, if this chat has been restricted. Supergroups and channels only. + See *restriction_reason* for details. + + is_scam (``bool``, *optional*): + True, if this chat has been flagged for scam. Supergroups and channels only. + title (``str``, *optional*): Title, for supergroups, channels and basic group chats. @@ -47,43 +57,44 @@ class Chat(PyrogramType): last_name (``str``, *optional*): Last name of the other party in a private chat, for private chats. - photo (:obj:`ChatPhoto `, *optional*): + photo (:obj:`ChatPhoto`, *optional*): Chat photo. Suitable for downloads only. description (``str``, *optional*): Bio, for private chats and bots or description for groups, supergroups and channels. - Returned only in :meth:`get_chat() `. + Returned only in :meth:`~Client.get_chat`. invite_link (``str``, *optional*): Chat invite link, for groups, supergroups and channels. - Returned only in :meth:`get_chat() `. + Returned only in :meth:`~Client.get_chat`. pinned_message (:obj:`Message`, *optional*): Pinned message, for groups, supergroups channels and own chat. - Returned only in :meth:`get_chat() `. + Returned only in :meth:`~Client.get_chat`. sticker_set_name (``str``, *optional*): For supergroups, name of group sticker set. - Returned only in :meth:`get_chat() `. + Returned only in :meth:`~Client.get_chat`. can_set_sticker_set (``bool``, *optional*): True, if the group sticker set can be changed by you. - Returned only in :meth:`get_chat() `. + Returned only in :meth:`~Client.get_chat`. 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. + This field is available only in case *is_restricted* is True. - permissions (:obj:`ChatPermissions ` *optional*): + permissions (:obj:`ChatPermissions` *optional*): Information about the chat default permissions, for groups and supergroups. """ __slots__ = [ - "id", "type", "title", "username", "first_name", "last_name", "photo", "description", "invite_link", - "pinned_message", "sticker_set_name", "can_set_sticker_set", "members_count", "restriction_reason", - "permissions" + "id", "type", "is_verified", "is_restricted", "is_scam", "title", "username", "first_name", "last_name", + "photo", "description", "invite_link", "pinned_message", "sticker_set_name", "can_set_sticker_set", + "members_count", "restriction_reason", "permissions" ] def __init__( @@ -92,6 +103,9 @@ class Chat(PyrogramType): client: "pyrogram.BaseClient" = None, id: int, type: str, + is_verified: bool = None, + is_restricted: bool = None, + is_scam: bool = None, title: str = None, username: str = None, first_name: str = None, @@ -110,6 +124,9 @@ class Chat(PyrogramType): self.id = id self.type = type + self.is_verified = is_verified + self.is_restricted = is_restricted + self.is_scam = is_scam self.title = title self.username = username self.first_name = first_name @@ -126,36 +143,45 @@ class Chat(PyrogramType): @staticmethod def _parse_user_chat(client, user: types.User) -> "Chat": + peer_id = user.id + return Chat( - id=user.id, + id=peer_id, type="bot" if user.bot else "private", username=user.username, first_name=user.first_name, last_name=user.last_name, - photo=ChatPhoto._parse(client, user.photo), + photo=ChatPhoto._parse(client, user.photo, peer_id), restriction_reason=user.restriction_reason, client=client ) @staticmethod def _parse_chat_chat(client, chat: types.Chat) -> "Chat": + peer_id = -chat.id + return Chat( - id=-chat.id, + id=peer_id, type="group", title=chat.title, - photo=ChatPhoto._parse(client, getattr(chat, "photo", None)), + photo=ChatPhoto._parse(client, getattr(chat, "photo", None), peer_id), permissions=ChatPermissions._parse(getattr(chat, "default_banned_rights", None)), client=client ) @staticmethod def _parse_channel_chat(client, channel: types.Channel) -> "Chat": + peer_id = int("-100" + str(channel.id)) + return Chat( - id=int("-100" + str(channel.id)), + id=peer_id, type="supergroup" if channel.megagroup else "channel", + is_verified=getattr(channel, "verified", None), + is_restricted=getattr(channel, "restricted", None), + is_scam=getattr(channel, "scam", None), title=channel.title, username=getattr(channel, "username", None), - photo=ChatPhoto._parse(client, getattr(channel, "photo", None)), + photo=ChatPhoto._parse(client, getattr(channel, "photo", None), peer_id), restriction_reason=getattr(channel, "restriction_reason", None), permissions=ChatPermissions._parse(getattr(channel, "default_banned_rights", None)), client=client diff --git a/pyrogram/client/types/user_and_chats/chat_photo.py b/pyrogram/client/types/user_and_chats/chat_photo.py index 08e43138..1885eff2 100644 --- a/pyrogram/client/types/user_and_chats/chat_photo.py +++ b/pyrogram/client/types/user_and_chats/chat_photo.py @@ -50,31 +50,24 @@ class ChatPhoto(PyrogramType): self.big_file_id = big_file_id @staticmethod - def _parse(client, chat_photo: types.UserProfilePhoto or types.ChatPhoto): + def _parse(client, chat_photo: types.UserProfilePhoto or types.ChatPhoto, peer_id: int): if not isinstance(chat_photo, (types.UserProfilePhoto, types.ChatPhoto)): return None - if not isinstance(chat_photo.photo_small, types.FileLocation): - return None - - if not isinstance(chat_photo.photo_big, types.FileLocation): - return None - - photo_id = getattr(chat_photo, "photo_id", 0) loc_small = chat_photo.photo_small loc_big = chat_photo.photo_big return ChatPhoto( small_file_id=encode( pack( - " "Dialog": + def _parse(client, dialog: types.Dialog, messages, users, chats) -> "Dialog": chat_id = dialog.peer if isinstance(chat_id, types.PeerUser): diff --git a/pyrogram/client/types/user_and_chats/dialogs.py b/pyrogram/client/types/user_and_chats/dialogs.py index 915166bf..f5c899bc 100644 --- a/pyrogram/client/types/user_and_chats/dialogs.py +++ b/pyrogram/client/types/user_and_chats/dialogs.py @@ -51,7 +51,7 @@ class Dialogs(PyrogramType): self.dialogs = dialogs @staticmethod - async def _parse(client, dialogs) -> "Dialogs": + async def _parse(client, dialogs: types.messages.Dialogs) -> "Dialogs": users = {i.id: i for i in dialogs.users} chats = {i.id: i for i in dialogs.chats} @@ -72,8 +72,16 @@ class Dialogs(PyrogramType): messages[chat_id] = await Message._parse(client, message, users, chats) + parsed_dialogs = [] + + for dialog in dialogs.dialogs: + if not isinstance(dialog, types.Dialog): + continue + + parsed_dialogs.append(Dialog._parse(client, dialog, messages, users, chats)) + return Dialogs( total_count=getattr(dialogs, "count", len(dialogs.dialogs)), - dialogs=[Dialog._parse(client, dialog, messages, users, chats) for dialog in dialogs.dialogs], + dialogs=parsed_dialogs, client=client ) diff --git a/pyrogram/client/types/user_and_chats/user.py b/pyrogram/client/types/user_and_chats/user.py index 455b4a4d..ae631df1 100644 --- a/pyrogram/client/types/user_and_chats/user.py +++ b/pyrogram/client/types/user_and_chats/user.py @@ -45,6 +45,19 @@ class User(PyrogramType): is_bot (``bool``): True, if this user is a bot. + is_verified (``bool``): + True, if this user has been verified by Telegram. + + is_restricted (``bool``): + True, if this user has been restricted. Bots only. + See *restriction_reason* for details. + + is_support (``bool``): + True, if this user is part of the Telegram support team. + + is_scam (``bool``): + True, if this user has been flagged for scam. + first_name (``str``): User's or bot's first name. @@ -68,11 +81,13 @@ class User(PyrogramType): restriction_reason (``str``, *optional*): The reason why this bot might be unavailable to some users. + This field is available only in case *is_restricted* is True. """ __slots__ = [ - "id", "is_self", "is_contact", "is_mutual_contact", "is_deleted", "is_bot", "first_name", "last_name", "status", - "username", "language_code", "phone_number", "photo", "restriction_reason" + "id", "is_self", "is_contact", "is_mutual_contact", "is_deleted", "is_bot", "is_verified", "is_restricted", + "is_support", "is_scam", "first_name", "last_name", "status", "username", "language_code", "phone_number", + "photo", "restriction_reason" ] def __init__( @@ -85,6 +100,10 @@ class User(PyrogramType): is_mutual_contact: bool, is_deleted: bool, is_bot: bool, + is_verified: bool, + is_restricted: bool, + is_support: bool, + is_scam: bool, first_name: str, last_name: str = None, status: UserStatus = None, @@ -102,6 +121,10 @@ class User(PyrogramType): self.is_mutual_contact = is_mutual_contact self.is_deleted = is_deleted self.is_bot = is_bot + self.is_verified = is_verified + self.is_restricted = is_restricted + self.is_support = is_support + self.is_scam = is_scam self.first_name = first_name self.last_name = last_name self.status = status @@ -123,13 +146,17 @@ class User(PyrogramType): is_mutual_contact=user.mutual_contact, is_deleted=user.deleted, is_bot=user.bot, + is_verified=user.verified, + is_restricted=user.restricted, + is_support=user.support, + is_scam=user.scam, first_name=user.first_name, last_name=user.last_name, status=UserStatus._parse(client, user.status, user.id, user.bot), username=user.username, language_code=user.lang_code, phone_number=user.phone, - photo=ChatPhoto._parse(client, user.photo), + photo=ChatPhoto._parse(client, user.photo, user.id), restriction_reason=user.restriction_reason, client=client ) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 680e05a6..f6617728 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -306,7 +306,8 @@ class Session: # Seconds to wait until middle-overlap, which is # 15 minutes before/after the current/next salt end/start time - dt = (self.current_salt.valid_until - now).total_seconds() - 900 + valid_until = datetime.fromtimestamp(self.current_salt.valid_until) + dt = (valid_until - now).total_seconds() - 900 log.info("Next salt in {:.0f}m {:.0f}s ({})".format( dt // 60, dt % 60,