Merge branch 'develop'
This commit is contained in:
commit
a093024824
17
README.rst
17
README.rst
@ -26,7 +26,7 @@ Features
|
||||
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
|
||||
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
|
||||
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
|
||||
- **Updated** to the latest Telegram API version, currently Layer 81 on top of MTProto 2.0.
|
||||
- **Updated** to the latest Telegram API version, currently Layer 82 on top of MTProto 2.0.
|
||||
- **Documented**: The Pyrogram API is well documented and resembles the Telegram Bot API.
|
||||
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
|
||||
|
||||
@ -78,14 +78,13 @@ Copyright & License
|
||||
|
||||
<h1 align="center">
|
||||
<a href="https://github.com/pyrogram/pyrogram">
|
||||
<div><img src="https://media.pyrogram.ml/images/icon.png" alt="Pyrogram Icon"></div>
|
||||
<div><img src="https://media.pyrogram.ml/images/label.png" alt="Pyrogram Label"></div>
|
||||
<div><img src="https://raw.githubusercontent.com/pyrogram/logos/master/logos/pyrogram_logo2.png" alt="Pyrogram Logo"></div>
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<b>Telegram MTProto API Client Library for Python</b>
|
||||
|
||||
|
||||
<br>
|
||||
<a href="https://github.com/pyrogram/pyrogram/releases/latest">
|
||||
Download
|
||||
@ -100,25 +99,25 @@ Copyright & License
|
||||
</a>
|
||||
<br><br>
|
||||
<a href="compiler/api/source/main_api.tl">
|
||||
<img src="https://img.shields.io/badge/SCHEME-LAYER%2081-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/SCHEME-LAYER%2082-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
alt="Scheme Layer">
|
||||
</a>
|
||||
<a href="https://github.com/pyrogram/tgcrypto">
|
||||
<img src="https://img.shields.io/badge/TGCRYPTO-V1.0.4-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/TGCRYPTO-V1.1.1-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
alt="TgCrypto">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
.. |logo| image:: https://pyrogram.ml/images/logo.png
|
||||
.. |logo| image:: https://raw.githubusercontent.com/pyrogram/logos/master/logos/pyrogram_logo2.png
|
||||
:target: https://pyrogram.ml
|
||||
:alt: Pyrogram
|
||||
|
||||
.. |description| replace:: **Telegram MTProto API Client Library for Python**
|
||||
|
||||
.. |scheme| image:: "https://img.shields.io/badge/SCHEME-LAYER%2081-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
.. |scheme| image:: "https://img.shields.io/badge/SCHEME-LAYER%2082-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
:target: compiler/api/source/main_api.tl
|
||||
:alt: Scheme Layer
|
||||
|
||||
.. |tgcrypto| image:: "https://img.shields.io/badge/TGCRYPTO-V1.0.4-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
.. |tgcrypto| image:: "https://img.shields.io/badge/TGCRYPTO-V1.1.1-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
:target: https://github.com/pyrogram/tgcrypto
|
||||
:alt: TgCrypto
|
||||
|
@ -172,9 +172,8 @@ def start():
|
||||
|
||||
with open("{}/source/auth_key.tl".format(HOME), encoding="utf-8") as auth, \
|
||||
open("{}/source/sys_msgs.tl".format(HOME), encoding="utf-8") as system, \
|
||||
open("{}/source/main_api.tl".format(HOME), encoding="utf-8") as api, \
|
||||
open("{}/source/pyrogram.tl".format(HOME), encoding="utf-8") as pyrogram:
|
||||
schema = (auth.read() + system.read() + api.read() + pyrogram.read()).splitlines()
|
||||
open("{}/source/main_api.tl".format(HOME), encoding="utf-8") as api:
|
||||
schema = (auth.read() + system.read() + api.read()).splitlines()
|
||||
|
||||
with open("{}/template/mtproto.txt".format(HOME), encoding="utf-8") as f:
|
||||
mtproto_template = f.read()
|
||||
@ -494,17 +493,19 @@ def start():
|
||||
f.write("\n 0xb0700015: \"pyrogram.client.types.ChatPhoto\",")
|
||||
f.write("\n 0xb0700016: \"pyrogram.client.types.ChatMember\",")
|
||||
f.write("\n 0xb0700017: \"pyrogram.client.types.Sticker\",")
|
||||
f.write("\n 0xb0700025: \"pyrogram.client.types.GIF\",")
|
||||
f.write("\n 0xb0700018: \"pyrogram.client.types.bots.ForceReply\",")
|
||||
f.write("\n 0xb0700019: \"pyrogram.client.types.bots.InlineKeyboardButton\",")
|
||||
f.write("\n 0xb0700020: \"pyrogram.client.types.bots.InlineKeyboardMarkup\",")
|
||||
f.write("\n 0xb0700021: \"pyrogram.client.types.bots.KeyboardButton\",")
|
||||
f.write("\n 0xb0700022: \"pyrogram.client.types.bots.ReplyKeyboardMarkup\",")
|
||||
f.write("\n 0xb0700023: \"pyrogram.client.types.bots.ReplyKeyboardRemove\",")
|
||||
f.write("\n 0xb0700024: \"pyrogram.client.types.CallbackQuery\",")
|
||||
f.write("\n 0xb0700025: \"pyrogram.client.types.Animation\",")
|
||||
f.write("\n 0xb0700026: \"pyrogram.client.types.Messages\",")
|
||||
|
||||
f.write("\n 0xb0700018: \"pyrogram.client.types.reply_markup.ForceReply\",")
|
||||
f.write("\n 0xb0700019: \"pyrogram.client.types.reply_markup.InlineKeyboardButton\",")
|
||||
f.write("\n 0xb0700020: \"pyrogram.client.types.reply_markup.InlineKeyboardMarkup\",")
|
||||
f.write("\n 0xb0700021: \"pyrogram.client.types.reply_markup.KeyboardButton\",")
|
||||
f.write("\n 0xb0700022: \"pyrogram.client.types.reply_markup.ReplyKeyboardMarkup\",")
|
||||
f.write("\n 0xb0700023: \"pyrogram.client.types.reply_markup.ReplyKeyboardRemove\",")
|
||||
|
||||
f.write("\n 0xb0700024: \"pyrogram.client.types.CallbackQuery\"")
|
||||
f.write("\n 0xb0700027: \"pyrogram.client.types.Photo\",")
|
||||
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")
|
||||
f.write("\n 0xb0700029: \"pyrogram.client.types.Dialogs\",")
|
||||
f.write("\n 0xb0700030: \"pyrogram.client.types.ChatMembers\",")
|
||||
|
||||
f.write("\n}\n")
|
||||
|
||||
|
@ -36,7 +36,7 @@ inputMediaEmpty#9664f57f = InputMedia;
|
||||
inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
|
||||
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
|
||||
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
|
||||
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
|
||||
@ -61,6 +61,7 @@ inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLo
|
||||
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
|
||||
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
|
||||
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
|
||||
inputTakeoutFileLocation#29be5899 = InputFileLocation;
|
||||
|
||||
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
|
||||
|
||||
@ -121,7 +122,7 @@ messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_un
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
|
||||
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
|
||||
messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia;
|
||||
messageMediaUnsupported#9f84f49e = MessageMedia;
|
||||
messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
|
||||
@ -153,7 +154,7 @@ messageActionBotAllowed#abe9affe domain:string = MessageAction;
|
||||
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
|
||||
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
|
||||
|
||||
dialog#e4def5db flags:# pinned:flags.2?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#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;
|
||||
|
||||
photoEmpty#2331b22d id:long = Photo;
|
||||
photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
|
||||
@ -163,7 +164,7 @@ photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = Phot
|
||||
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
|
||||
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#2049d70c long:double lat:double = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
|
||||
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
|
||||
|
||||
@ -213,6 +214,7 @@ contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Ve
|
||||
|
||||
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
|
||||
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
|
||||
messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
|
||||
|
||||
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
@ -309,6 +311,7 @@ updateFavedStickers#e511996d = Update;
|
||||
updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update;
|
||||
updateContactsReset#7084a7be = Update;
|
||||
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
|
||||
updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -335,7 +338,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#eb7bb160 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 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> 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 suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
|
||||
config#3213dbba 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 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> 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 = Config;
|
||||
|
||||
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
|
||||
|
||||
@ -562,7 +565,7 @@ inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?
|
||||
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
|
||||
inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult;
|
||||
@ -574,7 +577,7 @@ botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vecto
|
||||
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
|
||||
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
|
||||
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
|
||||
@ -617,8 +620,9 @@ topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<To
|
||||
|
||||
contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
|
||||
contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
|
||||
contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
|
||||
|
||||
draftMessageEmpty#ba4baec5 = DraftMessage;
|
||||
draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
|
||||
draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
|
||||
|
||||
messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
|
||||
@ -706,14 +710,13 @@ paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string e
|
||||
|
||||
paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials;
|
||||
|
||||
webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> dc_id:int = WebDocument;
|
||||
webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
|
||||
webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
|
||||
|
||||
inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;
|
||||
|
||||
inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
|
||||
inputWebFileGeoPointLocation#66275a62 geo_point:InputGeoPoint w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
inputWebFileGeoMessageLocation#553f32eb peer:InputPeer msg_id:int w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
|
||||
upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
|
||||
|
||||
@ -883,6 +886,10 @@ account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEma
|
||||
help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo;
|
||||
help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo;
|
||||
|
||||
savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact;
|
||||
|
||||
account.takeout#4dba4501 id:long = account.Takeout;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -890,13 +897,14 @@ invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
|
||||
initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
|
||||
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
|
||||
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
|
||||
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
|
||||
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||
|
||||
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
|
||||
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
|
||||
auth.logOut#5717da40 = Bool;
|
||||
auth.resetAuthorizations#9fab0d1a = Bool;
|
||||
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
|
||||
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
|
||||
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
|
||||
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
|
||||
@ -948,6 +956,8 @@ account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_
|
||||
account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
|
||||
account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
|
||||
account.verifyEmail#ecba39db email:string code:string = Bool;
|
||||
account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout;
|
||||
account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@ -968,9 +978,11 @@ 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.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
|
||||
contacts.resetSaved#879537f1 = Bool;
|
||||
contacts.getSaved#82f1e39f = Vector<SavedContact>;
|
||||
contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
|
||||
|
||||
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
|
||||
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
|
||||
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.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;
|
||||
@ -1065,6 +1077,9 @@ messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = message
|
||||
messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates;
|
||||
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
|
||||
messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
|
||||
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
|
||||
messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool;
|
||||
messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@ -1131,6 +1146,7 @@ channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet =
|
||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = 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;
|
||||
|
||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
@ -1161,4 +1177,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangP
|
||||
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
|
||||
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
|
||||
|
||||
// LAYER 81
|
||||
// LAYER 82
|
||||
|
@ -1,22 +0,0 @@
|
||||
// Pyrogram
|
||||
|
||||
---types---
|
||||
|
||||
//pyrogram.update#b0700000 flags:# update_id:int message:flags.0?Message edited_message:flags.1?Message channel_post:flags.2?Message edited_channel_post:flags.3?Message inline_query:flags.4?InlineQuery chosen_inline_result:flags.5?ChosenInlineResult callback_query:flags.6?CallbackQuery shipping_query:flags.7?ShippingQuery pre_checkout_query:flags.8?PreCheckoutQuery = pyrogram.Update;
|
||||
//pyrogram.user#b0700001 flags:# id:int is_bot:Bool first_name:string last_name:flags.0?string username:flags.1?string language_code:flags.2?string phone_number:flags.3?string photo:flags.4?ChatPhoto = pyrogram.User;
|
||||
//pyrogram.chat#b0700002 flags:# id:int type:string title:flags.0?string username:flags.1?string first_name:flags.2?string last_name:flags.3?string all_members_are_administrators:flags.4?Bool photo:flags.5?ChatPhoto description:flags.6?string invite_link:flags.7?string pinned_message:flags.8?Message sticker_set_name:flags.9?string can_set_sticker_set:flags.10?Bool = pyrogram.Chat;
|
||||
//pyrogram.message#b0700003 flags:# message_id:int from_user:flags.0?User date:int chat:Chat forward_from:flags.1?User forward_from_chat:flags.2?Chat forward_from_message_id:flags.3?int forward_signature:flags.4?string forward_date:flags.5?int reply_to_message:flags.6?Message edit_date:flags.7?int media_group_id:flags.8?string author_signature:flags.9?string text:flags.10?string entities:flags.11?Vector<MessageEntity> caption_entities:flags.12?Vector<MessageEntity> audio:flags.13?Audio document:flags.14?Document game:flags.15?Game photo:flags.16?Vector<PhotoSize> sticker:flags.17?Sticker video:flags.18?Video voice:flags.19?Voice video_note:flags.20?VideoNote caption:flags.21?string contact:flags.22?Contact location:flags.23?Location venue:flags.24?Venue new_chat_members:flags.25?Vector<User> left_chat_member:flags.26?User new_chat_title:flags.27?string new_chat_photo:flags.28?Vector<PhotoSize> delete_chat_photo:flags.29?true group_chat_created:flags.30?true supergroup_chat_created:flags.31?true channel_chat_created:flags.32?true migrate_to_chat_id:flags.33?int migrate_from_chat_id:flags.34?int pinned_message:flags.35?Message invoice:flags.36?Invoice successful_payment:flags.37?SuccessfulPayment connected_website:flags.38?string views:flags.39?int via_bot:flags.40?User = pyrogram.Message;
|
||||
//pyrogram.messageEntity#b0700004 flags:# type:string offset:int length:int url:flags.0?string user:flags.1?User = pyrogram.MessageEntity;
|
||||
//pyrogram.photoSize#b0700005 flags:# file_id:string file_size:flags.0?int date:flags.1?int width:int height:int = pyrogram.PhotoSize;
|
||||
//pyrogram.audio#b0700006 flags:# file_id:string thumb:flags.0?PhotoSize file_name:flags.1?string mime_type:flags.2?string file_size:flags.3?int date:flags.4?int duration:int performer:flags.5?string title:flags.6?string = pyrogram.Audio;
|
||||
//pyrogram.document#b0700007 flags:# file_id:string thumb:flags.0?PhotoSize file_name:flags.1?string mime_type:flags.2?string file_size:flags.3?int date:flags.4?int = pyrogram.Document;
|
||||
//pyrogram.video#b0700008 flags:# file_id:string thumb:flags.0?PhotoSize file_name:flags.1?string mime_type:flags.2?string file_size:flags.3?int date:flags.4?int width:int height:int duration:int = pyrogram.Video;
|
||||
//pyrogram.voice#b0700009 flags:# file_id:string thumb:flags.0?PhotoSize file_name:flags.1?string mime_type:flags.2?string file_size:flags.3?int date:flags.4?int duration:int = pyrogram.Voice;
|
||||
//pyrogram.videoNote#b0700010 flags:# file_id:string thumb:flags.0?PhotoSize file_name:flags.1?string mime_type:flags.2?string file_size:flags.3?int date:flags.4?int length:int duration:int = pyrogram.VideoNote;
|
||||
//pyrogram.contact#b0700011 flags:# phone_number:string first_name:string last_name:flags.0?string user_id:flags.1?int = pyrogram.Contact;
|
||||
//pyrogram.location#b0700012 longitude:double latitude:double = pyrogram.Location;
|
||||
//pyrogram.venue#b0700013 flags:# location:Location title:string address:string foursquare_id:flags.0?string = pyrogram.Venue;
|
||||
//pyrogram.userProfilePhotos#b0700014 total_count:int photos:Vector<Vector<PhotoSize>> = pyrogram.UserProfilePhotos;
|
||||
//pyrogram.chatPhoto#b0700015 small_file_id:string big_file_id:string = pyrogram.ChatPhoto;
|
||||
//pyrogram.chatMember#b0700016 flags:# user:User status:string until_date:flags.0?int can_be_edited:flags.1?Bool can_change_info:flags.2?Bool can_post_messages:flags.3?Bool can_edit_messages:flags.4?Bool can_delete_messages:flags.5?Bool can_invite_users:flags.6?Bool can_restrict_members:flags.7?Bool can_pin_messages:flags.8?Bool can_promote_members:flags.9?Bool can_send_messages:flags.10?Bool can_send_media_messages:flags.11?Bool can_send_other_messages:flags.12?Bool can_add_web_page_previews:flags.13?Bool = pyrogram.ChatMember;
|
||||
//pyrogram.sticker#b0700017 flags:# file_id:string thumb:flags.0?PhotoSize file_name:flags.1?string mime_type:flags.2?string file_size:flags.3?int date:flags.4?int width:int height:int emoji:flags.5?string set_name:flags.6?string mask_position:flags.7?MaskPosition = pyrogram.Sticker;
|
@ -62,4 +62,8 @@ USER_IS_BOT A bot cannot send messages to other bots or to itself
|
||||
WEBPAGE_CURL_FAILED Telegram could not fetch the provided URL
|
||||
STICKERSET_INVALID The requested sticker set is invalid
|
||||
PEER_FLOOD The method can't be used because your account is limited
|
||||
MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters
|
||||
MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters
|
||||
USER_NOT_MUTUAL_CONTACT The user is not a mutual contact
|
||||
USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups
|
||||
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
|
||||
USER_NOT_PARTICIPANT The user is not a member of this chat
|
|
2
compiler/error/source/403_FORBIDDEN.tsv
Normal file
2
compiler/error/source/403_FORBIDDEN.tsv
Normal file
@ -0,0 +1,2 @@
|
||||
id message
|
||||
CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat
|
|
2
compiler/error/source/406_NOT_ACCEPTABLE.tsv
Normal file
2
compiler/error/source/406_NOT_ACCEPTABLE.tsv
Normal file
@ -0,0 +1,2 @@
|
||||
id message
|
||||
AUTH_KEY_DUPLICATED Authorization error. You must log out and log in again with your phone number. We apologize for the inconvenience.
|
|
@ -3,4 +3,5 @@ AUTH_RESTART User authorization has restarted
|
||||
RPC_CALL_FAIL Telegram is having internal problems. Please try again later
|
||||
RPC_MCGET_FAIL Telegram is having internal problems. Please try again later
|
||||
PERSISTENT_TIMESTAMP_OUTDATED Telegram is having internal problems. Please try again later
|
||||
HISTORY_GET_FAILED Telegram is having internal problems. Please try again later
|
||||
HISTORY_GET_FAILED Telegram is having internal problems. Please try again later
|
||||
REG_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later
|
|
@ -3,7 +3,7 @@
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = ~/PycharmProjects/pyrogram/venv3.6/bin/sphinx-build
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = Pyrogram
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
@ -1,20 +0,0 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = Pyrogram
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@ -5,8 +5,7 @@ Welcome to Pyrogram
|
||||
|
||||
<div align="center">
|
||||
<a href="https://docs.pyrogram.ml">
|
||||
<div><img src="https://media.pyrogram.ml/images/icon.png" alt="Pyrogram Icon"></div>
|
||||
<div><img src="https://media.pyrogram.ml/images/label.png" alt="Pyrogram Label"></div>
|
||||
<div><img src="_static/logo.png" alt="Pyrogram Logo"></div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -26,11 +25,11 @@ Welcome to Pyrogram
|
||||
</a>
|
||||
<br><br>
|
||||
<a href="https://github.com/pyrogram/pyrogram/blob/master/compiler/api/source/main_api.tl">
|
||||
<img src="https://img.shields.io/badge/SCHEME-LAYER%2081-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/SCHEME-LAYER%2082-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
alt="Scheme Layer">
|
||||
</a>
|
||||
<a href="https://github.com/pyrogram/tgcrypto">
|
||||
<img src="https://img.shields.io/badge/TGCRYPTO-V1.0.4-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/TGCRYPTO-V1.1.1-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
alt="TgCrypto">
|
||||
</a>
|
||||
</p>
|
||||
@ -84,6 +83,7 @@ To get started, press the Next button.
|
||||
:caption: Resources
|
||||
|
||||
resources/UpdateHandling
|
||||
resources/UsingFilters
|
||||
resources/AutoAuthorization
|
||||
resources/CustomizeSessions
|
||||
resources/TgCrypto
|
||||
|
@ -1,68 +1,135 @@
|
||||
Client
|
||||
======
|
||||
|
||||
.. currentmodule:::: pyrogram.Client
|
||||
.. currentmodule:: pyrogram.Client
|
||||
|
||||
.. autoclass:: pyrogram.Client
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
start
|
||||
stop
|
||||
idle
|
||||
run
|
||||
add_handler
|
||||
remove_handler
|
||||
send
|
||||
resolve_peer
|
||||
download_media
|
||||
|
||||
Decorators
|
||||
----------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
on_message
|
||||
on_callback_query
|
||||
on_deleted_messages
|
||||
on_disconnect
|
||||
on_raw_update
|
||||
|
||||
Messages
|
||||
--------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
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_chat_action
|
||||
edit_message_text
|
||||
edit_message_caption
|
||||
edit_message_reply_markup
|
||||
edit_message_media
|
||||
delete_messages
|
||||
get_messages
|
||||
get_history
|
||||
|
||||
Chats
|
||||
-----
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
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
|
||||
get_dialogs
|
||||
|
||||
Users
|
||||
-----
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
get_me
|
||||
get_users
|
||||
get_user_profile_photos
|
||||
delete_profile_photos
|
||||
|
||||
Contacts
|
||||
--------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
add_contacts
|
||||
get_contacts
|
||||
delete_contacts
|
||||
|
||||
Password
|
||||
--------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
enable_cloud_password
|
||||
change_cloud_password
|
||||
remove_cloud_password
|
||||
|
||||
Bots
|
||||
----
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
get_inline_bot_results
|
||||
send_inline_bot_result
|
||||
answer_callback_query
|
||||
request_callback_answer
|
||||
|
||||
|
||||
.. autoclass:: pyrogram.Client
|
||||
:inherited-members:
|
||||
:members:
|
||||
|
||||
.. _available-methods:
|
||||
|
||||
**Available methods**
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
start
|
||||
stop
|
||||
idle
|
||||
run
|
||||
on_message
|
||||
on_callback_query
|
||||
on_raw_update
|
||||
add_handler
|
||||
remove_handler
|
||||
send
|
||||
resolve_peer
|
||||
get_me
|
||||
send_message
|
||||
forward_messages
|
||||
send_photo
|
||||
send_audio
|
||||
send_document
|
||||
send_sticker
|
||||
send_video
|
||||
send_voice
|
||||
send_video_note
|
||||
send_media_group
|
||||
send_location
|
||||
send_venue
|
||||
send_contact
|
||||
send_chat_action
|
||||
download_media
|
||||
get_user_profile_photos
|
||||
edit_message_text
|
||||
edit_message_caption
|
||||
edit_message_reply_markup
|
||||
delete_messages
|
||||
join_chat
|
||||
leave_chat
|
||||
export_chat_invite_link
|
||||
enable_cloud_password
|
||||
change_cloud_password
|
||||
remove_cloud_password
|
||||
kick_chat_member
|
||||
unban_chat_member
|
||||
restrict_chat_member
|
||||
promote_chat_member
|
||||
add_contacts
|
||||
get_contacts
|
||||
delete_contacts
|
||||
get_inline_bot_results
|
||||
send_inline_bot_result
|
||||
answer_callback_query
|
||||
get_users
|
||||
get_chat
|
||||
get_messages
|
||||
get_history
|
@ -1,5 +1,3 @@
|
||||
:tocdepth: 1
|
||||
|
||||
Error
|
||||
=====
|
||||
|
||||
|
29
docs/source/pyrogram/Handlers.rst
Normal file
29
docs/source/pyrogram/Handlers.rst
Normal file
@ -0,0 +1,29 @@
|
||||
Handlers
|
||||
========
|
||||
|
||||
.. currentmodule:: pyrogram
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
MessageHandler
|
||||
DeletedMessagesHandler
|
||||
CallbackQueryHandler
|
||||
DisconnectHandler
|
||||
RawUpdateHandler
|
||||
|
||||
.. autoclass:: MessageHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: DeletedMessagesHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: CallbackQueryHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: DisconnectHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: RawUpdateHandler
|
||||
:members:
|
||||
|
188
docs/source/pyrogram/Types.rst
Normal file
188
docs/source/pyrogram/Types.rst
Normal file
@ -0,0 +1,188 @@
|
||||
Types
|
||||
=====
|
||||
|
||||
.. currentmodule:: pyrogram
|
||||
|
||||
Users & Chats
|
||||
-------------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
User
|
||||
Chat
|
||||
ChatPhoto
|
||||
ChatMember
|
||||
ChatMembers
|
||||
Dialog
|
||||
Dialogs
|
||||
|
||||
Messages & Media
|
||||
----------------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
Message
|
||||
Messages
|
||||
MessageEntity
|
||||
Photo
|
||||
PhotoSize
|
||||
UserProfilePhotos
|
||||
Audio
|
||||
Document
|
||||
Animation
|
||||
Video
|
||||
Voice
|
||||
VideoNote
|
||||
Contact
|
||||
Location
|
||||
Venue
|
||||
Sticker
|
||||
|
||||
Bots
|
||||
----
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
ReplyKeyboardMarkup
|
||||
KeyboardButton
|
||||
ReplyKeyboardRemove
|
||||
InlineKeyboardMarkup
|
||||
InlineKeyboardButton
|
||||
ForceReply
|
||||
CallbackQuery
|
||||
|
||||
Input Media
|
||||
-----------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
InputMediaPhoto
|
||||
InputMediaVideo
|
||||
InputMediaAudio
|
||||
InputMediaAnimation
|
||||
InputMediaDocument
|
||||
InputPhoneContact
|
||||
|
||||
.. User & Chats
|
||||
------------
|
||||
|
||||
.. autoclass:: User
|
||||
:members:
|
||||
|
||||
.. autoclass:: Chat
|
||||
:members:
|
||||
|
||||
.. autoclass:: ChatPhoto
|
||||
:members:
|
||||
|
||||
.. autoclass:: ChatMember
|
||||
:members:
|
||||
|
||||
.. autoclass:: ChatMembers
|
||||
:members:
|
||||
|
||||
.. autoclass:: Dialog
|
||||
:members:
|
||||
|
||||
.. autoclass:: Dialogs
|
||||
:members:
|
||||
|
||||
.. Messages & Media
|
||||
----------------
|
||||
|
||||
.. autoclass:: Message
|
||||
:members:
|
||||
|
||||
.. autoclass:: Messages
|
||||
:members:
|
||||
|
||||
.. autoclass:: MessageEntity
|
||||
:members:
|
||||
|
||||
.. autoclass:: Photo
|
||||
:members:
|
||||
|
||||
.. autoclass:: PhotoSize
|
||||
:members:
|
||||
|
||||
.. autoclass:: UserProfilePhotos
|
||||
:members:
|
||||
|
||||
.. autoclass:: Audio
|
||||
:members:
|
||||
|
||||
.. autoclass:: Document
|
||||
:members:
|
||||
|
||||
.. autoclass:: Animation
|
||||
:members:
|
||||
|
||||
.. autoclass:: Video
|
||||
:members:
|
||||
|
||||
.. autoclass:: Voice
|
||||
:members:
|
||||
|
||||
.. autoclass:: VideoNote
|
||||
:members:
|
||||
|
||||
.. autoclass:: Contact
|
||||
:members:
|
||||
|
||||
.. autoclass:: Location
|
||||
:members:
|
||||
|
||||
.. autoclass:: Venue
|
||||
:members:
|
||||
|
||||
.. autoclass:: Sticker
|
||||
:members:
|
||||
|
||||
.. Bots
|
||||
----
|
||||
|
||||
.. autoclass:: ReplyKeyboardMarkup
|
||||
:members:
|
||||
|
||||
.. autoclass:: KeyboardButton
|
||||
:members:
|
||||
|
||||
.. autoclass:: ReplyKeyboardRemove
|
||||
:members:
|
||||
|
||||
.. autoclass:: InlineKeyboardMarkup
|
||||
:members:
|
||||
|
||||
.. autoclass:: InlineKeyboardButton
|
||||
:members:
|
||||
|
||||
.. autoclass:: ForceReply
|
||||
:members:
|
||||
|
||||
.. autoclass:: CallbackQuery
|
||||
:members:
|
||||
|
||||
.. Input Media
|
||||
-----------
|
||||
|
||||
.. autoclass:: InputMediaPhoto
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputMediaVideo
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputMediaAudio
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputMediaAnimation
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputMediaDocument
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputPhoneContact
|
||||
:members:
|
@ -1,6 +0,0 @@
|
||||
CallbackQueryHandler
|
||||
====================
|
||||
|
||||
.. autoclass:: pyrogram.CallbackQueryHandler
|
||||
:members:
|
||||
:undoc-members:
|
@ -1,6 +0,0 @@
|
||||
DeletedMessagesHandler
|
||||
======================
|
||||
|
||||
.. autoclass:: pyrogram.DeletedMessagesHandler
|
||||
:members:
|
||||
:undoc-members:
|
@ -1,6 +0,0 @@
|
||||
DisconnectHandler
|
||||
=================
|
||||
|
||||
.. autoclass:: pyrogram.DisconnectHandler
|
||||
:members:
|
||||
:undoc-members:
|
@ -1,6 +0,0 @@
|
||||
MessageHandler
|
||||
==============
|
||||
|
||||
.. autoclass:: pyrogram.MessageHandler
|
||||
:members:
|
||||
:undoc-members:
|
@ -1,6 +0,0 @@
|
||||
RawUpdateHandler
|
||||
================
|
||||
|
||||
.. autoclass:: pyrogram.RawUpdateHandler
|
||||
:members:
|
||||
:undoc-members:
|
@ -1,11 +0,0 @@
|
||||
:tocdepth: 1
|
||||
|
||||
Handlers
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
MessageHandler
|
||||
DeletedMessagesHandler
|
||||
CallbackQueryHandler
|
||||
DisconnectHandler
|
||||
RawUpdateHandler
|
@ -7,9 +7,11 @@ In this section you can find a detailed description of the Pyrogram package and
|
||||
after the well established `Telegram Bot API`_ methods, thus offering a familiar look to Bot developers.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Client
|
||||
types/index
|
||||
handlers/index
|
||||
Types
|
||||
Handlers
|
||||
Filters
|
||||
ChatAction
|
||||
ParseMode
|
||||
|
@ -1,5 +0,0 @@
|
||||
Audio
|
||||
=====
|
||||
|
||||
.. autoclass:: pyrogram.Audio
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
CallbackQuery
|
||||
=============
|
||||
|
||||
.. autoclass:: pyrogram.CallbackQuery
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Chat
|
||||
====
|
||||
|
||||
.. autoclass:: pyrogram.Chat
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
ChatMember
|
||||
==========
|
||||
|
||||
.. autoclass:: pyrogram.ChatMember
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
ChatPhoto
|
||||
=========
|
||||
|
||||
.. autoclass:: pyrogram.ChatPhoto
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Contact
|
||||
=======
|
||||
|
||||
.. autoclass:: pyrogram.Contact
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Document
|
||||
========
|
||||
|
||||
.. autoclass:: pyrogram.Document
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
GIF
|
||||
===
|
||||
|
||||
.. autoclass:: pyrogram.GIF
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
InputMediaPhoto
|
||||
===============
|
||||
|
||||
.. autoclass:: pyrogram.InputMediaPhoto
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
InputMediaVideo
|
||||
===============
|
||||
|
||||
.. autoclass:: pyrogram.InputMediaVideo
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
InputPhoneContact
|
||||
=================
|
||||
|
||||
.. autoclass:: pyrogram.InputPhoneContact
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Location
|
||||
========
|
||||
|
||||
.. autoclass:: pyrogram.Location
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Message
|
||||
=======
|
||||
|
||||
.. autoclass:: pyrogram.Message
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
MessageEntity
|
||||
=============
|
||||
|
||||
.. autoclass:: pyrogram.MessageEntity
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Messages
|
||||
========
|
||||
|
||||
.. autoclass:: pyrogram.Messages
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
PhotoSize
|
||||
=========
|
||||
|
||||
.. autoclass:: pyrogram.PhotoSize
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Sticker
|
||||
=======
|
||||
|
||||
.. autoclass:: pyrogram.Sticker
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Update
|
||||
======
|
||||
|
||||
.. autoclass:: pyrogram.Update
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
User
|
||||
====
|
||||
|
||||
.. autoclass:: pyrogram.User
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
UserProfilePhotos
|
||||
=================
|
||||
|
||||
.. autoclass:: pyrogram.UserProfilePhotos
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Venue
|
||||
=====
|
||||
|
||||
.. autoclass:: pyrogram.Venue
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Video
|
||||
=====
|
||||
|
||||
.. autoclass:: pyrogram.Video
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
VideoNote
|
||||
=========
|
||||
|
||||
.. autoclass:: pyrogram.VideoNote
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
Voice
|
||||
=====
|
||||
|
||||
.. autoclass:: pyrogram.Voice
|
||||
:members:
|
@ -1,35 +0,0 @@
|
||||
:tocdepth: 1
|
||||
|
||||
Types
|
||||
=====
|
||||
|
||||
.. toctree::
|
||||
User
|
||||
Chat
|
||||
Message
|
||||
MessageEntity
|
||||
Messages
|
||||
PhotoSize
|
||||
Audio
|
||||
Document
|
||||
GIF
|
||||
Video
|
||||
Voice
|
||||
VideoNote
|
||||
Contact
|
||||
Location
|
||||
Venue
|
||||
UserProfilePhotos
|
||||
ChatPhoto
|
||||
ChatMember
|
||||
InputMediaPhoto
|
||||
InputMediaVideo
|
||||
InputPhoneContact
|
||||
Sticker
|
||||
reply_markup/ForceReply
|
||||
reply_markup/InlineKeyboardButton
|
||||
reply_markup/InlineKeyboardMarkup
|
||||
reply_markup/KeyboardButton
|
||||
reply_markup/ReplyKeyboardMarkup
|
||||
reply_markup/ReplyKeyboardRemove
|
||||
CallbackQuery
|
@ -1,5 +0,0 @@
|
||||
ForceReply
|
||||
==========
|
||||
|
||||
.. autoclass:: pyrogram.ForceReply
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
InlineKeyboardButton
|
||||
====================
|
||||
|
||||
.. autoclass:: pyrogram.InlineKeyboardButton
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
InlineKeyboardMarkup
|
||||
====================
|
||||
|
||||
.. autoclass:: pyrogram.InlineKeyboardMarkup
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
KeyboardButton
|
||||
==============
|
||||
|
||||
.. autoclass:: pyrogram.KeyboardButton
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
ReplyKeyboardMarkup
|
||||
===================
|
||||
|
||||
.. autoclass:: pyrogram.ReplyKeyboardMarkup
|
||||
:members:
|
@ -1,5 +0,0 @@
|
||||
ReplyKeyboardRemove
|
||||
===================
|
||||
|
||||
.. autoclass:: pyrogram.ReplyKeyboardRemove
|
||||
:members:
|
@ -1,8 +1,11 @@
|
||||
Text Formatting
|
||||
===============
|
||||
|
||||
Pyrogram, just like `Telegram Bot API`_, supports basic Markdown and HTML formatting styles for text messages and
|
||||
media captions; Markdown uses the same syntax as Telegram Desktop's and is enabled by default.
|
||||
Pyrogram, just like the `Telegram Bot API`_, natively supports basic Markdown and HTML formatting styles for text
|
||||
messages and media captions.
|
||||
|
||||
Markdown style uses the same syntax as Telegram Desktop's and is enabled by default.
|
||||
|
||||
Beside bold, italic, and pre-formatted code, **Pyrogram does also support inline URLs and inline mentions of users**.
|
||||
|
||||
Markdown Style
|
||||
@ -11,7 +14,7 @@ Markdown Style
|
||||
To use this mode, pass :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or "markdown" in the *parse_mode* field when using
|
||||
:obj:`send_message() <pyrogram.Client.send_message>`. Use the following syntax in your message:
|
||||
|
||||
.. code-block:: txt
|
||||
.. code-block:: text
|
||||
|
||||
**bold text**
|
||||
|
||||
@ -34,7 +37,7 @@ HTML Style
|
||||
To use this mode, pass :obj:`HTML <pyrogram.ParseMode.HTML>` or "html" in the *parse_mode* field when using
|
||||
:obj:`send_message() <pyrogram.Client.send_message>`. The following tags are currently supported:
|
||||
|
||||
.. code-block:: txt
|
||||
.. code-block:: text
|
||||
|
||||
<b>bold</b>, <strong>bold</strong>
|
||||
|
||||
@ -46,9 +49,7 @@ To use this mode, pass :obj:`HTML <pyrogram.ParseMode.HTML>` or "html" in the *p
|
||||
|
||||
<code>inline fixed-width code</code>
|
||||
|
||||
<pre>pre-formatted fixed-width
|
||||
code block
|
||||
</pre>
|
||||
<pre>pre-formatted fixed-width code block</pre>
|
||||
|
||||
.. note:: Mentions are only guaranteed to work if you have already met the user (in groups or private chats).
|
||||
|
||||
|
@ -2,188 +2,58 @@ Update Handling
|
||||
===============
|
||||
|
||||
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
|
||||
and are handled by registering one or more callback functions with an Handler. There are multiple Handlers to choose
|
||||
from, one for each kind of update:
|
||||
and can be handled by registering one or more callback functions in your app by using an `Handler <../pyrogram/Handlers.html>`_.
|
||||
|
||||
- `MessageHandler <../pyrogram/handlers/MessageHandler.html>`_
|
||||
- `DeletedMessagesHandler <../pyrogram/handlers/DeletedMessagesHandler.html>`_
|
||||
- `CallbackQueryHandler <../pyrogram/handlers/CallbackQueryHandler.html>`_
|
||||
- `RawUpdateHandler <../pyrogram/handlers/RawUpdateHandler.html>`_
|
||||
- `DisconnectHandler <../pyrogram/handlers/DisconnectHandler.html>`_
|
||||
To put it simply, whenever an update is received from Telegram it will be dispatched and your previously defined callback
|
||||
function(s) will be called back with the update itself as argument.
|
||||
|
||||
Registering an Handler
|
||||
----------------------
|
||||
|
||||
We shall examine the :obj:`MessageHandler <pyrogram.MessageHandler>`, which will be in charge for handling
|
||||
:obj:`Message <pyrogram.Message>` objects.
|
||||
|
||||
- The easiest and nicest way to register a MessageHandler is by decorating your function with the
|
||||
:meth:`on_message() <pyrogram.Client.on_message>` decorator. Here's a full example that prints out the content
|
||||
of a message as soon as it arrives.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
To explain how `Handlers <../pyrogram/Handlers.html>`_ work let's have a look at the most used one, the
|
||||
:obj:`MessageHandler <pyrogram.MessageHandler>`, which will be in charge for handling :obj:`Message <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.
|
||||
|
||||
|
||||
@app.on_message()
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app.run()
|
||||
|
||||
- If you prefer not to use decorators, there is an alternative way for registering Handlers.
|
||||
This is useful, for example, when you want to keep your callback functions in separate files.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, MessageHandler
|
||||
|
||||
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
app.add_handler(MessageHandler(my_handler))
|
||||
|
||||
app.run()
|
||||
|
||||
Using Filters
|
||||
-------------
|
||||
|
||||
For a finer grained control over what kind of messages will be allowed or not in your callback functions, you can use
|
||||
:class:`Filters <pyrogram.Filters>`.
|
||||
|
||||
- This example will show you how to **only** handle messages containing an
|
||||
:obj:`Audio <pyrogram.Audio>` object and filter out any other message:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Filters
|
||||
|
||||
|
||||
@app.on_message(Filters.audio)
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- or, without decorators:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Filters, MessageHandler
|
||||
|
||||
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app.add_handler(MessageHandler(my_handler, Filters.audio))
|
||||
|
||||
Combining Filters
|
||||
-----------------
|
||||
|
||||
Filters can also be used in a more advanced way by combining more filters together using bitwise operators:
|
||||
|
||||
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
|
||||
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- Message is a **text** message **and** is **not edited**.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text & ~Filters.edited)
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- Message is a **sticker** **and** is coming from a **channel or** a **private** chat.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.sticker & (Filters.channel | Filters.private))
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
Advanced Filters
|
||||
Using Decorators
|
||||
----------------
|
||||
|
||||
Some filters, like :obj:`command() <pyrogram.Filters.command>` or :obj:`regex() <pyrogram.Filters.regex>`
|
||||
can also accept arguments:
|
||||
|
||||
- Message is either a */start* or */help* **command**.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.command(["start", "help"]))
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- Message is a **text** message matching the given **regex** pattern.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.regex("pyrogram"))
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
More handlers using different filters can also live together.
|
||||
The easiest and nicest way to register a MessageHandler is by decorating your function with the
|
||||
:meth:`on_message() <pyrogram.Client.on_message>` decorator. Here's a full example that prints out the content
|
||||
of a message as soon as it arrives.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.command("start"))
|
||||
def start_command(client, message):
|
||||
print("This is the /start command")
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message(Filters.command("help"))
|
||||
def help_command(client, message):
|
||||
print("This is the /help command")
|
||||
@app.on_message()
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
@app.on_message(Filters.chat("PyrogramChat"))
|
||||
def from_pyrogramchat(client, message):
|
||||
print("New message in @PyrogramChat")
|
||||
app.run()
|
||||
|
||||
Handler Groups
|
||||
--------------
|
||||
Using add_handler()
|
||||
-------------------
|
||||
|
||||
If you register handlers with overlapping filters, only the first one is executed and any other handler will be ignored.
|
||||
|
||||
In order to process the same message more than once, you can register your handler in a different group.
|
||||
Groups are identified by a number (number 0 being the default) and are sorted. This means that a lower group number has
|
||||
a higher priority.
|
||||
|
||||
For example, in:
|
||||
If you prefer not to use decorators for any reason, there is an alternative way for registering Handlers.
|
||||
This is useful, for example, when you want to keep your callback functions in separate files.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text | Filters.sticker)
|
||||
def text_or_sticker(client, message):
|
||||
print("Text or Sticker")
|
||||
from pyrogram import Client, MessageHandler
|
||||
|
||||
|
||||
@app.on_message(Filters.text)
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
``just_text`` is never executed. To enable it, simply register the function using a different group:
|
||||
|
||||
.. code-block:: python
|
||||
app = Client("my_account")
|
||||
|
||||
@app.on_message(Filters.text, group=1)
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
app.add_handler(MessageHandler(my_handler))
|
||||
|
||||
or, if you want ``just_text`` to be fired *before* ``text_or_sticker``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text, group=-1)
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
app.run()
|
||||
|
228
docs/source/resources/UsingFilters.rst
Normal file
228
docs/source/resources/UsingFilters.rst
Normal file
@ -0,0 +1,228 @@
|
||||
Using Filters
|
||||
=============
|
||||
|
||||
For a finer grained control over what kind of messages will be allowed or not in your callback functions, you can use
|
||||
:class:`Filters <pyrogram.Filters>`.
|
||||
|
||||
.. note::
|
||||
This section makes use of Handlers to handle updates. Learn more at `Update Handling <UpdateHandling.html>`_.
|
||||
|
||||
- This example will show you how to **only** handle messages containing an :obj:`Audio <pyrogram.Audio>` object and
|
||||
ignore any other message:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Filters
|
||||
|
||||
|
||||
@app.on_message(Filters.audio)
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- or, without decorators:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Filters, MessageHandler
|
||||
|
||||
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app.add_handler(MessageHandler(my_handler, Filters.audio))
|
||||
|
||||
Combining Filters
|
||||
-----------------
|
||||
|
||||
Filters can also be used in a more advanced way by inverting and combining more filters together using bitwise
|
||||
operators:
|
||||
|
||||
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
|
||||
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- Message is a **text** message **and** is **not edited**.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text & ~Filters.edited)
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- Message is a **sticker** **and** is coming from a **channel or** a **private** chat.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.sticker & (Filters.channel | Filters.private))
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
Advanced Filters
|
||||
----------------
|
||||
|
||||
Some filters, like :meth:`command() <pyrogram.Filters.command>` or :meth:`regex() <pyrogram.Filters.regex>`
|
||||
can also accept arguments:
|
||||
|
||||
- Message is either a */start* or */help* **command**.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.command(["start", "help"]))
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- Message is a **text** message matching the given **regex** pattern.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.regex("pyrogram"))
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
More handlers using different filters can also live together.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.command("start"))
|
||||
def start_command(client, message):
|
||||
print("This is the /start command")
|
||||
|
||||
|
||||
@app.on_message(Filters.command("help"))
|
||||
def help_command(client, message):
|
||||
print("This is the /help command")
|
||||
|
||||
|
||||
@app.on_message(Filters.chat("PyrogramChat"))
|
||||
def from_pyrogramchat(client, message):
|
||||
print("New message in @PyrogramChat")
|
||||
|
||||
Handler Groups
|
||||
--------------
|
||||
|
||||
If you register handlers with overlapping filters, only the first one is executed and any other handler will be ignored.
|
||||
|
||||
In order to process the same message more than once, you can register your handler in a different group.
|
||||
Groups are identified by a number (number 0 being the default) and are sorted. This means that a lower group number has
|
||||
a higher priority.
|
||||
|
||||
For example, in:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text | Filters.sticker)
|
||||
def text_or_sticker(client, message):
|
||||
print("Text or Sticker")
|
||||
|
||||
|
||||
@app.on_message(Filters.text)
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
``just_text`` is never executed because ``text_or_sticker`` already handles texts. To enable it, simply register the
|
||||
function using a different group:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text, group=1)
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
or, if you want ``just_text`` to be fired *before* ``text_or_sticker`` (note ``-1``, which is less than ``0``):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.text, group=-1)
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
Custom Filters
|
||||
--------------
|
||||
|
||||
Pyrogram already provides lots of built-in :class:`Filters <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 handler, for
|
||||
example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
|
||||
|
||||
.. note::
|
||||
At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`
|
||||
only.
|
||||
|
||||
An example to demonstrate how custom filters work is to show how to create and use one for the
|
||||
:obj:`CallbackQueryHandler <pyrogram.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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton
|
||||
|
||||
app.send_message(
|
||||
"username", # Change this to your username or id
|
||||
"Pyrogram's custom filter test",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton("Press me", "pyrogram")]]
|
||||
)
|
||||
)
|
||||
|
||||
Basic Filters
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
For this basic filter we will be using only the first two parameters of :meth:`Filters.create() <pyrogram.Filters.create>`.
|
||||
|
||||
The code below creates a simple filter for hardcoded callback data. This filter will only allow callback queries
|
||||
containing "pyrogram" as data:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
hardcoded_data = Filters.create(
|
||||
name="HardcodedData",
|
||||
func=lambda filter, callback_query: callback_query.data == "pyrogram"
|
||||
)
|
||||
|
||||
The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example, the same
|
||||
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter itself:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def func(filter, callback_query):
|
||||
return callback_query.data == "pyrogram"
|
||||
|
||||
hardcoded_data = Filters.create(
|
||||
name="HardcodedData",
|
||||
func=func
|
||||
)
|
||||
|
||||
The filter usage remains the same:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_callback_query(hardcoded_data)
|
||||
def pyrogram_data(client, callback_query):
|
||||
client.answer_callback_query(callback_query.id, "it works!")
|
||||
|
||||
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() <pyrogram.Filters.create>`.
|
||||
|
||||
This is how a dynamic custom filter looks like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def dynamic_data(data):
|
||||
return Filters.create(
|
||||
name="DynamicData",
|
||||
func=lambda filter, callback_query: filter.data == callback_query.data,
|
||||
data=data # "data" kwarg is accessed with "filter.data"
|
||||
)
|
||||
|
||||
And its usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_callback_query(dynamic_data("pyrogram"))
|
||||
def pyrogram_data(client, callback_query):
|
||||
client.answer_callback_query(callback_query.id, "it works!")
|
@ -7,7 +7,8 @@ We recommend using the latest version of Python 3 and pip.
|
||||
Get Python 3 from https://www.python.org/downloads/ or with your package manager and pip
|
||||
by following the instructions at https://pip.pypa.io/en/latest/installing/.
|
||||
|
||||
Pyrogram supports Python 3 only, starting from version 3.4 and PyPy.
|
||||
.. note::
|
||||
Pyrogram supports Python 3 only, starting from version 3.4 and PyPy.
|
||||
|
||||
Install Pyrogram
|
||||
----------------
|
||||
@ -44,7 +45,7 @@ If no error shows up you are good to go.
|
||||
|
||||
>>> import pyrogram
|
||||
>>> pyrogram.__version__
|
||||
'0.7.5'
|
||||
'0.8.0'
|
||||
|
||||
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
|
||||
.. _develop: http://github.com/pyrogram/pyrogram
|
@ -8,22 +8,29 @@ with Pyrogram.
|
||||
API Keys
|
||||
--------
|
||||
|
||||
The very first step requires you to obtain a valid Telegram API key.
|
||||
The very first step requires you to obtain a valid Telegram API key (API id/hash pair).
|
||||
If you already have one you can skip this step, otherwise:
|
||||
|
||||
#. Visit https://my.telegram.org/apps and log in with your Telegram Account.
|
||||
#. Fill out the form to register a new Telegram application.
|
||||
#. Done. The Telegram API key consists of two parts: the **App api_id** and the **App api_hash**.
|
||||
#. Done. The API key consists of two parts: **App api_id** and **App api_hash**.
|
||||
|
||||
.. important:: This key should be kept secret.
|
||||
|
||||
.. important::
|
||||
|
||||
This API key is personal and should be kept secret.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
There are two ways to configure a Pyrogram application project, and you can choose the one that fits better for you:
|
||||
The API key obtained in the `previous step <#api-keys>`_ defines a token for your application allowing you to access
|
||||
the Telegram database using the MTProto API — **it is therefore required for all authorizations of both Users and Bots**.
|
||||
|
||||
Having it handy, it's time to configure your Pyrogram project. There are two ways to do so, and you can choose what
|
||||
fits better for you:
|
||||
|
||||
- Create a new ``config.ini`` file at the root of your working directory, copy-paste the following and replace the
|
||||
**api_id** and **api_hash** values with `your own <#api-keys>`_. This is the preferred method because allows you
|
||||
**api_id** and **api_hash** values with your own. This is the preferred method because allows you
|
||||
to keep your credentials out of your code without having to deal with how to load them:
|
||||
|
||||
.. code-block:: ini
|
||||
@ -45,7 +52,8 @@ There are two ways to configure a Pyrogram application project, and you can choo
|
||||
api_hash="0123456789abcdef0123456789abcdef"
|
||||
)
|
||||
|
||||
.. note:: The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
|
||||
.. note::
|
||||
The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
|
||||
and *api_hash* parameters usage.
|
||||
|
||||
User Authorization
|
||||
@ -76,16 +84,17 @@ After successfully authorizing yourself, a new file called ``my_account.session`
|
||||
Pyrogram executing API calls with your identity. This file will be loaded again when you restart your app,
|
||||
and as long as you keep the session alive, Pyrogram won't ask you again to enter your phone number.
|
||||
|
||||
.. important:: Your ``*.session`` file(s) must be kept secret.
|
||||
.. important:: Your ``*.session`` files are personal and must be kept secret.
|
||||
|
||||
Bot Authorization
|
||||
-----------------
|
||||
|
||||
Being written entirely from the ground up, Pyrogram is also able to authorize Bots.
|
||||
Bots are a special kind of users which also make use of MTProto, the underlying Telegram protocol.
|
||||
This means that you can use Pyrogram to execute API calls with a Bot identity.
|
||||
Bots are a special kind of users and are authorized via their tokens (instead of phone numbers), which are created by
|
||||
BotFather_. Bot tokens replace the Users' phone numbers only — you still need to
|
||||
`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using Bots.
|
||||
|
||||
Instead of phone numbers, Bots are authorized via their tokens which are created by BotFather_:
|
||||
The authorization process is automatically managed. All you need to do is pass the bot token as ``session_name``.
|
||||
The session file will be named after the Bot user_id, which is ``123456.session`` for the example below.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -94,9 +103,6 @@ Instead of phone numbers, Bots are authorized via their tokens which are created
|
||||
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
app.run()
|
||||
|
||||
That's all, no further action is needed. The session file will be named after the Bot user_id, which is
|
||||
``123456.session`` for the example above.
|
||||
|
||||
.. _installed Pyrogram: Installation.html
|
||||
.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes
|
||||
.. _BotFather: https://t.me/botfather
|
@ -108,9 +108,9 @@ Examples (more on `GitHub <https://github.com/pyrogram/pyrogram/tree/develop/exa
|
||||
|
||||
app.stop()
|
||||
|
||||
.. _methods: ../pyrogram/Client.html#available-methods
|
||||
.. _plenty of them: ../pyrogram/Client.html#available-methods
|
||||
.. _types: ../pyrogram/types/index.html
|
||||
.. _methods: ../pyrogram/Client.html#messages
|
||||
.. _plenty of them: ../pyrogram/Client.html#messages
|
||||
.. _types: ../pyrogram/Types.html
|
||||
.. _Raw Functions: Usage.html#using-raw-functions
|
||||
.. _Community: https://t.me/PyrogramChat
|
||||
.. _project set up: Setup.html
|
||||
|
@ -23,18 +23,15 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance
|
||||
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
||||
)
|
||||
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
|
||||
__version__ = "0.7.5"
|
||||
__version__ = "0.8.0"
|
||||
|
||||
from .api.errors import Error
|
||||
from .client.types import (
|
||||
Audio, Chat, ChatMember, ChatPhoto, Contact, Document, InputMediaPhoto,
|
||||
InputMediaVideo, InputPhoneContact, Location, Message, MessageEntity,
|
||||
PhotoSize, Sticker, Update, User, UserProfilePhotos, Venue, GIF, Video,
|
||||
VideoNote, Voice, CallbackQuery, Messages
|
||||
)
|
||||
from .client.types.reply_markup import (
|
||||
ForceReply, InlineKeyboardButton, InlineKeyboardMarkup,
|
||||
KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
|
||||
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
|
||||
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
|
||||
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User,
|
||||
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
|
||||
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
|
||||
)
|
||||
from .client import (
|
||||
Client, ChatAction, ParseMode, Emoji,
|
||||
|
@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
from io import BytesIO
|
||||
@ -23,13 +24,23 @@ from json import JSONEncoder, dumps
|
||||
|
||||
from ..all import objects
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Object:
|
||||
all = {}
|
||||
|
||||
@staticmethod
|
||||
def read(b: BytesIO, *args):
|
||||
return Object.all[int.from_bytes(b.read(4), "little")].read(b, *args)
|
||||
constructor_id = int.from_bytes(b.read(4), "little")
|
||||
|
||||
try:
|
||||
return Object.all[constructor_id].read(b, *args)
|
||||
except KeyError:
|
||||
log.error("Unknown constructor found: {}. Full data: {}".format(
|
||||
hex(constructor_id),
|
||||
b.getvalue().hex())
|
||||
)
|
||||
|
||||
def write(self, *args) -> bytes:
|
||||
pass
|
||||
|
@ -30,7 +30,7 @@ class BoolFalse(Object):
|
||||
return cls.value
|
||||
|
||||
def __new__(cls) -> bytes:
|
||||
return int.to_bytes(cls.ID, 4, "little")
|
||||
return cls.ID.to_bytes(4, "little")
|
||||
|
||||
|
||||
class BoolTrue(BoolFalse):
|
||||
|
@ -48,7 +48,7 @@ class Bytes(Object):
|
||||
else:
|
||||
return (
|
||||
bytes([254])
|
||||
+ int.to_bytes(length, 3, "little")
|
||||
+ length.to_bytes(3, "little")
|
||||
+ value
|
||||
+ bytes(-length % 4)
|
||||
)
|
||||
|
@ -29,15 +29,12 @@ class Int(Object):
|
||||
return int.from_bytes(b.read(cls.SIZE), "little", signed=signed)
|
||||
|
||||
def __new__(cls, value: int, signed: bool = True) -> bytes:
|
||||
return int.to_bytes(value, cls.SIZE, "little", signed=signed)
|
||||
return value.to_bytes(cls.SIZE, "little", signed=signed)
|
||||
|
||||
|
||||
class Long(Int):
|
||||
SIZE = 8
|
||||
|
||||
def __new__(cls, *args):
|
||||
return super().__new__(cls, *args)
|
||||
|
||||
|
||||
class Int128(Int):
|
||||
SIZE = 16
|
||||
|
@ -29,4 +29,4 @@ class Null(Object):
|
||||
return None
|
||||
|
||||
def __new__(cls) -> bytes:
|
||||
return int.to_bytes(cls.ID, 4, "little")
|
||||
return cls.ID.to_bytes(4, "little")
|
||||
|
@ -24,7 +24,7 @@ from . import Bytes
|
||||
class String(Bytes):
|
||||
@staticmethod
|
||||
def read(b: BytesIO, *args) -> str:
|
||||
return super(String, String).read(b).decode()
|
||||
return super(String, String).read(b).decode(errors="replace")
|
||||
|
||||
def __new__(cls, value: str) -> bytes:
|
||||
return super().__new__(cls, value.encode())
|
||||
|
@ -146,6 +146,7 @@ class Client(Methods, BaseClient):
|
||||
device_model: str = None,
|
||||
system_version: str = None,
|
||||
lang_code: str = None,
|
||||
ipv6: bool = False,
|
||||
proxy: dict = None,
|
||||
test_mode: bool = False,
|
||||
phone_number: str = None,
|
||||
@ -166,6 +167,7 @@ class Client(Methods, BaseClient):
|
||||
self.device_model = device_model
|
||||
self.system_version = system_version
|
||||
self.lang_code = lang_code
|
||||
self.ipv6 = ipv6
|
||||
# TODO: Make code consistent, use underscore for private/protected fields
|
||||
self._proxy = proxy
|
||||
self.test_mode = test_mode
|
||||
@ -181,6 +183,13 @@ class Client(Methods, BaseClient):
|
||||
|
||||
self.dispatcher = Dispatcher(self, workers)
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.stop()
|
||||
|
||||
@property
|
||||
def proxy(self):
|
||||
return self._proxy
|
||||
@ -201,7 +210,7 @@ class Client(Methods, BaseClient):
|
||||
raise ConnectionError("Client has already been started")
|
||||
|
||||
if self.BOT_TOKEN_RE.match(self.session_name):
|
||||
self.token = self.session_name
|
||||
self.bot_token = self.session_name
|
||||
self.session_name = self.session_name.split(":")[0]
|
||||
|
||||
self.load_config()
|
||||
@ -216,28 +225,33 @@ class Client(Methods, BaseClient):
|
||||
self.session.start()
|
||||
self.is_started = True
|
||||
|
||||
if self.user_id is None:
|
||||
if self.token is None:
|
||||
self.authorize_user()
|
||||
try:
|
||||
if self.user_id is None:
|
||||
if self.bot_token is None:
|
||||
self.authorize_user()
|
||||
else:
|
||||
self.authorize_bot()
|
||||
|
||||
self.save_session()
|
||||
|
||||
if self.bot_token is None:
|
||||
now = time.time()
|
||||
|
||||
if abs(now - self.date) > Client.OFFLINE_SLEEP:
|
||||
self.peers_by_username = {}
|
||||
self.peers_by_phone = {}
|
||||
|
||||
self.get_initial_dialogs()
|
||||
self.get_contacts()
|
||||
else:
|
||||
self.send(functions.messages.GetPinnedDialogs())
|
||||
self.get_initial_dialogs_chunk()
|
||||
else:
|
||||
self.authorize_bot()
|
||||
|
||||
self.save_session()
|
||||
|
||||
if self.token is None:
|
||||
now = time.time()
|
||||
|
||||
if abs(now - self.date) > Client.OFFLINE_SLEEP:
|
||||
self.peers_by_username = {}
|
||||
self.peers_by_phone = {}
|
||||
|
||||
self.get_dialogs()
|
||||
self.get_contacts()
|
||||
else:
|
||||
self.send(functions.messages.GetPinnedDialogs())
|
||||
self.get_dialogs_chunk(0)
|
||||
else:
|
||||
self.send(functions.updates.GetState())
|
||||
self.send(functions.updates.GetState())
|
||||
except Exception as e:
|
||||
self.is_started = False
|
||||
self.session.stop()
|
||||
raise e
|
||||
|
||||
for i in range(self.UPDATES_WORKERS):
|
||||
self.updates_workers_list.append(
|
||||
@ -381,14 +395,14 @@ class Client(Methods, BaseClient):
|
||||
flags=0,
|
||||
api_id=self.api_id,
|
||||
api_hash=self.api_hash,
|
||||
bot_auth_token=self.token
|
||||
bot_auth_token=self.bot_token
|
||||
)
|
||||
)
|
||||
except UserMigrate as e:
|
||||
self.session.stop()
|
||||
|
||||
self.dc_id = e.x
|
||||
self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
|
||||
self.auth_key = Auth(self.dc_id, self.test_mode, self.ipv6, self._proxy).create()
|
||||
|
||||
self.session = Session(
|
||||
self,
|
||||
@ -433,7 +447,7 @@ class Client(Methods, BaseClient):
|
||||
self.session.stop()
|
||||
|
||||
self.dc_id = e.x
|
||||
self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
|
||||
self.auth_key = Auth(self.dc_id, self.test_mode, self.ipv6, self._proxy).create()
|
||||
|
||||
self.session = Session(
|
||||
self,
|
||||
@ -613,7 +627,7 @@ class Client(Methods, BaseClient):
|
||||
if phone is not None:
|
||||
self.peers_by_phone[phone] = input_peer
|
||||
|
||||
if isinstance(entity, types.Chat):
|
||||
if isinstance(entity, (types.Chat, types.ChatForbidden)):
|
||||
chat_id = entity.id
|
||||
peer_id = -chat_id
|
||||
|
||||
@ -623,7 +637,7 @@ class Client(Methods, BaseClient):
|
||||
|
||||
self.peers_by_id[peer_id] = input_peer
|
||||
|
||||
if isinstance(entity, types.Channel):
|
||||
if isinstance(entity, (types.Channel, types.ChannelForbidden)):
|
||||
channel_id = entity.id
|
||||
peer_id = int("-100" + str(channel_id))
|
||||
|
||||
@ -632,7 +646,7 @@ class Client(Methods, BaseClient):
|
||||
if access_hash is None:
|
||||
continue
|
||||
|
||||
username = entity.username
|
||||
username = getattr(entity, "username", None)
|
||||
|
||||
input_peer = types.InputPeerChannel(
|
||||
channel_id=channel_id,
|
||||
@ -711,7 +725,9 @@ class Client(Methods, BaseClient):
|
||||
|
||||
file_name = "{}_{}_{}{}".format(
|
||||
media_type_str,
|
||||
datetime.fromtimestamp(media.date or time.time()).strftime("%Y-%m-%d_%H-%M-%S"),
|
||||
datetime.fromtimestamp(
|
||||
getattr(media, "date", None) or time.time()
|
||||
).strftime("%Y-%m-%d_%H-%M-%S"),
|
||||
self.rnd_id(),
|
||||
extension
|
||||
)
|
||||
@ -776,6 +792,9 @@ class Client(Methods, BaseClient):
|
||||
pts = getattr(update, "pts", None)
|
||||
pts_count = getattr(update, "pts_count", None)
|
||||
|
||||
if isinstance(update, types.UpdateChannelTooLong):
|
||||
log.warning(update)
|
||||
|
||||
if isinstance(update, types.UpdateNewChannelMessage):
|
||||
message = update.message
|
||||
|
||||
@ -834,6 +853,8 @@ class Client(Methods, BaseClient):
|
||||
self.dispatcher.updates.put((diff.other_updates[0], [], []))
|
||||
elif isinstance(updates, types.UpdateShort):
|
||||
self.dispatcher.updates.put((updates.update, [], []))
|
||||
elif isinstance(updates, types.UpdatesTooLong):
|
||||
log.warning(updates)
|
||||
except Exception as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
||||
@ -885,30 +906,18 @@ class Client(Methods, BaseClient):
|
||||
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
|
||||
)
|
||||
|
||||
for option in {"app_version", "device_model", "system_version", "lang_code"}:
|
||||
for option in ["app_version", "device_model", "system_version", "lang_code"]:
|
||||
if getattr(self, option):
|
||||
pass
|
||||
else:
|
||||
setattr(self, option, Client.APP_VERSION)
|
||||
|
||||
if parser.has_section("pyrogram"):
|
||||
setattr(self, option, parser.get(
|
||||
"pyrogram",
|
||||
option,
|
||||
fallback=getattr(Client, option.upper())
|
||||
))
|
||||
|
||||
if self.lang_code:
|
||||
pass
|
||||
else:
|
||||
self.lang_code = Client.LANG_CODE
|
||||
|
||||
if parser.has_section("pyrogram"):
|
||||
self.lang_code = parser.get(
|
||||
"pyrogram",
|
||||
"lang_code",
|
||||
fallback=Client.LANG_CODE
|
||||
)
|
||||
else:
|
||||
setattr(self, option, getattr(Client, option.upper()))
|
||||
|
||||
if self._proxy:
|
||||
self._proxy["enabled"] = True
|
||||
@ -929,7 +938,7 @@ class Client(Methods, BaseClient):
|
||||
except FileNotFoundError:
|
||||
self.dc_id = 1
|
||||
self.date = 0
|
||||
self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
|
||||
self.auth_key = Auth(self.dc_id, self.test_mode, self.ipv6, self._proxy).create()
|
||||
else:
|
||||
self.dc_id = s["dc_id"]
|
||||
self.test_mode = s["test_mode"]
|
||||
@ -971,13 +980,17 @@ class Client(Methods, BaseClient):
|
||||
indent=4
|
||||
)
|
||||
|
||||
def get_dialogs_chunk(self, offset_date):
|
||||
def get_initial_dialogs_chunk(self, offset_date: int = 0):
|
||||
while True:
|
||||
try:
|
||||
r = self.send(
|
||||
functions.messages.GetDialogs(
|
||||
offset_date, 0, types.InputPeerEmpty(),
|
||||
self.DIALOGS_AT_ONCE, True
|
||||
offset_date=offset_date,
|
||||
offset_id=0,
|
||||
offset_peer=types.InputPeerEmpty(),
|
||||
limit=self.DIALOGS_AT_ONCE,
|
||||
hash=0,
|
||||
exclude_pinned=True
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
@ -987,34 +1000,32 @@ class Client(Methods, BaseClient):
|
||||
log.info("Total peers: {}".format(len(self.peers_by_id)))
|
||||
return r
|
||||
|
||||
def get_dialogs(self):
|
||||
def get_initial_dialogs(self):
|
||||
self.send(functions.messages.GetPinnedDialogs())
|
||||
|
||||
dialogs = self.get_dialogs_chunk(0)
|
||||
dialogs = self.get_initial_dialogs_chunk()
|
||||
offset_date = utils.get_offset_date(dialogs)
|
||||
|
||||
while len(dialogs.dialogs) == self.DIALOGS_AT_ONCE:
|
||||
dialogs = self.get_dialogs_chunk(offset_date)
|
||||
dialogs = self.get_initial_dialogs_chunk(offset_date)
|
||||
offset_date = utils.get_offset_date(dialogs)
|
||||
|
||||
self.get_dialogs_chunk(0)
|
||||
self.get_initial_dialogs_chunk()
|
||||
|
||||
def resolve_peer(self, peer_id: int or str):
|
||||
"""Use this method to get the *InputPeer* of a known *peer_id*.
|
||||
"""Use this method to get the InputPeer of a known peer_id.
|
||||
|
||||
It is intended to be used when working with Raw Functions (i.e: a Telegram API method you wish to use which is
|
||||
not available yet in the Client class as an easy-to-use method).
|
||||
This is a utility method intended to be used only when working with Raw Functions (i.e: a Telegram API method
|
||||
you wish to use which is not available yet in the Client class as an easy-to-use method), whenever an InputPeer
|
||||
type is required.
|
||||
|
||||
Args:
|
||||
peer_id (``int`` | ``str`` | ``Peer``):
|
||||
The Peer ID you want to extract the InputPeer from. Can be one of these types: ``int`` (direct ID),
|
||||
``str`` (@username), :obj:`PeerUser <pyrogram.api.types.PeerUser>`,
|
||||
:obj:`PeerChat <pyrogram.api.types.PeerChat>`, :obj:`PeerChannel <pyrogram.api.types.PeerChannel>`
|
||||
peer_id (``int`` | ``str``):
|
||||
The peer id you want to extract the InputPeer from.
|
||||
Can be a direct id (int), a username (str) or a phone number (str).
|
||||
|
||||
Returns:
|
||||
:obj:`InputPeerUser <pyrogram.api.types.InputPeerUser>` or
|
||||
:obj:`InputPeerChat <pyrogram.api.types.InputPeerChat>` or
|
||||
:obj:`InputPeerChannel <pyrogram.api.types.InputPeerChannel>` depending on the *peer_id*.
|
||||
On success, the resolved peer id is returned in form of an InputPeer object.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
@ -1023,38 +1034,21 @@ class Client(Methods, BaseClient):
|
||||
if peer_id in ("self", "me"):
|
||||
return types.InputPeerSelf()
|
||||
|
||||
match = self.INVITE_LINK_RE.match(peer_id)
|
||||
|
||||
try:
|
||||
decoded = base64.b64decode(match.group(1) + "=" * (-len(match.group(1)) % 4), "-_")
|
||||
return self.resolve_peer(struct.unpack(">2iq", decoded)[1])
|
||||
except (AttributeError, binascii.Error, struct.error):
|
||||
pass
|
||||
|
||||
peer_id = re.sub(r"[@+\s]", "", peer_id.lower())
|
||||
|
||||
try:
|
||||
int(peer_id)
|
||||
except ValueError:
|
||||
try:
|
||||
return self.peers_by_username[peer_id]
|
||||
except KeyError:
|
||||
if peer_id not in self.peers_by_username:
|
||||
self.send(functions.contacts.ResolveUsername(peer_id))
|
||||
return self.peers_by_username[peer_id]
|
||||
|
||||
return self.peers_by_username[peer_id]
|
||||
else:
|
||||
try:
|
||||
return self.peers_by_phone[peer_id]
|
||||
except KeyError:
|
||||
raise PeerIdInvalid
|
||||
|
||||
if type(peer_id) is not int:
|
||||
if isinstance(peer_id, types.PeerUser):
|
||||
peer_id = peer_id.user_id
|
||||
elif isinstance(peer_id, types.PeerChat):
|
||||
peer_id = -peer_id.chat_id
|
||||
elif isinstance(peer_id, types.PeerChannel):
|
||||
peer_id = int("-100" + str(peer_id.channel_id))
|
||||
|
||||
try: # User
|
||||
return self.peers_by_id[peer_id]
|
||||
except KeyError:
|
||||
@ -1166,7 +1160,7 @@ class Client(Methods, BaseClient):
|
||||
session = Session(
|
||||
self,
|
||||
dc_id,
|
||||
Auth(dc_id, self.test_mode, self._proxy).create(),
|
||||
Auth(dc_id, self.test_mode, self.ipv6, self._proxy).create(),
|
||||
is_media=True
|
||||
)
|
||||
|
||||
@ -1229,8 +1223,6 @@ class Client(Methods, BaseClient):
|
||||
break
|
||||
|
||||
f.write(chunk)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
|
||||
offset += limit
|
||||
|
||||
@ -1253,7 +1245,7 @@ class Client(Methods, BaseClient):
|
||||
cdn_session = Session(
|
||||
self,
|
||||
r.dc_id,
|
||||
Auth(r.dc_id, self.test_mode, self._proxy).create(),
|
||||
Auth(r.dc_id, self.test_mode, self.ipv6, self._proxy).create(),
|
||||
is_media=True,
|
||||
is_cdn=True
|
||||
)
|
||||
@ -1313,8 +1305,6 @@ class Client(Methods, BaseClient):
|
||||
assert h.hash == sha256(cdn_chunk).digest(), "Invalid CDN hash part {}".format(i)
|
||||
|
||||
f.write(decrypted_chunk)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
|
||||
offset += limit
|
||||
|
||||
|
@ -41,7 +41,6 @@ class BaseClient:
|
||||
platform.release()
|
||||
)
|
||||
|
||||
SYSTEM_LANG_CODE = "en"
|
||||
LANG_CODE = "en"
|
||||
|
||||
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
|
||||
@ -60,12 +59,12 @@ class BaseClient:
|
||||
5: "document",
|
||||
8: "sticker",
|
||||
9: "audio",
|
||||
10: "gif",
|
||||
10: "animation",
|
||||
13: "video_note"
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.token = None
|
||||
self.bot_token = None
|
||||
self.dc_id = None
|
||||
self.auth_key = None
|
||||
self.user_id = None
|
||||
|
@ -60,6 +60,7 @@ class Str(str):
|
||||
ENTITIES = {
|
||||
types.MessageEntityMention.ID: "mention",
|
||||
types.MessageEntityHashtag.ID: "hashtag",
|
||||
types.MessageEntityCashtag.ID: "cashtag",
|
||||
types.MessageEntityBotCommand.ID: "bot_command",
|
||||
types.MessageEntityUrl.ID: "url",
|
||||
types.MessageEntityEmail.ID: "email",
|
||||
@ -68,7 +69,8 @@ ENTITIES = {
|
||||
types.MessageEntityCode.ID: "code",
|
||||
types.MessageEntityPre.ID: "pre",
|
||||
types.MessageEntityTextUrl.ID: "text_link",
|
||||
types.MessageEntityMentionName.ID: "text_mention"
|
||||
types.MessageEntityMentionName.ID: "text_mention",
|
||||
types.MessageEntityPhone.ID: "phone_number"
|
||||
}
|
||||
|
||||
|
||||
@ -79,18 +81,20 @@ def parse_entities(entities: list, users: dict) -> list:
|
||||
entity_type = ENTITIES.get(entity.ID, None)
|
||||
|
||||
if entity_type:
|
||||
output_entities.append(pyrogram_types.MessageEntity(
|
||||
type=entity_type,
|
||||
offset=entity.offset,
|
||||
length=entity.length,
|
||||
url=getattr(entity, "url", None),
|
||||
user=parse_user(
|
||||
users.get(
|
||||
getattr(entity, "user_id", None),
|
||||
None
|
||||
output_entities.append(
|
||||
pyrogram_types.MessageEntity(
|
||||
type=entity_type,
|
||||
offset=entity.offset,
|
||||
length=entity.length,
|
||||
url=getattr(entity, "url", None),
|
||||
user=parse_user(
|
||||
users.get(
|
||||
getattr(entity, "user_id", None),
|
||||
None
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
)
|
||||
|
||||
return output_entities
|
||||
|
||||
@ -128,6 +132,10 @@ def parse_chat_photo(photo):
|
||||
def parse_user(user: types.User) -> pyrogram_types.User or None:
|
||||
return pyrogram_types.User(
|
||||
id=user.id,
|
||||
is_self=user.is_self,
|
||||
is_contact=user.contact,
|
||||
is_mutual_contact=user.mutual_contact,
|
||||
is_deleted=user.deleted,
|
||||
is_bot=user.bot,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
@ -288,7 +296,7 @@ def parse_messages(
|
||||
venue = None
|
||||
audio = None
|
||||
voice = None
|
||||
gif = None
|
||||
animation = None
|
||||
video = None
|
||||
video_note = None
|
||||
sticker = None
|
||||
@ -329,13 +337,23 @@ def parse_messages(
|
||||
),
|
||||
width=size.w,
|
||||
height=size.h,
|
||||
file_size=file_size,
|
||||
date=photo.date
|
||||
file_size=file_size
|
||||
)
|
||||
|
||||
photo_sizes.append(photo_size)
|
||||
|
||||
photo = photo_sizes
|
||||
photo = pyrogram_types.Photo(
|
||||
id=b64encode(
|
||||
pack(
|
||||
"<qq",
|
||||
photo.id,
|
||||
photo.access_hash
|
||||
),
|
||||
b"-_"
|
||||
).decode().rstrip("="),
|
||||
date=photo.date,
|
||||
sizes=photo_sizes
|
||||
)
|
||||
elif isinstance(media, types.MessageMediaGeo):
|
||||
geo_point = media.geo
|
||||
|
||||
@ -349,6 +367,7 @@ def parse_messages(
|
||||
phone_number=media.phone_number,
|
||||
first_name=media.first_name,
|
||||
last_name=media.last_name or None,
|
||||
vcard=media.vcard or None,
|
||||
user_id=media.user_id or None
|
||||
)
|
||||
elif isinstance(media, types.MessageMediaVenue):
|
||||
@ -359,7 +378,8 @@ def parse_messages(
|
||||
),
|
||||
title=media.title,
|
||||
address=media.address,
|
||||
foursquare_id=media.venue_id or None
|
||||
foursquare_id=media.venue_id or None,
|
||||
foursquare_type=media.venue_type
|
||||
)
|
||||
elif isinstance(media, types.MessageMediaDocument):
|
||||
doc = media.document
|
||||
@ -390,8 +410,7 @@ def parse_messages(
|
||||
duration=audio_attributes.duration,
|
||||
mime_type=doc.mime_type,
|
||||
file_size=doc.size,
|
||||
thumb=parse_thumb(doc.thumb),
|
||||
file_name=file_name,
|
||||
waveform=audio_attributes.waveform,
|
||||
date=doc.date
|
||||
)
|
||||
else:
|
||||
@ -417,7 +436,7 @@ def parse_messages(
|
||||
elif types.DocumentAttributeAnimated in attributes:
|
||||
video_attributes = attributes.get(types.DocumentAttributeVideo, None)
|
||||
|
||||
gif = pyrogram_types.GIF(
|
||||
animation = pyrogram_types.Animation(
|
||||
file_id=encode(
|
||||
pack(
|
||||
"<iiqq",
|
||||
@ -454,7 +473,6 @@ def parse_messages(
|
||||
duration=video_attributes.duration,
|
||||
thumb=parse_thumb(doc.thumb),
|
||||
file_size=doc.size,
|
||||
file_name=file_name,
|
||||
mime_type=doc.mime_type,
|
||||
date=doc.date
|
||||
)
|
||||
@ -570,7 +588,7 @@ def parse_messages(
|
||||
venue=venue,
|
||||
audio=audio,
|
||||
voice=voice,
|
||||
gif=gif,
|
||||
animation=animation,
|
||||
video=video,
|
||||
video_note=video_note,
|
||||
sticker=sticker,
|
||||
@ -664,13 +682,23 @@ def parse_messages(
|
||||
),
|
||||
width=size.w,
|
||||
height=size.h,
|
||||
file_size=file_size,
|
||||
date=photo.date
|
||||
file_size=file_size
|
||||
)
|
||||
|
||||
photo_sizes.append(photo_size)
|
||||
|
||||
new_chat_photo = photo_sizes
|
||||
new_chat_photo = pyrogram_types.Photo(
|
||||
id=b64encode(
|
||||
pack(
|
||||
"<qq",
|
||||
photo.id,
|
||||
photo.access_hash
|
||||
),
|
||||
b"-_"
|
||||
).decode().rstrip("="),
|
||||
date=photo.date,
|
||||
sizes=photo_sizes
|
||||
)
|
||||
|
||||
m = pyrogram_types.Message(
|
||||
message_id=message.id,
|
||||
@ -757,7 +785,7 @@ def get_offset_date(dialogs):
|
||||
return 0
|
||||
|
||||
|
||||
def parse_photos(photos):
|
||||
def parse_profile_photos(photos):
|
||||
if isinstance(photos, types.photos.Photos):
|
||||
total_count = len(photos.photos)
|
||||
else:
|
||||
@ -795,13 +823,25 @@ def parse_photos(photos):
|
||||
),
|
||||
width=size.w,
|
||||
height=size.h,
|
||||
file_size=file_size,
|
||||
date=photo.date
|
||||
file_size=file_size
|
||||
)
|
||||
|
||||
photo_sizes.append(photo_size)
|
||||
|
||||
user_profile_photos.append(photo_sizes)
|
||||
user_profile_photos.append(
|
||||
pyrogram_types.Photo(
|
||||
id=b64encode(
|
||||
pack(
|
||||
"<qq",
|
||||
photo.id,
|
||||
photo.access_hash
|
||||
),
|
||||
b"-_"
|
||||
).decode().rstrip("="),
|
||||
date=photo.date,
|
||||
sizes=photo_sizes
|
||||
)
|
||||
)
|
||||
|
||||
return pyrogram_types.UserProfilePhotos(
|
||||
total_count=total_count,
|
||||
@ -852,8 +892,8 @@ def parse_chat_full(
|
||||
chat_full: types.messages.ChatFull or types.UserFull
|
||||
) -> pyrogram_types.Chat:
|
||||
if isinstance(chat_full, types.UserFull):
|
||||
chat = parse_user_chat(chat_full.user)
|
||||
chat.description = chat_full.about
|
||||
parsed_chat = parse_user_chat(chat_full.user)
|
||||
parsed_chat.description = chat_full.about
|
||||
else:
|
||||
full_chat = chat_full.full_chat
|
||||
chat = None
|
||||
@ -863,21 +903,134 @@ def parse_chat_full(
|
||||
chat = i
|
||||
|
||||
if isinstance(full_chat, types.ChatFull):
|
||||
chat = parse_chat_chat(chat)
|
||||
parsed_chat = parse_chat_chat(chat)
|
||||
|
||||
if isinstance(full_chat.participants, types.ChatParticipants):
|
||||
parsed_chat.members_count = len(full_chat.participants.participants)
|
||||
else:
|
||||
chat = parse_channel_chat(chat)
|
||||
chat.description = full_chat.about or None
|
||||
parsed_chat = parse_channel_chat(chat)
|
||||
parsed_chat.members_count = full_chat.participants_count
|
||||
parsed_chat.description = full_chat.about or None
|
||||
# TODO: Add StickerSet type
|
||||
chat.can_set_sticker_set = full_chat.can_set_stickers
|
||||
chat.sticker_set_name = full_chat.stickerset
|
||||
parsed_chat.can_set_sticker_set = full_chat.can_set_stickers
|
||||
parsed_chat.sticker_set_name = full_chat.stickerset
|
||||
|
||||
if full_chat.pinned_msg_id:
|
||||
chat.pinned_message = client.get_messages(
|
||||
int("-100" + str(full_chat.id)),
|
||||
parsed_chat.pinned_message = client.get_messages(
|
||||
parsed_chat.id,
|
||||
full_chat.pinned_msg_id
|
||||
)
|
||||
|
||||
if isinstance(full_chat.exported_invite, types.ChatInviteExported):
|
||||
chat.invite_link = full_chat.exported_invite.link
|
||||
parsed_chat.invite_link = full_chat.exported_invite.link
|
||||
|
||||
return chat
|
||||
return parsed_chat
|
||||
|
||||
|
||||
def parse_dialog_chat(peer, users: dict, chats: dict):
|
||||
if isinstance(peer, types.PeerUser):
|
||||
return parse_user_chat(users[peer.user_id])
|
||||
elif isinstance(peer, types.PeerChat):
|
||||
return parse_chat_chat(chats[peer.chat_id])
|
||||
else:
|
||||
return parse_channel_chat(chats[peer.channel_id])
|
||||
|
||||
|
||||
def parse_chat_members(members: types.channels.ChannelParticipants or types.messages.ChatFull):
|
||||
users = {i.id: i for i in members.users}
|
||||
parsed_members = []
|
||||
|
||||
if isinstance(members, types.channels.ChannelParticipants):
|
||||
members = members.participants
|
||||
|
||||
for member in members:
|
||||
user = parse_user(users[member.user_id])
|
||||
|
||||
if isinstance(member, (types.ChannelParticipant, types.ChannelParticipantSelf)):
|
||||
parsed_members.append(
|
||||
pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="member"
|
||||
)
|
||||
)
|
||||
elif isinstance(member, types.ChannelParticipantCreator):
|
||||
parsed_members.append(
|
||||
pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="creator"
|
||||
)
|
||||
)
|
||||
elif isinstance(member, types.ChannelParticipantAdmin):
|
||||
rights = member.admin_rights # type: types.ChannelAdminRights
|
||||
|
||||
parsed_members.append(
|
||||
pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="administrator",
|
||||
can_be_edited=member.can_edit,
|
||||
can_change_info=rights.change_info,
|
||||
can_post_messages=rights.post_messages,
|
||||
can_edit_messages=rights.edit_messages,
|
||||
can_delete_messages=rights.delete_messages,
|
||||
can_invite_users=rights.invite_users or rights.invite_link,
|
||||
can_restrict_members=rights.ban_users,
|
||||
can_pin_messages=rights.pin_messages,
|
||||
can_promote_members=rights.add_admins
|
||||
)
|
||||
)
|
||||
elif isinstance(member, types.ChannelParticipantBanned):
|
||||
rights = member.banned_rights # type: types.ChannelBannedRights
|
||||
|
||||
chat_member = pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="kicked" if rights.view_messages else "restricted",
|
||||
until_date=0 if rights.until_date == (1 << 31) - 1 else rights.until_date
|
||||
)
|
||||
|
||||
if chat_member.status == "restricted":
|
||||
chat_member.can_send_messages = not rights.send_messages
|
||||
chat_member.can_send_media_messages = not rights.send_media
|
||||
chat_member.can_send_other_messages = (
|
||||
not rights.send_stickers or not rights.send_gifs or
|
||||
not rights.send_games or not rights.send_inline
|
||||
)
|
||||
chat_member.can_add_web_page_previews = not rights.embed_links
|
||||
|
||||
parsed_members.append(chat_member)
|
||||
|
||||
return pyrogram_types.ChatMembers(
|
||||
total_count=members.count,
|
||||
chat_members=parsed_members
|
||||
)
|
||||
else:
|
||||
members = members.full_chat.participants.participants
|
||||
|
||||
for member in members:
|
||||
user = parse_user(users[member.user_id])
|
||||
|
||||
if isinstance(member, types.ChatParticipant):
|
||||
parsed_members.append(
|
||||
pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="member"
|
||||
)
|
||||
)
|
||||
elif isinstance(member, types.ChatParticipantCreator):
|
||||
parsed_members.append(
|
||||
pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="creator"
|
||||
)
|
||||
)
|
||||
elif isinstance(member, types.ChatParticipantAdmin):
|
||||
parsed_members.append(
|
||||
pyrogram_types.ChatMember(
|
||||
user=user,
|
||||
status="administrator"
|
||||
)
|
||||
)
|
||||
|
||||
return pyrogram_types.ChatMembers(
|
||||
total_count=len(members),
|
||||
chat_members=parsed_members
|
||||
)
|
||||
|
@ -19,10 +19,32 @@
|
||||
import re
|
||||
|
||||
from .filter import Filter
|
||||
from ..types.reply_markup import InlineKeyboardMarkup, ReplyKeyboardMarkup
|
||||
from ..types.bots import InlineKeyboardMarkup, ReplyKeyboardMarkup
|
||||
|
||||
|
||||
def build(name: str, func: callable, **kwargs) -> type:
|
||||
def create(name: str, func: callable, **kwargs) -> type:
|
||||
"""Use this method to create a Filter.
|
||||
|
||||
Custom filters give you extra control over which updates are allowed or not to be processed by your handlers.
|
||||
|
||||
Args:
|
||||
name (``str``):
|
||||
Your filter's name. Can be anything you like.
|
||||
|
||||
func (``callable``):
|
||||
A function that accepts two arguments *(filter, update)* and returns a Boolean: True if the update should be
|
||||
handled, False otherwise.
|
||||
The "update" argument type will vary depending on which `Handler <Handlers.html>`_ is coming from.
|
||||
For example, in a :obj:`MessageHandler <pyrogram.MessageHandler>` the update type will be
|
||||
a :obj:`Message <pyrogram.Message>`; in a :obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>` the
|
||||
update type will be a :obj:`CallbackQuery <pyrogram.CallbackQuery>`. Your function body can then access the
|
||||
incoming update and decide whether to allow it or not.
|
||||
|
||||
**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`).
|
||||
"""
|
||||
# TODO: unpack kwargs using **kwargs into the dict itself. For Python 3.5+ only
|
||||
d = {"__call__": func}
|
||||
d.update(kwargs)
|
||||
|
||||
@ -30,112 +52,118 @@ def build(name: str, func: callable, **kwargs) -> type:
|
||||
|
||||
|
||||
class Filters:
|
||||
"""This class provides access to all Filters available in Pyrogram.
|
||||
Filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`."""
|
||||
"""This class provides access to all library-defined Filters available in Pyrogram.
|
||||
|
||||
bot = build("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
|
||||
The Filters listed here are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>` only.
|
||||
At the moment, if you want to filter updates coming from different `Handlers <Handlers.html>`_ you have to create
|
||||
your own filters with :meth:`Filters.create` and use them in the same way.
|
||||
"""
|
||||
|
||||
create = create
|
||||
|
||||
bot = create("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
|
||||
"""Filter messages coming from bots"""
|
||||
|
||||
incoming = build("Incoming", lambda _, m: not m.outgoing)
|
||||
incoming = create("Incoming", lambda _, m: not m.outgoing)
|
||||
"""Filter incoming messages."""
|
||||
|
||||
outgoing = build("Outgoing", lambda _, m: m.outgoing)
|
||||
outgoing = create("Outgoing", lambda _, m: m.outgoing)
|
||||
"""Filter outgoing messages."""
|
||||
|
||||
text = build("Text", lambda _, m: bool(m.text))
|
||||
text = create("Text", lambda _, m: bool(m.text))
|
||||
"""Filter text messages."""
|
||||
|
||||
reply = build("Reply", lambda _, m: bool(m.reply_to_message))
|
||||
reply = create("Reply", lambda _, m: bool(m.reply_to_message))
|
||||
"""Filter messages that are replies to other messages."""
|
||||
|
||||
forwarded = build("Forwarded", lambda _, m: bool(m.forward_date))
|
||||
forwarded = create("Forwarded", lambda _, m: bool(m.forward_date))
|
||||
"""Filter messages that are forwarded."""
|
||||
|
||||
caption = build("Caption", lambda _, m: bool(m.caption))
|
||||
caption = create("Caption", lambda _, m: bool(m.caption))
|
||||
"""Filter media messages that contain captions."""
|
||||
|
||||
edited = build("Edited", lambda _, m: bool(m.edit_date))
|
||||
edited = create("Edited", lambda _, m: bool(m.edit_date))
|
||||
"""Filter edited messages."""
|
||||
|
||||
audio = build("Audio", lambda _, m: bool(m.audio))
|
||||
audio = create("Audio", lambda _, m: bool(m.audio))
|
||||
"""Filter messages that contain :obj:`Audio <pyrogram.api.types.pyrogram.Audio>` objects."""
|
||||
|
||||
document = build("Document", lambda _, m: bool(m.document))
|
||||
document = create("Document", lambda _, m: bool(m.document))
|
||||
"""Filter messages that contain :obj:`Document <pyrogram.api.types.pyrogram.Document>` objects."""
|
||||
|
||||
photo = build("Photo", lambda _, m: bool(m.photo))
|
||||
photo = create("Photo", lambda _, m: bool(m.photo))
|
||||
"""Filter messages that contain :obj:`Photo <pyrogram.api.types.pyrogram.PhotoSize>` objects."""
|
||||
|
||||
sticker = build("Sticker", lambda _, m: bool(m.sticker))
|
||||
sticker = create("Sticker", lambda _, m: bool(m.sticker))
|
||||
"""Filter messages that contain :obj:`Sticker <pyrogram.api.types.pyrogram.Sticker>` objects."""
|
||||
|
||||
gif = build("GIF", lambda _, m: bool(m.gif))
|
||||
"""Filter messages that contain :obj:`GIF <pyrogram.api.types.pyrogram.GIF>` objects."""
|
||||
animation = create("GIF", lambda _, m: bool(m.animation))
|
||||
"""Filter messages that contain :obj:`Animation <pyrogram.api.types.pyrogram.Animation>` objects."""
|
||||
|
||||
video = build("Video", lambda _, m: bool(m.video))
|
||||
video = create("Video", lambda _, m: bool(m.video))
|
||||
"""Filter messages that contain :obj:`Video <pyrogram.api.types.pyrogram.Video>` objects."""
|
||||
|
||||
voice = build("Voice", lambda _, m: bool(m.voice))
|
||||
voice = create("Voice", lambda _, m: bool(m.voice))
|
||||
"""Filter messages that contain :obj:`Voice <pyrogram.api.types.pyrogram.Voice>` note objects."""
|
||||
|
||||
video_note = build("Voice", lambda _, m: bool(m.video_note))
|
||||
video_note = create("Voice", lambda _, m: bool(m.video_note))
|
||||
"""Filter messages that contain :obj:`VideoNote <pyrogram.api.types.pyrogram.VideoNote>` objects."""
|
||||
|
||||
contact = build("Contact", lambda _, m: bool(m.contact))
|
||||
contact = create("Contact", lambda _, m: bool(m.contact))
|
||||
"""Filter messages that contain :obj:`Contact <pyrogram.api.types.pyrogram.Contact>` objects."""
|
||||
|
||||
location = build("Location", lambda _, m: bool(m.location))
|
||||
location = create("Location", lambda _, m: bool(m.location))
|
||||
"""Filter messages that contain :obj:`Location <pyrogram.api.types.pyrogram.Location>` objects."""
|
||||
|
||||
venue = build("Venue", lambda _, m: bool(m.venue))
|
||||
venue = create("Venue", lambda _, m: bool(m.venue))
|
||||
"""Filter messages that contain :obj:`Venue <pyrogram.api.types.pyrogram.Venue>` objects."""
|
||||
|
||||
private = build("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
|
||||
private = create("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
|
||||
"""Filter messages sent in private chats."""
|
||||
|
||||
group = build("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}))
|
||||
group = create("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}))
|
||||
"""Filter messages sent in group or supergroup chats."""
|
||||
|
||||
channel = build("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel"))
|
||||
channel = create("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel"))
|
||||
"""Filter messages sent in channels."""
|
||||
|
||||
new_chat_members = build("NewChatMembers", lambda _, m: bool(m.new_chat_members))
|
||||
new_chat_members = create("NewChatMembers", lambda _, m: bool(m.new_chat_members))
|
||||
"""Filter service messages for new chat members."""
|
||||
|
||||
left_chat_member = build("LeftChatMember", lambda _, m: bool(m.left_chat_member))
|
||||
left_chat_member = create("LeftChatMember", lambda _, m: bool(m.left_chat_member))
|
||||
"""Filter service messages for members that left the chat."""
|
||||
|
||||
new_chat_title = build("NewChatTitle", lambda _, m: bool(m.new_chat_title))
|
||||
new_chat_title = create("NewChatTitle", lambda _, m: bool(m.new_chat_title))
|
||||
"""Filter service messages for new chat titles."""
|
||||
|
||||
new_chat_photo = build("NewChatPhoto", lambda _, m: bool(m.new_chat_photo))
|
||||
new_chat_photo = create("NewChatPhoto", lambda _, m: bool(m.new_chat_photo))
|
||||
"""Filter service messages for new chat photos."""
|
||||
|
||||
delete_chat_photo = build("DeleteChatPhoto", lambda _, m: bool(m.delete_chat_photo))
|
||||
delete_chat_photo = create("DeleteChatPhoto", lambda _, m: bool(m.delete_chat_photo))
|
||||
"""Filter service messages for deleted photos."""
|
||||
|
||||
group_chat_created = build("GroupChatCreated", lambda _, m: bool(m.group_chat_created))
|
||||
group_chat_created = create("GroupChatCreated", lambda _, m: bool(m.group_chat_created))
|
||||
"""Filter service messages for group chat creations."""
|
||||
|
||||
supergroup_chat_created = build("SupergroupChatCreated", lambda _, m: bool(m.supergroup_chat_created))
|
||||
supergroup_chat_created = create("SupergroupChatCreated", lambda _, m: bool(m.supergroup_chat_created))
|
||||
"""Filter service messages for supergroup chat creations."""
|
||||
|
||||
channel_chat_created = build("ChannelChatCreated", lambda _, m: bool(m.channel_chat_created))
|
||||
channel_chat_created = create("ChannelChatCreated", lambda _, m: bool(m.channel_chat_created))
|
||||
"""Filter service messages for channel chat creations."""
|
||||
|
||||
migrate_to_chat_id = build("MigrateToChatId", lambda _, m: bool(m.migrate_to_chat_id))
|
||||
migrate_to_chat_id = create("MigrateToChatId", lambda _, m: bool(m.migrate_to_chat_id))
|
||||
"""Filter service messages that contain migrate_to_chat_id."""
|
||||
|
||||
migrate_from_chat_id = build("MigrateFromChatId", lambda _, m: bool(m.migrate_from_chat_id))
|
||||
migrate_from_chat_id = create("MigrateFromChatId", lambda _, m: bool(m.migrate_from_chat_id))
|
||||
"""Filter service messages that contain migrate_from_chat_id."""
|
||||
|
||||
pinned_message = build("PinnedMessage", lambda _, m: bool(m.pinned_message))
|
||||
pinned_message = create("PinnedMessage", lambda _, m: bool(m.pinned_message))
|
||||
"""Filter service messages for pinned messages."""
|
||||
|
||||
reply_keyboard = build("ReplyKeyboard", lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup))
|
||||
reply_keyboard = create("ReplyKeyboard", lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup))
|
||||
"""Filter messages containing reply keyboard markups"""
|
||||
|
||||
inline_keyboard = build("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
|
||||
inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
|
||||
"""Filter messages containing inline keyboard markups"""
|
||||
|
||||
@staticmethod
|
||||
@ -174,7 +202,7 @@ class Filters:
|
||||
|
||||
return bool(m.command)
|
||||
|
||||
return build(
|
||||
return create(
|
||||
"Command",
|
||||
f,
|
||||
c={command if case_sensitive
|
||||
@ -206,51 +234,67 @@ class Filters:
|
||||
m.matches = [i for i in _.p.finditer(m.text or "")]
|
||||
return bool(m.matches)
|
||||
|
||||
return build("Regex", f, p=re.compile(pattern, flags))
|
||||
return create("Regex", f, p=re.compile(pattern, flags))
|
||||
|
||||
@staticmethod
|
||||
def user(user: int or str or list):
|
||||
"""Filter messages coming from specific users.
|
||||
# noinspection PyPep8Naming
|
||||
class user(Filter, set):
|
||||
"""Filter messages coming from one or more users.
|
||||
|
||||
You can use `set bound methods <https://docs.python.org/3/library/stdtypes.html#set>`_ to manipulate the
|
||||
users container.
|
||||
|
||||
Args:
|
||||
user (``int`` | ``str`` | ``list``):
|
||||
The user or list of user IDs (int) or usernames (str) the filter should look for.
|
||||
users (``int`` | ``str`` | ``list``):
|
||||
Pass one or more user ids/usernames to filter users.
|
||||
Defaults to None (no users).
|
||||
"""
|
||||
return build(
|
||||
"User",
|
||||
lambda _, m: bool(m.from_user
|
||||
and (m.from_user.id in _.u
|
||||
or (m.from_user.username
|
||||
and m.from_user.username.lower() in _.u))),
|
||||
u=(
|
||||
{user.lower().strip("@") if type(user) is str else user}
|
||||
if not isinstance(user, list)
|
||||
else {i.lower().strip("@") if type(i) is str else i for i in user}
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def chat(chat: int or str or list):
|
||||
"""Filter messages coming from specific chats.
|
||||
def __init__(self, users: int or str or list = None):
|
||||
users = [] if users is None else users if type(users) is list else [users]
|
||||
super().__init__(
|
||||
{i.lower().strip("@") if type(i) is str else i for i in users}
|
||||
if type(users) is list else
|
||||
{users.lower().strip("@") if type(users) is str else users}
|
||||
)
|
||||
|
||||
def __call__(self, message):
|
||||
return bool(
|
||||
message.from_user
|
||||
and (message.from_user.id in self
|
||||
or (message.from_user.username
|
||||
and message.from_user.username.lower() in self))
|
||||
)
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class chat(Filter, set):
|
||||
"""Filter messages coming from one or more chats.
|
||||
|
||||
You can use `set bound methods <https://docs.python.org/3/library/stdtypes.html#set>`_ to manipulate the
|
||||
chats container.
|
||||
|
||||
Args:
|
||||
chat (``int`` | ``str`` | ``list``):
|
||||
The chat or list of chat IDs (int) or usernames (str) the filter should look for.
|
||||
chats (``int`` | ``str`` | ``list``):
|
||||
Pass one or more chat ids/usernames to filter chats.
|
||||
Defaults to None (no chats).
|
||||
"""
|
||||
return build(
|
||||
"Chat",
|
||||
lambda _, m: bool(m.chat
|
||||
and (m.chat.id in _.c
|
||||
or (m.chat.username
|
||||
and m.chat.username.lower() in _.c))),
|
||||
c=(
|
||||
{chat.lower().strip("@") if type(chat) is str else chat}
|
||||
if not isinstance(chat, list)
|
||||
else {i.lower().strip("@") if type(i) is str else i for i in chat}
|
||||
)
|
||||
)
|
||||
|
||||
service = build(
|
||||
def __init__(self, chats: int or str or list = None):
|
||||
chats = [] if chats is None else chats if type(chats) is list else [chats]
|
||||
super().__init__(
|
||||
{i.lower().strip("@") if type(i) is str else i for i in chats}
|
||||
if type(chats) is list else
|
||||
{chats.lower().strip("@") if type(chats) is str else chats}
|
||||
)
|
||||
|
||||
def __call__(self, message):
|
||||
return bool(
|
||||
message.chat
|
||||
and (message.chat.id in self
|
||||
or (message.chat.username
|
||||
and message.chat.username.lower() in self))
|
||||
)
|
||||
|
||||
service = create(
|
||||
"Service",
|
||||
lambda _, m: bool(
|
||||
Filters.new_chat_members(m)
|
||||
@ -268,7 +312,7 @@ class Filters:
|
||||
)
|
||||
"""Filter all service messages."""
|
||||
|
||||
media = build(
|
||||
media = create(
|
||||
"Media",
|
||||
lambda _, m: bool(
|
||||
Filters.audio(m)
|
||||
@ -276,7 +320,7 @@ class Filters:
|
||||
or Filters.photo(m)
|
||||
or Filters.sticker(m)
|
||||
or Filters.video(m)
|
||||
or Filters.gif(m)
|
||||
or Filters.animation(m)
|
||||
or Filters.voice(m)
|
||||
or Filters.video_note(m)
|
||||
or Filters.contact(m)
|
||||
|
@ -49,6 +49,6 @@ class CallbackQueryHandler(Handler):
|
||||
def check(self, callback_query):
|
||||
return (
|
||||
self.filters(callback_query)
|
||||
if self.filters
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -50,6 +50,6 @@ class DeletedMessagesHandler(Handler):
|
||||
def check(self, messages):
|
||||
return (
|
||||
self.filters(messages.messages[0])
|
||||
if self.filters
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -50,6 +50,6 @@ class MessageHandler(Handler):
|
||||
def check(self, message):
|
||||
return (
|
||||
self.filters(message)
|
||||
if self.filters
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -20,10 +20,10 @@ from .bots import Bots
|
||||
from .chats import Chats
|
||||
from .contacts import Contacts
|
||||
from .decorators import Decorators
|
||||
from .download_media import DownloadMedia
|
||||
from .messages import Messages
|
||||
from .password import Password
|
||||
from .users import Users
|
||||
from .utilities import Utilities
|
||||
|
||||
|
||||
class Methods(
|
||||
@ -32,7 +32,7 @@ class Methods(
|
||||
Password,
|
||||
Chats,
|
||||
Users,
|
||||
DownloadMedia,
|
||||
Utilities,
|
||||
Messages,
|
||||
Decorators
|
||||
):
|
||||
|
@ -33,7 +33,6 @@ class RequestCallbackAnswer(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
message_id (``int``):
|
||||
The message id the inline keyboard is attached on.
|
||||
|
@ -35,7 +35,6 @@ class SendInlineBotResult(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
query_id (``int``):
|
||||
Unique identifier for the answered query.
|
||||
|
@ -16,14 +16,24 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .delete_chat_photo import DeleteChatPhoto
|
||||
from .export_chat_invite_link import ExportChatInviteLink
|
||||
from .get_chat import GetChat
|
||||
from .get_chat_member import GetChatMember
|
||||
from .get_chat_members import GetChatMembers
|
||||
from .get_chat_members_count import GetChatMembersCount
|
||||
from .get_dialogs import GetDialogs
|
||||
from .join_chat import JoinChat
|
||||
from .kick_chat_member import KickChatMember
|
||||
from .leave_chat import LeaveChat
|
||||
from .pin_chat_message import PinChatMessage
|
||||
from .promote_chat_member import PromoteChatMember
|
||||
from .restrict_chat_member import RestrictChatMember
|
||||
from .set_chat_description import SetChatDescription
|
||||
from .set_chat_photo import SetChatPhoto
|
||||
from .set_chat_title import SetChatTitle
|
||||
from .unban_chat_member import UnbanChatMember
|
||||
from .unpin_chat_message import UnpinChatMessage
|
||||
|
||||
|
||||
class Chats(
|
||||
@ -34,6 +44,16 @@ class Chats(
|
||||
KickChatMember,
|
||||
UnbanChatMember,
|
||||
RestrictChatMember,
|
||||
PromoteChatMember
|
||||
PromoteChatMember,
|
||||
GetChatMembers,
|
||||
GetChatMember,
|
||||
SetChatPhoto,
|
||||
DeleteChatPhoto,
|
||||
SetChatTitle,
|
||||
SetChatDescription,
|
||||
PinChatMessage,
|
||||
UnpinChatMessage,
|
||||
GetDialogs,
|
||||
GetChatMembersCount
|
||||
):
|
||||
pass
|
||||
|
63
pyrogram/client/methods/chats/delete_chat_photo.py
Normal file
63
pyrogram/client/methods/chats/delete_chat_photo.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class DeleteChatPhoto(BaseClient):
|
||||
def delete_chat_photo(self, chat_id: int or str):
|
||||
"""Use this method to delete a chat photo.
|
||||
Photos can't be changed for private chats.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
|
||||
setting is off.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
self.send(
|
||||
functions.messages.EditChatPhoto(
|
||||
chat_id=peer.chat_id,
|
||||
photo=types.InputChatPhotoEmpty()
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
functions.channels.EditPhoto(
|
||||
channel=peer,
|
||||
photo=types.InputChatPhotoEmpty()
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
return True
|
@ -25,6 +25,10 @@ class GetChat(BaseClient):
|
||||
"""Use this method to get up to date information about the chat (current name of the user for
|
||||
one-on-one conversations, current username of a user, group or channel, etc.)
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
|
75
pyrogram/client/methods/chats/get_chat_member.py
Normal file
75
pyrogram/client/methods/chats/get_chat_member.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types, errors
|
||||
from ...ext import BaseClient, utils
|
||||
|
||||
|
||||
class GetChatMember(BaseClient):
|
||||
def get_chat_member(self,
|
||||
chat_id: int or str,
|
||||
user_id: int or str):
|
||||
"""Use this method to get information about one member of a chat.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
user_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).
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`ChatMember <pyrogram.ChatMember>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
"""
|
||||
chat_id = self.resolve_peer(chat_id)
|
||||
user_id = self.resolve_peer(user_id)
|
||||
|
||||
if isinstance(chat_id, types.InputPeerChat):
|
||||
full_chat = self.send(
|
||||
functions.messages.GetFullChat(
|
||||
chat_id=chat_id.chat_id
|
||||
)
|
||||
)
|
||||
|
||||
for member in utils.parse_chat_members(full_chat).chat_members:
|
||||
if member.user.id == user_id.user_id:
|
||||
return member
|
||||
else:
|
||||
raise errors.UserNotParticipant
|
||||
elif isinstance(chat_id, types.InputPeerChannel):
|
||||
r = self.send(
|
||||
functions.channels.GetParticipant(
|
||||
channel=chat_id,
|
||||
user_id=user_id
|
||||
)
|
||||
)
|
||||
|
||||
return utils.parse_chat_members(
|
||||
types.channels.ChannelParticipants(
|
||||
count=1,
|
||||
participants=[r.participant],
|
||||
users=r.users
|
||||
)
|
||||
).chat_members[0]
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
115
pyrogram/client/methods/chats/get_chat_members.py
Normal file
115
pyrogram/client/methods/chats/get_chat_members.py
Normal file
@ -0,0 +1,115 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient, utils
|
||||
|
||||
|
||||
class Filters:
|
||||
ALL = "all"
|
||||
KICKED = "kicked"
|
||||
RESTRICTED = "restricted"
|
||||
BOTS = "bots"
|
||||
RECENT = "recent"
|
||||
ADMINISTRATORS = "administrators"
|
||||
|
||||
|
||||
class GetChatMembers(BaseClient):
|
||||
def get_chat_members(self,
|
||||
chat_id: int or str,
|
||||
offset: int = 0,
|
||||
limit: int = 200,
|
||||
query: str = "",
|
||||
filter: str = Filters.ALL):
|
||||
"""Use this method to get the members list of a chat.
|
||||
|
||||
A chat can be either a basic group, a supergroup or a channel.
|
||||
You must be admin to retrieve the members (also known as "subscribers") list of a channel.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
offset (``int``, *optional*):
|
||||
Sequential number of the first member to be returned.
|
||||
Defaults to 0 [1]_.
|
||||
|
||||
limit (``int``, *optional*):
|
||||
Limits the number of members to be retrieved.
|
||||
Defaults to 200, which is also the maximum limit allowed per method call.
|
||||
|
||||
query (``str``, *optional*):
|
||||
Query string to filter members based on their display names and usernames.
|
||||
Defaults to "" (empty string) [2]_.
|
||||
|
||||
filter (``str``, *optional*):
|
||||
Filter used to select the kind of members you want to retrieve. Only applicable for supergroups
|
||||
and channels. It can be any of the followings:
|
||||
*"all"* - all kind of members,
|
||||
*"kicked"* - kicked (banned) members only,
|
||||
*"restricted"* - restricted members only,
|
||||
*"bots"* - bots only,
|
||||
*"recent"* - recent members only,
|
||||
*"administrators"* - chat administrators only.
|
||||
Defaults to *"all"*.
|
||||
|
||||
.. [1] On supergroups and channels you can get up to 10,000 members for a single query string.
|
||||
|
||||
.. [2] A query string is applicable only for *"all"*, *"kicked"* and *"restricted"* filters only.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
return utils.parse_chat_members(
|
||||
self.send(
|
||||
functions.messages.GetFullChat(
|
||||
peer.chat_id
|
||||
)
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChannel):
|
||||
filter = filter.lower()
|
||||
|
||||
if filter == Filters.ALL:
|
||||
filter = types.ChannelParticipantsSearch(q=query)
|
||||
elif filter == Filters.KICKED:
|
||||
filter = types.ChannelParticipantsKicked(q=query)
|
||||
elif filter == Filters.RESTRICTED:
|
||||
filter = types.ChannelParticipantsBanned(q=query)
|
||||
elif filter == Filters.BOTS:
|
||||
filter = types.ChannelParticipantsBots()
|
||||
elif filter == Filters.RECENT:
|
||||
filter = types.ChannelParticipantsRecent()
|
||||
elif filter == Filters.ADMINISTRATORS:
|
||||
filter = types.ChannelParticipantsAdmins()
|
||||
else:
|
||||
raise ValueError("Invalid filter \"{}\"".format(filter))
|
||||
|
||||
return utils.parse_chat_members(
|
||||
self.send(
|
||||
functions.channels.GetParticipants(
|
||||
channel=peer,
|
||||
filter=filter,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
hash=0
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
53
pyrogram/client/methods/chats/get_chat_members_count.py
Normal file
53
pyrogram/client/methods/chats/get_chat_members_count.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class GetChatMembersCount(BaseClient):
|
||||
def get_chat_members_count(self, chat_id: int or str):
|
||||
"""Use this method to get the number of members in a chat.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
Returns:
|
||||
On success, an integer is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
return self.send(
|
||||
functions.messages.GetChats(
|
||||
id=[peer.chat_id]
|
||||
)
|
||||
).chats[0].participants_count
|
||||
elif isinstance(peer, types.InputPeerChannel):
|
||||
return self.send(
|
||||
functions.channels.GetFullChannel(
|
||||
channel=peer
|
||||
)
|
||||
).full_chat.participants_count
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
125
pyrogram/client/methods/chats/get_dialogs.py
Normal file
125
pyrogram/client/methods/chats/get_dialogs.py
Normal file
@ -0,0 +1,125 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient, utils
|
||||
|
||||
|
||||
class GetDialogs(BaseClient):
|
||||
def get_dialogs(self,
|
||||
offset_dialogs=None,
|
||||
limit: int = 100,
|
||||
pinned_only: bool = False):
|
||||
"""Use this method to get the user's dialogs
|
||||
|
||||
You can get up to 100 dialogs at once.
|
||||
|
||||
Args:
|
||||
limit (``str``, *optional*):
|
||||
Limits the number of dialogs to be retrieved.
|
||||
Defaults to 100
|
||||
|
||||
pinned_only (``bool``, *optional*):
|
||||
Pass True if you want to get only pinned dialogs.
|
||||
Defaults to False.
|
||||
|
||||
offset_dialogs (:obj:`Dialogs`):
|
||||
Pass the previous dialogs object to retrieve the next dialogs chunk starting from the last dialog.
|
||||
Defaults to None (start from the beginning).
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`Dialogs` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error`
|
||||
"""
|
||||
|
||||
if pinned_only:
|
||||
r = self.send(functions.messages.GetPinnedDialogs())
|
||||
else:
|
||||
offset_date = 0
|
||||
|
||||
if offset_dialogs:
|
||||
for dialog in reversed(offset_dialogs.dialogs):
|
||||
top_message = dialog.top_message
|
||||
|
||||
if top_message:
|
||||
message_date = top_message.date
|
||||
|
||||
if message_date:
|
||||
offset_date = message_date
|
||||
break
|
||||
|
||||
r = self.send(
|
||||
functions.messages.GetDialogs(
|
||||
offset_date=offset_date,
|
||||
offset_id=0,
|
||||
offset_peer=types.InputPeerEmpty(),
|
||||
limit=limit,
|
||||
hash=0,
|
||||
exclude_pinned=True
|
||||
)
|
||||
)
|
||||
|
||||
users = {i.id: i for i in r.users}
|
||||
chats = {i.id: i for i in r.chats}
|
||||
messages = {}
|
||||
|
||||
for message in r.messages:
|
||||
to_id = message.to_id
|
||||
|
||||
if isinstance(to_id, types.PeerUser):
|
||||
if message.out:
|
||||
chat_id = to_id.user_id
|
||||
else:
|
||||
chat_id = message.from_id
|
||||
elif isinstance(to_id, types.PeerChat):
|
||||
chat_id = -to_id.chat_id
|
||||
else:
|
||||
chat_id = int("-100" + str(to_id.channel_id))
|
||||
|
||||
messages[chat_id] = utils.parse_messages(self, message, users, chats)
|
||||
|
||||
dialogs = []
|
||||
|
||||
for dialog in r.dialogs:
|
||||
chat_id = dialog.peer
|
||||
|
||||
if isinstance(chat_id, types.PeerUser):
|
||||
chat_id = chat_id.user_id
|
||||
elif isinstance(chat_id, types.PeerChat):
|
||||
chat_id = -chat_id.chat_id
|
||||
else:
|
||||
chat_id = int("-100" + str(chat_id.channel_id))
|
||||
|
||||
dialogs.append(
|
||||
pyrogram.Dialog(
|
||||
chat=utils.parse_dialog_chat(dialog.peer, users, chats),
|
||||
top_message=messages.get(chat_id),
|
||||
unread_messages_count=dialog.unread_count,
|
||||
unread_mentions_count=dialog.unread_mentions_count,
|
||||
unread_mark=dialog.unread_mark,
|
||||
is_pinned=dialog.pinned
|
||||
)
|
||||
)
|
||||
|
||||
return pyrogram.Dialogs(
|
||||
total_count=getattr(r, "count", len(r.dialogs)),
|
||||
dialogs=dialogs
|
||||
)
|
@ -38,7 +38,6 @@ class KickChatMember(BaseClient):
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
user_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target user.
|
||||
|
62
pyrogram/client/methods/chats/pin_chat_message.py
Normal file
62
pyrogram/client/methods/chats/pin_chat_message.py
Normal file
@ -0,0 +1,62 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class PinChatMessage(BaseClient):
|
||||
def pin_chat_message(self, chat_id: int or str, message_id: int, disable_notification: bool = None):
|
||||
"""Use this method to pin a message in a supergroup or a channel.
|
||||
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in
|
||||
the supergroup or "can_edit_messages" admin right in the channel.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
message_id (``int``):
|
||||
Identifier of a message to pin.
|
||||
|
||||
disable_notification (``bool``):
|
||||
Pass True, if it is not necessary to send a notification to all chat members about the new pinned
|
||||
message. Notifications are always disabled in channels.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
functions.channels.UpdatePinnedMessage(
|
||||
channel=peer,
|
||||
id=message_id,
|
||||
silent=disable_notification or None
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChat):
|
||||
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
return True
|
@ -39,7 +39,6 @@ class PromoteChatMember(BaseClient):
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
user_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target user.
|
||||
|
@ -36,7 +36,6 @@ class RestrictChatMember(BaseClient):
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
user_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target user.
|
||||
|
56
pyrogram/client/methods/chats/set_chat_description.py
Normal file
56
pyrogram/client/methods/chats/set_chat_description.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetChatDescription(BaseClient):
|
||||
def set_chat_description(self, chat_id: int or str, description: str):
|
||||
"""Use this method to change the description of a supergroup or a channel.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
description (``str``):
|
||||
New chat description, 0-255 characters.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
functions.channels.EditAbout(
|
||||
channel=peer,
|
||||
about=description
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChat):
|
||||
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
return True
|
82
pyrogram/client/methods/chats/set_chat_photo.py
Normal file
82
pyrogram/client/methods/chats/set_chat_photo.py
Normal file
@ -0,0 +1,82 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from base64 import b64decode
|
||||
from struct import unpack
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetChatPhoto(BaseClient):
|
||||
def set_chat_photo(self, chat_id: int or str, photo: str):
|
||||
"""Use this method to set a new profile photo for the chat.
|
||||
Photos can't be changed for private chats.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
|
||||
setting is off.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
photo (``str``):
|
||||
New chat photo. You can pass a :class:`Photo` id or a file path to upload a new photo.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if os.path.exists(photo):
|
||||
photo = types.InputChatUploadedPhoto(file=self.save_file(photo))
|
||||
else:
|
||||
s = unpack("<qq", b64decode(photo + "=" * (-len(photo) % 4), "-_"))
|
||||
|
||||
photo = types.InputChatPhoto(
|
||||
id=types.InputPhoto(
|
||||
id=s[0],
|
||||
access_hash=s[1]
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
self.send(
|
||||
functions.messages.EditChatPhoto(
|
||||
chat_id=peer.chat_id,
|
||||
photo=photo
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
functions.channels.EditPhoto(
|
||||
channel=peer,
|
||||
photo=photo
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
return True
|
66
pyrogram/client/methods/chats/set_chat_title.py
Normal file
66
pyrogram/client/methods/chats/set_chat_title.py
Normal file
@ -0,0 +1,66 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetChatTitle(BaseClient):
|
||||
def set_chat_title(self, chat_id: int or str, title: str):
|
||||
"""Use this method to change the title of a chat.
|
||||
Titles can't be changed for private chats.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
|
||||
setting is off.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
title (``str``):
|
||||
New chat title, 1-255 characters.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
self.send(
|
||||
functions.messages.EditChatTitle(
|
||||
chat_id=peer.chat_id,
|
||||
title=title
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
functions.channels.EditTitle(
|
||||
channel=peer,
|
||||
title=title
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
return True
|
@ -31,7 +31,6 @@ class UnbanChatMember(BaseClient):
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
user_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target user.
|
||||
|
54
pyrogram/client/methods/chats/unpin_chat_message.py
Normal file
54
pyrogram/client/methods/chats/unpin_chat_message.py
Normal file
@ -0,0 +1,54 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class UnpinChatMessage(BaseClient):
|
||||
def unpin_chat_message(self, chat_id: int or str):
|
||||
"""Use this method to unpin a message in a supergroup or a channel.
|
||||
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin
|
||||
right in the supergroup or "can_edit_messages" admin right in the channel.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
functions.channels.UpdatePinnedMessage(
|
||||
channel=peer,
|
||||
id=0
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChat):
|
||||
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
return True
|
@ -18,16 +18,17 @@
|
||||
|
||||
from .delete_messages import DeleteMessages
|
||||
from .edit_message_caption import EditMessageCaption
|
||||
from .edit_message_media import EditMessageMedia
|
||||
from .edit_message_reply_markup import EditMessageReplyMarkup
|
||||
from .edit_message_text import EditMessageText
|
||||
from .forward_messages import ForwardMessages
|
||||
from .get_history import GetHistory
|
||||
from .get_messages import GetMessages
|
||||
from .send_animation import SendAnimation
|
||||
from .send_audio import SendAudio
|
||||
from .send_chat_action import SendChatAction
|
||||
from .send_contact import SendContact
|
||||
from .send_document import SendDocument
|
||||
from .send_gif import SendGIF
|
||||
from .send_location import SendLocation
|
||||
from .send_media_group import SendMediaGroup
|
||||
from .send_message import SendMessage
|
||||
@ -43,6 +44,7 @@ class Messages(
|
||||
DeleteMessages,
|
||||
EditMessageCaption,
|
||||
EditMessageReplyMarkup,
|
||||
EditMessageMedia,
|
||||
EditMessageText,
|
||||
ForwardMessages,
|
||||
GetHistory,
|
||||
@ -51,7 +53,7 @@ class Messages(
|
||||
SendChatAction,
|
||||
SendContact,
|
||||
SendDocument,
|
||||
SendGIF,
|
||||
SendAnimation,
|
||||
SendLocation,
|
||||
SendMediaGroup,
|
||||
SendMessage,
|
||||
|
@ -38,7 +38,6 @@ class DeleteMessages(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
message_ids (``iterable``):
|
||||
A list of Message identifiers to delete or a single message id.
|
||||
|
@ -34,7 +34,6 @@ class EditMessageCaption(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
message_id (``int``):
|
||||
Message identifier in the chat specified in chat_id.
|
||||
|
312
pyrogram/client/methods/messages/edit_message_media.py
Normal file
312
pyrogram/client/methods/messages/edit_message_media.py
Normal file
@ -0,0 +1,312 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.errors import FileIdInvalid
|
||||
from pyrogram.client.ext import BaseClient, utils
|
||||
from pyrogram.client.types import (
|
||||
InputMediaPhoto, InputMediaVideo, InputMediaAudio,
|
||||
InputMediaAnimation, InputMediaDocument
|
||||
)
|
||||
|
||||
|
||||
class EditMessageMedia(BaseClient):
|
||||
def edit_message_media(self,
|
||||
chat_id: int or str,
|
||||
message_id: int,
|
||||
media,
|
||||
reply_markup=None):
|
||||
style = self.html if media.parse_mode.lower() == "html" else self.markdown
|
||||
caption = media.caption
|
||||
|
||||
if isinstance(media, InputMediaPhoto):
|
||||
if os.path.exists(media.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedPhoto(
|
||||
file=self.save_file(media.media)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
media = types.InputMediaPhoto(
|
||||
id=types.InputPhoto(
|
||||
id=media.photo.id,
|
||||
access_hash=media.photo.access_hash
|
||||
)
|
||||
)
|
||||
elif media.media.startswith("http"):
|
||||
media = types.InputMediaPhotoExternal(
|
||||
url=media.media
|
||||
)
|
||||
else:
|
||||
try:
|
||||
decoded = utils.decode(media.media)
|
||||
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||
unpacked = struct.unpack(fmt, decoded)
|
||||
except (AssertionError, binascii.Error, struct.error):
|
||||
raise FileIdInvalid from None
|
||||
else:
|
||||
if unpacked[0] != 2:
|
||||
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||
|
||||
if media_type:
|
||||
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||
else:
|
||||
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||
|
||||
media = types.InputMediaPhoto(
|
||||
id=types.InputPhoto(
|
||||
id=unpacked[2],
|
||||
access_hash=unpacked[3]
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(media, InputMediaVideo):
|
||||
if os.path.exists(media.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeVideo(
|
||||
supports_streaming=media.supports_streaming or None,
|
||||
duration=media.duration,
|
||||
w=media.width,
|
||||
h=media.height
|
||||
),
|
||||
types.DocumentAttributeFilename(os.path.basename(media.media))
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=media.document.id,
|
||||
access_hash=media.document.access_hash
|
||||
)
|
||||
)
|
||||
elif media.media.startswith("http"):
|
||||
media = types.InputMediaDocumentExternal(
|
||||
url=media.media
|
||||
)
|
||||
else:
|
||||
try:
|
||||
decoded = utils.decode(media.media)
|
||||
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||
unpacked = struct.unpack(fmt, decoded)
|
||||
except (AssertionError, binascii.Error, struct.error):
|
||||
raise FileIdInvalid from None
|
||||
else:
|
||||
if unpacked[0] != 4:
|
||||
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||
|
||||
if media_type:
|
||||
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||
else:
|
||||
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=unpacked[2],
|
||||
access_hash=unpacked[3]
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(media, InputMediaAudio):
|
||||
if os.path.exists(media.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + media.media.split(".")[-1], "audio/mpeg"),
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeAudio(
|
||||
duration=media.duration,
|
||||
performer=media.performer,
|
||||
title=media.title
|
||||
),
|
||||
types.DocumentAttributeFilename(os.path.basename(media.media))
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=media.document.id,
|
||||
access_hash=media.document.access_hash
|
||||
)
|
||||
)
|
||||
elif media.media.startswith("http"):
|
||||
media = types.InputMediaDocumentExternal(
|
||||
url=media.media
|
||||
)
|
||||
else:
|
||||
try:
|
||||
decoded = utils.decode(media.media)
|
||||
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||
unpacked = struct.unpack(fmt, decoded)
|
||||
except (AssertionError, binascii.Error, struct.error):
|
||||
raise FileIdInvalid from None
|
||||
else:
|
||||
if unpacked[0] != 9:
|
||||
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||
|
||||
if media_type:
|
||||
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||
else:
|
||||
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=unpacked[2],
|
||||
access_hash=unpacked[3]
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(media, InputMediaAnimation):
|
||||
if os.path.exists(media.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeVideo(
|
||||
supports_streaming=True,
|
||||
duration=media.duration,
|
||||
w=media.width,
|
||||
h=media.height
|
||||
),
|
||||
types.DocumentAttributeFilename(os.path.basename(media.media)),
|
||||
types.DocumentAttributeAnimated()
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=media.document.id,
|
||||
access_hash=media.document.access_hash
|
||||
)
|
||||
)
|
||||
elif media.media.startswith("http"):
|
||||
media = types.InputMediaDocumentExternal(
|
||||
url=media.media
|
||||
)
|
||||
else:
|
||||
try:
|
||||
decoded = utils.decode(media.media)
|
||||
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||
unpacked = struct.unpack(fmt, decoded)
|
||||
except (AssertionError, binascii.Error, struct.error):
|
||||
raise FileIdInvalid from None
|
||||
else:
|
||||
if unpacked[0] != 10:
|
||||
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||
|
||||
if media_type:
|
||||
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||
else:
|
||||
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=unpacked[2],
|
||||
access_hash=unpacked[3]
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(media, InputMediaDocument):
|
||||
if os.path.exists(media.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + media.media.split(".")[-1], "text/plain"),
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeFilename(os.path.basename(media.media))
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=media.document.id,
|
||||
access_hash=media.document.access_hash
|
||||
)
|
||||
)
|
||||
elif media.media.startswith("http"):
|
||||
media = types.InputMediaDocumentExternal(
|
||||
url=media.media
|
||||
)
|
||||
else:
|
||||
try:
|
||||
decoded = utils.decode(media.media)
|
||||
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||
unpacked = struct.unpack(fmt, decoded)
|
||||
except (AssertionError, binascii.Error, struct.error):
|
||||
raise FileIdInvalid from None
|
||||
else:
|
||||
if unpacked[0] not in (5, 10):
|
||||
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||
|
||||
if media_type:
|
||||
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||
else:
|
||||
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
id=unpacked[2],
|
||||
access_hash=unpacked[3]
|
||||
)
|
||||
)
|
||||
|
||||
r = self.send(
|
||||
functions.messages.EditMessage(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
id=message_id,
|
||||
reply_markup=reply_markup.write() if reply_markup else None,
|
||||
media=media,
|
||||
**style.parse(caption)
|
||||
)
|
||||
)
|
||||
|
||||
for i in r.updates:
|
||||
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
|
||||
return utils.parse_messages(
|
||||
self, i.message,
|
||||
{i.id: i for i in r.users},
|
||||
{i.id: i for i in r.chats}
|
||||
)
|
@ -32,7 +32,6 @@ class EditMessageReplyMarkup(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
message_id (``int``):
|
||||
Message identifier in the chat specified in chat_id.
|
||||
|
@ -35,7 +35,6 @@ class EditMessageText(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
message_id (``int``):
|
||||
Message identifier in the chat specified in chat_id.
|
||||
|
@ -33,13 +33,11 @@ class ForwardMessages(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
from_chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the source chat where the original message was sent.
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
message_ids (``iterable``):
|
||||
A list of Message identifiers in the chat specified in *from_chat_id* or a single message id.
|
||||
|
@ -37,7 +37,6 @@ class GetHistory(BaseClient):
|
||||
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).
|
||||
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||
|
||||
offset (``int``, *optional*)
|
||||
Sequential number of the first message to be returned.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user