mirror of
https://github.com/Mayuri-Chan/pyrofork.git
synced 2025-12-30 12:24:52 +00:00
Compare commits
116 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c25bc05fb3 | ||
|
|
b1b781eda8 | ||
|
|
973d9df40e | ||
|
|
d5e86f11e7 | ||
|
|
e0487e557d | ||
|
|
eda14b667c | ||
|
|
803fd63a2f | ||
|
|
5213ddbffa | ||
|
|
bf66a1e439 | ||
|
|
903da76d6d | ||
|
|
8272c706a6 | ||
|
|
c76e9263dd | ||
|
|
e45001ca8c | ||
|
|
6a17d55e66 | ||
|
|
be5eacb998 | ||
|
|
575f88e97e | ||
|
|
a175b33d27 | ||
|
|
84a41e9aa2 | ||
|
|
bafef3d71e | ||
|
|
0280fc2572 | ||
|
|
89feb4a4d8 | ||
|
|
5bc419ce2c | ||
|
|
955db61bc3 | ||
|
|
b27d18c640 | ||
|
|
578b438804 | ||
|
|
c646595adb | ||
|
|
91ff2dc82d | ||
|
|
c3eddf234c | ||
|
|
fadd6bc147 | ||
|
|
ff4ee9dae8 | ||
|
|
c0d9564843 | ||
|
|
2378fb7800 | ||
|
|
5c78995343 | ||
|
|
344256d92b | ||
|
|
08248222bb | ||
|
|
9bb83e9319 | ||
|
|
c35e60de94 | ||
|
|
5d5e4b4845 | ||
|
|
1cfad73e95 | ||
|
|
664b525530 | ||
|
|
1d4948309f | ||
|
|
caf80f239b | ||
|
|
d5b2a76fc6 | ||
|
|
f38d90cc0a | ||
|
|
7a58c865b5 | ||
|
|
9966bd92a5 | ||
|
|
2cd117f301 | ||
|
|
4401c62244 | ||
|
|
2afbe7f4fd | ||
|
|
66c7d64b6b | ||
|
|
cbbd0e0dd2 | ||
|
|
99e3f3e317 | ||
|
|
ab1dde5f79 | ||
|
|
252a49332d | ||
|
|
d398b5b29c | ||
|
|
8940c7d1f6 | ||
|
|
3163030574 | ||
|
|
cb7ba4f821 | ||
|
|
cb60c6ae8d | ||
|
|
84b4d2181b | ||
|
|
ab7ab16356 | ||
|
|
6331a5500e | ||
|
|
fbe56d5426 | ||
|
|
1d113f8aa4 | ||
|
|
034a4d6041 | ||
|
|
42a2f04d8e | ||
|
|
f55d75d3bb | ||
|
|
c484e82810 | ||
|
|
30822dabff | ||
|
|
3a88297a9a | ||
|
|
231f1a1620 | ||
|
|
0f60e05fce | ||
|
|
e39fdcca0e | ||
|
|
00fb071215 | ||
|
|
609d8985d4 | ||
|
|
e15e3d7d50 | ||
|
|
b1354d5579 | ||
|
|
2a8a01aeb5 | ||
|
|
bec44280a4 | ||
|
|
41b771f4bf | ||
|
|
d91b933715 | ||
|
|
b2158f702a | ||
|
|
97f0ecc7c9 | ||
|
|
b64d33dca0 | ||
|
|
482798c2fc | ||
|
|
64177b533c | ||
|
|
3c0e86a167 | ||
|
|
09ad827374 | ||
|
|
94c589ed43 | ||
|
|
77cfaa0ff4 | ||
|
|
28307ca58e | ||
|
|
65b045ff2d | ||
|
|
b865512c68 | ||
|
|
b0ac808f2e | ||
|
|
3e219771bd | ||
|
|
aedade2ff2 | ||
|
|
8428de1722 | ||
|
|
85184be318 | ||
|
|
d89b083bf0 | ||
|
|
ede9af3e00 | ||
|
|
abf1b2fece | ||
|
|
b038890745 | ||
|
|
e0b7576418 | ||
|
|
86883a3b91 | ||
|
|
e38ceb08cc | ||
|
|
b76bf48862 | ||
|
|
9f32305c3a | ||
|
|
6edc4256c3 | ||
|
|
a1aa281614 | ||
|
|
00520678f6 | ||
|
|
f22cc34c9a | ||
|
|
9b92492553 | ||
|
|
c9e36cc150 | ||
|
|
eeb1338c48 | ||
|
|
115b9877b6 | ||
|
|
6f8aaa449c |
189 changed files with 6964 additions and 273 deletions
5
.github/FUNDING.yml
vendored
5
.github/FUNDING.yml
vendored
|
|
@ -1,3 +1,2 @@
|
|||
github: delivrance
|
||||
liberapay: delivrance
|
||||
open_collective: pyrogram
|
||||
ko_fi: wulan17
|
||||
custom: ["https://saweria.co/wulan17", "https://paypal.me/wulan17", "https://trakteer.id/wulan17"]
|
||||
|
|
|
|||
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "22:00"
|
||||
open-pull-requests-limit: 10
|
||||
18
.github/workflows/build-docs.yml
vendored
Normal file
18
.github/workflows/build-docs.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
name: Build-docs
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build
|
||||
run: bash build-docs.sh
|
||||
env:
|
||||
DOCS_KEY: ${{ secrets.DOCS_KEY }}
|
||||
41
.github/workflows/python-publish.yml
vendored
Normal file
41
.github/workflows/python-publish.yml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# This workflow will upload a Python Package using Twine when a release is created
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
|
||||
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
name: Upload Python Package
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install build twine
|
||||
- name: Build package
|
||||
run: python -m build
|
||||
- name: Publish package
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
||||
run: |
|
||||
twine upload dist/*
|
||||
6
Makefile
6
Makefile
|
|
@ -14,6 +14,10 @@ venv:
|
|||
$(PYTHON) -m pip install -U -r requirements.txt -r dev-requirements.txt
|
||||
@echo "Created venv with $$($(PYTHON) --version)"
|
||||
|
||||
clean-docs:
|
||||
$(RM) docs/build
|
||||
$(RM) docs/source/api/bound-methods docs/source/api/methods docs/source/api/types docs/source/telegram
|
||||
|
||||
clean-build:
|
||||
$(RM) *.egg-info build dist
|
||||
|
||||
|
|
@ -39,4 +43,4 @@ tag:
|
|||
|
||||
dtag:
|
||||
git tag -d $(TAG)
|
||||
git push origin -d $(TAG)
|
||||
git push origin -d $(TAG)
|
||||
|
|
|
|||
30
README.md
30
README.md
|
|
@ -1,28 +1,20 @@
|
|||
<p align="center">
|
||||
<a href="https://github.com/pyrogram/pyrogram">
|
||||
<img src="https://docs.pyrogram.org/_static/pyrogram.png" alt="Pyrogram" width="128">
|
||||
<a href="https://github.com/Mayuri-Chan/pyrofork">
|
||||
<img src="https://docs.pyrogram.org/_static/pyrogram.png" alt="PyroFork" width="128">
|
||||
</a>
|
||||
<br>
|
||||
<b>Telegram MTProto API Framework for Python</b>
|
||||
<br>
|
||||
<a href="https://pyrogram.org">
|
||||
<a href="https://pyrofork.mayuri.my.id">
|
||||
Homepage
|
||||
</a>
|
||||
•
|
||||
<a href="https://docs.pyrogram.org">
|
||||
<a href="https://pyrofork.mayuri.my.id">
|
||||
Documentation
|
||||
</a>
|
||||
•
|
||||
<a href="https://docs.pyrogram.org/releases">
|
||||
Releases
|
||||
</a>
|
||||
•
|
||||
<a href="https://t.me/pyrogram">
|
||||
News
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Pyrogram
|
||||
## PyroFork
|
||||
|
||||
> Elegant, modern and asynchronous Telegram MTProto API framework in Python for users and bots
|
||||
|
||||
|
|
@ -40,7 +32,7 @@ async def hello(client, message):
|
|||
app.run()
|
||||
```
|
||||
|
||||
**Pyrogram** is a modern, elegant and asynchronous [MTProto API](https://docs.pyrogram.org/topics/mtproto-vs-botapi)
|
||||
**PyroFork** is a modern, elegant and asynchronous [MTProto API](https://docs.pyrogram.org/topics/mtproto-vs-botapi)
|
||||
framework. It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot
|
||||
identity (bot API alternative) using Python.
|
||||
|
||||
|
|
@ -48,10 +40,6 @@ identity (bot API alternative) using Python.
|
|||
|
||||
If you'd like to support Pyrogram, you can consider:
|
||||
|
||||
- [Become a GitHub sponsor](https://github.com/sponsors/delivrance).
|
||||
- [Become a LiberaPay patron](https://liberapay.com/delivrance).
|
||||
- [Become an OpenCollective backer](https://opencollective.com/pyrogram).
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Ready**: Install Pyrogram with pip and start building your applications right away.
|
||||
|
|
@ -65,11 +53,11 @@ If you'd like to support Pyrogram, you can consider:
|
|||
### Installing
|
||||
|
||||
``` bash
|
||||
pip3 install pyrogram
|
||||
pip3 install pyrofork
|
||||
```
|
||||
|
||||
### Resources
|
||||
|
||||
- Check out the docs at https://docs.pyrogram.org to learn more about Pyrogram, get started right
|
||||
- Check out the docs at https://pyrofork.mayuri.my.id to learn more about PyroFork, get started right
|
||||
away and discover more in-depth material for building your client applications.
|
||||
- Join the official channel at https://t.me/pyrogram and stay tuned for news, updates and announcements.
|
||||
|
||||
|
|
|
|||
20
build-docs.sh
Normal file
20
build-docs.sh
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
export DOCS_KEY
|
||||
export VENV=$(pwd)/venv
|
||||
|
||||
make clean
|
||||
make clean-docs
|
||||
make venv
|
||||
make api
|
||||
"$VENV"/bin/pip install -r docs/requirements.txt
|
||||
cd compiler/docs && "$VENV"/bin/python compiler.py
|
||||
cd ../..
|
||||
"$VENV"/bin/sphinx-build -b html "docs/source" "docs/build/html" -j auto
|
||||
git clone https://wulan17:"$DOCS_KEY"@github.com/Mayuri-Chan/pyrofork-docs.git
|
||||
cp -r docs/build/html/* pyrofork-docs
|
||||
cd pyrofork-docs
|
||||
git config --local user.name "Mayuri-Chan"
|
||||
git config --local user.email "mayuri@mayuri.my.id"
|
||||
git add --all
|
||||
git commit -a -m "docs: Update docs $(date '+%Y-%m-%d | %H:%m:%S %p %Z')" --signoff
|
||||
git push -u origin --all
|
||||
|
|
@ -1,4 +1,28 @@
|
|||
// https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/Resources/tl/api.tl
|
||||
///////////////////////////////
|
||||
/////////////////// Layer cons
|
||||
///////////////////////////////
|
||||
|
||||
//invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
|
||||
//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
|
||||
//invokeWithLayer1#53835315 query:!X = X;
|
||||
//invokeWithLayer2#289dd1f6 query:!X = X;
|
||||
//invokeWithLayer3#b7475268 query:!X = X;
|
||||
//invokeWithLayer4#dea0d430 query:!X = X;
|
||||
//invokeWithLayer5#417a57ae query:!X = X;
|
||||
//invokeWithLayer6#3a64d54d query:!X = X;
|
||||
//invokeWithLayer7#a5be56d3 query:!X = X;
|
||||
//invokeWithLayer8#e9abd9fd query:!X = X;
|
||||
//invokeWithLayer9#76715a63 query:!X = X;
|
||||
//invokeWithLayer10#39620c41 query:!X = X;
|
||||
//invokeWithLayer11#a6b88fdf query:!X = X;
|
||||
//invokeWithLayer12#dda60d3c query:!X = X;
|
||||
//invokeWithLayer13#427c8ea2 query:!X = X;
|
||||
//invokeWithLayer14#2b9b08fa query:!X = X;
|
||||
//invokeWithLayer15#b4418b64 query:!X = X;
|
||||
//invokeWithLayer16#cf5f0987 query:!X = X;
|
||||
//invokeWithLayer17#50858a19 query:!X = X;
|
||||
//invokeWithLayer18#1c900537 query:!X = X;
|
||||
//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
|
||||
|
||||
///////////////////////////////
|
||||
///////// Main application API
|
||||
|
|
@ -11,11 +35,11 @@
|
|||
|
||||
// true#3fedd339 = True; // Not used
|
||||
|
||||
// vector#1cb5c415 {t:Type} # [ t ] = Vector t; // Parsed manually
|
||||
vector#1cb5c415 {t:Type} # [ t ] = Vector t;
|
||||
|
||||
// error#c4b9f9bb code:int text:string = Error; // Not used
|
||||
error#c4b9f9bb code:int text:string = Error;
|
||||
|
||||
// null#56730bcc = Null; // Parsed manually
|
||||
null#56730bcc = Null;
|
||||
|
||||
inputPeerEmpty#7f3b18ea = InputPeer;
|
||||
inputPeerSelf#7da07ec9 = InputPeer;
|
||||
|
|
@ -36,15 +60,15 @@ inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile
|
|||
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
|
||||
|
||||
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;
|
||||
inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
|
||||
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
|
||||
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true force_file:flags.4?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#33473058 flags:# id:InputDocument ttl_seconds:flags.0?int query:flags.1?string = InputMedia;
|
||||
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?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#33473058 flags:# spoiler:flags.2?true id:InputDocument ttl_seconds:flags.0?int query:flags.1?string = InputMedia;
|
||||
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
|
||||
inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
inputMediaInvoice#8eb5a6d5 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia;
|
||||
inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia;
|
||||
|
|
@ -52,7 +76,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> s
|
|||
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
||||
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#c642724e flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double = InputChatPhoto;
|
||||
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
|
||||
inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
|
||||
|
||||
inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
|
||||
|
|
@ -88,10 +112,10 @@ storage.fileMp4#b3cea0e4 = storage.FileType;
|
|||
storage.fileWebp#1081464c = storage.FileType;
|
||||
|
||||
userEmpty#d3bc4b7a id:long = User;
|
||||
user#8f97c628 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector<Username> = User;
|
||||
user#8f97c628 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector<Username> = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#82d1f706 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto;
|
||||
userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto;
|
||||
|
||||
userStatusEmpty#9d05049 = UserStatus;
|
||||
userStatusOnline#edb93949 expires:int = UserStatus;
|
||||
|
|
@ -106,8 +130,8 @@ chatForbidden#6592a1a7 id:long title:string = Chat;
|
|||
channel#83259464 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> = Chat;
|
||||
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
|
||||
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
|
||||
channelFull#f2355507 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions = ChatFull;
|
||||
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
|
||||
channelFull#f2355507 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions = ChatFull;
|
||||
|
||||
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
||||
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
||||
|
|
@ -124,11 +148,11 @@ message#38116ee0 flags:# out:flags.1?true mentioned:flags.4?true media_unread:fl
|
|||
messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message;
|
||||
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
|
||||
messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia;
|
||||
messageMediaUnsupported#9f84f49e = MessageMedia;
|
||||
messageMediaDocument#9cb070d7 flags:# nopremium:flags.3?true document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaDocument#9cb070d7 flags:# nopremium:flags.3?true spoiler:flags.4?true document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
|
||||
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
|
||||
messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
|
|
@ -156,7 +180,7 @@ messageActionPaymentSent#96163f56 flags:# recurring_init:flags.2?true recurring_
|
|||
messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
|
||||
messageActionScreenshotTaken#4792929b = MessageAction;
|
||||
messageActionCustomAction#fae69f56 message:string = MessageAction;
|
||||
messageActionBotAllowed#abe9affe domain:string = MessageAction;
|
||||
messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true domain:flags.0?string app:flags.2?BotApp = MessageAction;
|
||||
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
|
||||
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
|
||||
messageActionContactSignUp#f3f25f76 = MessageAction;
|
||||
|
|
@ -169,9 +193,13 @@ messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
|
|||
messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
|
||||
messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction;
|
||||
messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction;
|
||||
messageActionGiftPremium#aba0f5c6 currency:string amount:long months:int = MessageAction;
|
||||
messageActionGiftPremium#c83d6aec flags:# currency:string amount:long months:int crypto_currency:flags.0?string crypto_amount:flags.0?long = MessageAction;
|
||||
messageActionTopicCreate#d999256 flags:# title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction;
|
||||
messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction;
|
||||
messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
|
||||
messageActionRequestedPeer#fe77345d button_id:int peer:Peer = MessageAction;
|
||||
messageActionSetChatWallPaper#bc44a927 wallpaper:WallPaper = MessageAction;
|
||||
messageActionSetSameChatWallPaper#c0787d6d wallpaper:WallPaper = MessageAction;
|
||||
|
||||
dialog#d58a08c6 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 unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
|
||||
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
|
||||
|
|
@ -190,8 +218,9 @@ geoPointEmpty#1117dd5f = GeoPoint;
|
|||
geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint;
|
||||
|
||||
auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
|
||||
auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode;
|
||||
|
||||
auth.authorization#33fb7bb8 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int user:User = auth.Authorization;
|
||||
auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization;
|
||||
auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;
|
||||
|
||||
auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization;
|
||||
|
|
@ -222,7 +251,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason;
|
|||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||
|
||||
userFull#c4b1fc3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true id:long about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> = UserFull;
|
||||
userFull#93eadb53 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper = UserFull;
|
||||
|
||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||
|
||||
|
|
@ -280,7 +309,6 @@ updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction
|
|||
updateChatParticipants#7761198 participants:ChatParticipants = Update;
|
||||
updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update;
|
||||
updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector<Username> = Update;
|
||||
updateUserPhoto#f227868c user_id:long date:int photo:UserProfilePhoto previous:Bool = Update;
|
||||
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
|
||||
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
|
||||
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
|
||||
|
|
@ -361,7 +389,7 @@ updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<Gro
|
|||
updateGroupCall#14b24500 chat_id:long call:GroupCall = Update;
|
||||
updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update;
|
||||
updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
|
||||
updateChannelParticipant#985d3abb flags:# channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
|
||||
updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
|
||||
updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update;
|
||||
updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update;
|
||||
updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = Update;
|
||||
|
|
@ -381,6 +409,9 @@ updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?tru
|
|||
updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = Update;
|
||||
updateChannelPinnedTopic#192efbe3 flags:# pinned:flags.0?true channel_id:long topic_id:int = Update;
|
||||
updateChannelPinnedTopics#fe198602 flags:# channel_id:long order:flags.0?Vector<int> = Update;
|
||||
updateUser#20529438 user_id:long = Update;
|
||||
updateAutoSaveSettings#ec05b097 = Update;
|
||||
updateGroupInvitePrivacyForbidden#ccf08ad6 user_id:long = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
|
|
@ -407,7 +438,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 this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
|
||||
|
||||
config#232566ac flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true force_try_ipv6:flags.14?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 pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction = Config;
|
||||
config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?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 edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config;
|
||||
|
||||
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
|
||||
|
||||
|
|
@ -525,7 +556,7 @@ documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_strea
|
|||
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
|
||||
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
|
||||
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
|
||||
documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true alt:string stickerset:InputStickerSet = DocumentAttribute;
|
||||
documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute;
|
||||
|
||||
messages.stickersNotModified#f1749a22 = messages.Stickers;
|
||||
messages.stickers#30a6ec7e hash:long stickers:Vector<Document> = messages.Stickers;
|
||||
|
|
@ -588,7 +619,7 @@ keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
|
|||
keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton;
|
||||
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
|
||||
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
|
||||
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
|
||||
keyboardButtonSwitchInline#93b9fbb5 flags:# same_peer:flags.0?true text:string query:string peer_types:flags.1?Vector<InlineQueryPeerType> = KeyboardButton;
|
||||
keyboardButtonGame#50f41ccf text:string = KeyboardButton;
|
||||
keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
|
||||
keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
|
||||
|
|
@ -598,12 +629,13 @@ inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = Keyboard
|
|||
keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton;
|
||||
keyboardButtonWebView#13767230 text:string url:string = KeyboardButton;
|
||||
keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton;
|
||||
keyboardButtonRequestPeer#d0b468c text:string button_id:int peer_type:RequestPeerType = KeyboardButton;
|
||||
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
|
||||
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
|
||||
replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup;
|
||||
replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> placeholder:flags.3?string = ReplyMarkup;
|
||||
replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector<KeyboardButtonRow> placeholder:flags.3?string = ReplyMarkup;
|
||||
replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup;
|
||||
|
||||
messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity;
|
||||
|
|
@ -692,7 +724,7 @@ botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1
|
|||
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;
|
||||
|
||||
messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;
|
||||
messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;
|
||||
|
||||
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
|
||||
|
||||
|
|
@ -709,9 +741,10 @@ auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
|
|||
auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType;
|
||||
auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
|
||||
auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType;
|
||||
auth.sentCodeTypeEmailCode#5a159841 flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int next_phone_login_date:flags.2?int = auth.SentCodeType;
|
||||
auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType;
|
||||
auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType;
|
||||
auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType;
|
||||
auth.sentCodeTypeFirebaseSms#e57b1432 flags:# nonce:flags.0?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType;
|
||||
|
||||
messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;
|
||||
|
||||
|
|
@ -758,6 +791,7 @@ messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered>
|
|||
stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
|
||||
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = StickerSetCovered;
|
||||
stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered;
|
||||
|
||||
maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
|
||||
|
||||
|
|
@ -870,7 +904,7 @@ account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPas
|
|||
|
||||
shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption;
|
||||
|
||||
inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem;
|
||||
inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem;
|
||||
|
||||
inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
|
||||
|
||||
|
|
@ -929,7 +963,7 @@ channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = Channe
|
|||
channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionParticipantJoinByInvite#5cdada77 invite:ExportedChatInvite = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction;
|
||||
|
|
@ -1111,7 +1145,7 @@ statsURL#47a971e0 url:string = StatsURL;
|
|||
|
||||
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true = ChatAdminRights;
|
||||
|
||||
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true until_date:int = ChatBannedRights;
|
||||
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true until_date:int = ChatBannedRights;
|
||||
|
||||
inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
|
||||
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
|
||||
|
|
@ -1120,7 +1154,7 @@ inputWallPaperNoFile#967a462e id:long = InputWallPaper;
|
|||
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
||||
account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = account.WallPapers;
|
||||
|
||||
codeSettings#8a6469c2 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true logout_tokens:flags.6?Vector<bytes> = CodeSettings;
|
||||
codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true logout_tokens:flags.6?Vector<bytes> token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings;
|
||||
|
||||
wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
|
||||
|
||||
|
|
@ -1197,6 +1231,7 @@ payments.bankCardData#3e24e573 title:string open_urls:Vector<BankCardOpenUrl> =
|
|||
|
||||
dialogFilter#7438f7e8 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true id:int title:string emoticon:flags.25?string pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> exclude_peers:Vector<InputPeer> = DialogFilter;
|
||||
dialogFilterDefault#363293ae = DialogFilter;
|
||||
dialogFilterChatlist#d64a04a8 flags:# has_my_invites:flags.26?true id:int title:string emoticon:flags.25?string pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> = DialogFilter;
|
||||
|
||||
dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested;
|
||||
|
||||
|
|
@ -1218,6 +1253,8 @@ help.promoDataEmpty#98f6ac75 expires:int = help.PromoData;
|
|||
help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector<Chat> users:Vector<User> psa_type:flags.1?string psa_message:flags.2?string = help.PromoData;
|
||||
|
||||
videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize;
|
||||
videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector<int> = VideoSize;
|
||||
videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector<int> = VideoSize;
|
||||
|
||||
statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster;
|
||||
|
||||
|
|
@ -1266,6 +1303,7 @@ inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType;
|
|||
inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType;
|
||||
inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType;
|
||||
inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType;
|
||||
inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType;
|
||||
|
||||
messages.historyImport#1662af0b id:long = messages.HistoryImport;
|
||||
|
||||
|
|
@ -1273,7 +1311,7 @@ messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true
|
|||
|
||||
messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector<int> = messages.AffectedFoundMessages;
|
||||
|
||||
chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter;
|
||||
chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter;
|
||||
|
||||
messages.exportedChatInvites#bdc62dcc count:int invites:Vector<ExportedChatInvite> users:Vector<User> = messages.ExportedChatInvites;
|
||||
|
||||
|
|
@ -1310,7 +1348,7 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR
|
|||
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
||||
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
||||
|
||||
sponsoredMessage#3a836df8 flags:# recommended:flags.5?true show_peer_photo:flags.6?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
|
||||
sponsoredMessage#fc25b828 flags:# recommended:flags.5?true show_peer_photo:flags.6?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage;
|
||||
|
||||
messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
||||
messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages;
|
||||
|
|
@ -1342,10 +1380,7 @@ availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true re
|
|||
messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions;
|
||||
messages.availableReactions#768e3aad hash:int reactions:Vector<AvailableReaction> = messages.AvailableReactions;
|
||||
|
||||
messages.translateNoResult#67ca4737 = messages.TranslatedText;
|
||||
messages.translateResultText#a214f7d0 text:string = messages.TranslatedText;
|
||||
|
||||
messagePeerReaction#b156fe9c flags:# big:flags.0?true unread:flags.1?true peer_id:Peer reaction:Reaction = MessagePeerReaction;
|
||||
messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction;
|
||||
|
||||
groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel;
|
||||
|
||||
|
|
@ -1357,7 +1392,7 @@ attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;
|
|||
|
||||
attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;
|
||||
|
||||
attachMenuBot#c8aa2cd2 flags:# inactive:flags.0?true has_settings:flags.1?true bot_id:long short_name:string peer_types:Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
|
||||
attachMenuBot#c8aa2cd2 flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true bot_id:long short_name:string peer_types:Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
|
||||
|
||||
attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
|
||||
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;
|
||||
|
|
@ -1400,7 +1435,7 @@ messages.transcribedAudio#93752c52 flags:# pending:flags.0?true transcription_id
|
|||
|
||||
help.premiumPromo#5334759c status_text:string status_entities:Vector<MessageEntity> video_sections:Vector<string> videos:Vector<Document> period_options:Vector<PremiumSubscriptionOption> users:Vector<User> = help.PremiumPromo;
|
||||
|
||||
inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true = InputStorePaymentPurpose;
|
||||
inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose;
|
||||
inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose;
|
||||
|
||||
premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption;
|
||||
|
|
@ -1436,7 +1471,7 @@ emailVerificationApple#96d074fd token:string = EmailVerification;
|
|||
account.emailVerified#2b96cd1b email:string = account.EmailVerified;
|
||||
account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified;
|
||||
|
||||
premiumSubscriptionOption#b6f11ebe flags:# current:flags.1?true can_purchase_upgrade:flags.2?true months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption;
|
||||
premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption;
|
||||
|
||||
sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;
|
||||
|
||||
|
|
@ -1456,6 +1491,60 @@ defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL;
|
|||
|
||||
exportedContactToken#41bf109b url:string expires:int = ExportedContactToken;
|
||||
|
||||
requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType;
|
||||
requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType;
|
||||
requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType;
|
||||
|
||||
emojiListNotModified#481eadfa = EmojiList;
|
||||
emojiList#7a1e11d1 hash:long document_id:Vector<long> = EmojiList;
|
||||
|
||||
emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector<string> = EmojiGroup;
|
||||
|
||||
messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups;
|
||||
messages.emojiGroups#881fb94b hash:int groups:Vector<EmojiGroup> = messages.EmojiGroups;
|
||||
|
||||
textWithEntities#751f3146 text:string entities:Vector<MessageEntity> = TextWithEntities;
|
||||
|
||||
messages.translateResult#33db32f8 result:Vector<TextWithEntities> = messages.TranslatedText;
|
||||
|
||||
autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings;
|
||||
|
||||
autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException;
|
||||
|
||||
account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector<AutoSaveException> chats:Vector<Chat> users:Vector<User> = account.AutoSaveSettings;
|
||||
|
||||
help.appConfigNotModified#7cde641d = help.AppConfig;
|
||||
help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig;
|
||||
|
||||
inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp;
|
||||
inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp;
|
||||
|
||||
botAppNotModified#5da674b7 = BotApp;
|
||||
botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp;
|
||||
|
||||
messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true app:BotApp = messages.BotApp;
|
||||
|
||||
appWebViewResultUrl#3c1b4f0d url:string = AppWebViewResult;
|
||||
|
||||
inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView;
|
||||
|
||||
readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate;
|
||||
|
||||
inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist;
|
||||
|
||||
exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector<Peer> = ExportedChatlistInvite;
|
||||
|
||||
chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite;
|
||||
|
||||
chatlists.exportedInvites#10ab6dc7 invites:Vector<ExportedChatlistInvite> chats:Vector<Chat> users:Vector<User> = chatlists.ExportedInvites;
|
||||
|
||||
chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector<Peer> already_peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = chatlists.ChatlistInvite;
|
||||
chatlists.chatlistInvite#1dcd839d flags:# title:string emoticon:flags.0?string peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = chatlists.ChatlistInvite;
|
||||
|
||||
chatlists.chatlistUpdates#93bd878d missing_peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = chatlists.ChatlistUpdates;
|
||||
|
||||
bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
|
|
@ -1486,6 +1575,8 @@ auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
|
|||
auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
|
||||
auth.checkRecoveryPassword#d36bf79 code:string = Bool;
|
||||
auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization;
|
||||
auth.requestFirebaseSms#89464b50 flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string ios_push_secret:flags.1?string = Bool;
|
||||
auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode;
|
||||
|
||||
account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<long> = Bool;
|
||||
account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector<long> = Bool;
|
||||
|
|
@ -1536,7 +1627,7 @@ account.getContactSignUpNotification#9f07c728 = Bool;
|
|||
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
|
||||
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
|
||||
account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
|
||||
account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
|
||||
account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
|
||||
account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool;
|
||||
account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool;
|
||||
account.resetWallPapers#bb3b9804 = Bool;
|
||||
|
|
@ -1569,6 +1660,11 @@ account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses;
|
|||
account.clearRecentEmojiStatuses#18201aae = Bool;
|
||||
account.reorderUsernames#ef500eab order:Vector<string> = Bool;
|
||||
account.toggleUsername#58d6b376 username:string active:Bool = Bool;
|
||||
account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList;
|
||||
account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList;
|
||||
account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings;
|
||||
account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool;
|
||||
account.deleteAutoSaveExceptions#53bc0020 = Bool;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
||||
|
|
@ -1651,7 +1747,7 @@ messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Do
|
|||
messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
|
||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
||||
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
||||
messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool;
|
||||
messages.sendInlineBotResult#d3fbdccb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int top_msg_id:flags.9?int random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
|
||||
|
|
@ -1740,7 +1836,7 @@ messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true peer:Inp
|
|||
messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates;
|
||||
messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer;
|
||||
messages.setChatTheme#e63be13f peer:InputPeer emoticon:string = Updates;
|
||||
messages.getMessageReadParticipants#2c6f97b7 peer:InputPeer msg_id:int = Vector<long>;
|
||||
messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector<ReadParticipantDate>;
|
||||
messages.getSearchResultsCalendar#49f0bde9 peer:InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar;
|
||||
messages.getSearchResultsPositions#6e9583a3 peer:InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions;
|
||||
messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates;
|
||||
|
|
@ -1753,16 +1849,16 @@ messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction
|
|||
messages.setChatAvailableReactions#feb16771 peer:InputPeer available_reactions:ChatReactions = Updates;
|
||||
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
||||
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
||||
messages.translateText#24ce6dee flags:# peer:flags.0?InputPeer msg_id:flags.0?int text:flags.1?string from_lang:flags.2?string to_lang:string = messages.TranslatedText;
|
||||
messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector<int> text:flags.1?Vector<TextWithEntities> to_lang:string = messages.TranslatedText;
|
||||
messages.getUnreadReactions#3223495b flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
|
||||
messages.readReactions#54aa7f8e flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
|
||||
messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages;
|
||||
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
|
||||
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
|
||||
messages.toggleBotInAttachMenu#1aee33af bot:InputUser enabled:Bool = Bool;
|
||||
messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool;
|
||||
messages.requestWebView#178b480b flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to_msg_id:flags.0?int top_msg_id:flags.9?int send_as:flags.13?InputPeer = WebViewResult;
|
||||
messages.prolongWebView#7ff34309 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to_msg_id:flags.0?int top_msg_id:flags.9?int send_as:flags.13?InputPeer = Bool;
|
||||
messages.requestSimpleWebView#299bec8e flags:# bot:InputUser url:string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult;
|
||||
messages.requestSimpleWebView#299bec8e flags:# from_switch_webview:flags.1?true bot:InputUser url:string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult;
|
||||
messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent;
|
||||
messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates;
|
||||
messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio;
|
||||
|
|
@ -1777,15 +1873,25 @@ messages.clearRecentReactions#9dfeefb4 = Bool;
|
|||
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
|
||||
messages.setDefaultHistoryTTL#9eb51445 period:int = Bool;
|
||||
messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL;
|
||||
messages.sendBotRequestedPeer#fe38d01b peer:InputPeer msg_id:int button_id:int requested_peer:InputPeer = Updates;
|
||||
messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups;
|
||||
messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups;
|
||||
messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups;
|
||||
messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList;
|
||||
messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool;
|
||||
messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp;
|
||||
messages.requestAppWebView#8c5a3b3c flags:# write_allowed:flags.0?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = AppWebViewResult;
|
||||
messages.setChatWallPaper#8ffacae1 flags:# peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
|
||||
|
||||
photos.updateProfilePhoto#72d4742c id:InputPhoto = photos.Photo;
|
||||
photos.uploadProfilePhoto#89f30f69 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double = photos.Photo;
|
||||
photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo;
|
||||
photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo;
|
||||
photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
|
||||
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
|
||||
photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo;
|
||||
|
||||
upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
|
||||
upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File;
|
||||
|
|
@ -1808,7 +1914,7 @@ help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
|
|||
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
|
||||
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
|
||||
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
|
||||
help.getAppConfig#98914110 = JSONValue;
|
||||
help.getAppConfig#61e3f854 hash:int = help.AppConfig;
|
||||
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
|
||||
help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
|
||||
help.getSupportName#d360e72c = help.SupportName;
|
||||
|
|
@ -1828,7 +1934,7 @@ channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipant
|
|||
channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant;
|
||||
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
|
||||
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
|
||||
channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates;
|
||||
channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates;
|
||||
channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates;
|
||||
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
|
||||
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
|
||||
|
|
@ -1874,6 +1980,7 @@ channels.deleteTopicHistory#34435f2d channel:InputChannel top_msg_id:int = messa
|
|||
channels.reorderPinnedForumTopics#2950a18f flags:# force:flags.0?true channel:InputChannel order:Vector<int> = Updates;
|
||||
channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates;
|
||||
channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool;
|
||||
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
|
||||
|
||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
|
|
@ -1884,6 +1991,10 @@ bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool;
|
|||
bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton;
|
||||
bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool;
|
||||
bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool;
|
||||
bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool;
|
||||
bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo;
|
||||
bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector<string> = Bool;
|
||||
bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool;
|
||||
|
||||
payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm;
|
||||
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
||||
|
|
@ -1897,13 +2008,16 @@ payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaym
|
|||
payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates;
|
||||
payments.canPurchasePremium#9fc19eb6 purpose:InputStorePaymentPurpose = Bool;
|
||||
|
||||
stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true videos:flags.4?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
|
||||
stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true videos:flags.4?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
|
||||
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
|
||||
stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet;
|
||||
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
|
||||
stickers.setStickerSetThumb#9a364e30 stickerset:InputStickerSet thumb:InputDocument = messages.StickerSet;
|
||||
stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet;
|
||||
stickers.checkShortName#284b3639 short_name:string = Bool;
|
||||
stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName;
|
||||
stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet;
|
||||
stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet;
|
||||
stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool;
|
||||
|
||||
phone.getCallConfig#55451fa9 = DataJSON;
|
||||
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
|
|
@ -1944,7 +2058,6 @@ langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
|
|||
langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;
|
||||
|
||||
folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
|
||||
folders.deleteFolder#1c295881 folder_id:int = Updates;
|
||||
|
||||
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
|
||||
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
|
||||
|
|
@ -1952,4 +2065,16 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
|
|||
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
|
||||
|
||||
// LAYER 150
|
||||
chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector<InputPeer> = chatlists.ExportedChatlistInvite;
|
||||
chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool;
|
||||
chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector<InputPeer> = ExportedChatlistInvite;
|
||||
chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites;
|
||||
chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite;
|
||||
chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector<InputPeer> = Updates;
|
||||
chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates;
|
||||
chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector<InputPeer> = Updates;
|
||||
chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool;
|
||||
chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector<Peer>;
|
||||
chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector<InputPeer> = Updates;
|
||||
|
||||
// LAYER 158
|
||||
|
|
@ -219,6 +219,8 @@ def pyrogram_api():
|
|||
get_chat_members_count
|
||||
get_dialogs
|
||||
get_dialogs_count
|
||||
get_forum_topics
|
||||
get_forum_topics_by_id
|
||||
set_chat_username
|
||||
get_nearby_chats
|
||||
archive_chats
|
||||
|
|
@ -237,6 +239,16 @@ def pyrogram_api():
|
|||
get_send_as_chats
|
||||
set_send_as_chat
|
||||
set_chat_protected_content
|
||||
close_forum_topic
|
||||
close_general_topic
|
||||
create_forum_topic
|
||||
delete_forum_topic
|
||||
edit_forum_topic
|
||||
edit_general_topic
|
||||
hide_general_topic
|
||||
reopen_forum_topic
|
||||
reopen_general_topic
|
||||
unhide_general_topic
|
||||
""",
|
||||
users="""
|
||||
Users
|
||||
|
|
@ -254,6 +266,12 @@ def pyrogram_api():
|
|||
get_default_emoji_statuses
|
||||
set_emoji_status
|
||||
""",
|
||||
stickers="""
|
||||
Stickers
|
||||
add_sticker_to_set
|
||||
create_sticker_set
|
||||
get_sticker_set
|
||||
""",
|
||||
invite_links="""
|
||||
Invite Links
|
||||
get_chat_invite_link
|
||||
|
|
@ -385,9 +403,13 @@ def pyrogram_api():
|
|||
ChatMemberUpdated
|
||||
ChatJoinRequest
|
||||
ChatJoiner
|
||||
ChatJoinedByRequest
|
||||
Dialog
|
||||
Restriction
|
||||
EmojiStatus
|
||||
ForumTopic
|
||||
PeerUser
|
||||
PeerChannel
|
||||
""",
|
||||
messages_media="""
|
||||
Messages & Media
|
||||
|
|
@ -405,6 +427,7 @@ def pyrogram_api():
|
|||
Location
|
||||
Venue
|
||||
Sticker
|
||||
StickerSet
|
||||
Game
|
||||
WebPage
|
||||
Poll
|
||||
|
|
@ -418,6 +441,12 @@ def pyrogram_api():
|
|||
WebAppData
|
||||
MessageReactions
|
||||
ChatReactions
|
||||
ForumTopicCreated
|
||||
ForumTopicEdited
|
||||
ForumTopicClosed
|
||||
ForumTopicReopened
|
||||
GeneralTopicHidden
|
||||
GeneralTopicUnhidden
|
||||
""",
|
||||
bot_keyboards="""
|
||||
Bot keyboards
|
||||
|
|
|
|||
13
compiler/docs/template/methods.rst
vendored
13
compiler/docs/template/methods.rst
vendored
|
|
@ -73,6 +73,19 @@ Chats
|
|||
|
||||
{chats}
|
||||
|
||||
Stickers
|
||||
-----
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
{stickers}
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{stickers}
|
||||
|
||||
Users
|
||||
-----
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ BOT_INLINE_DISABLED The inline feature of the bot is disabled
|
|||
BOT_INVALID This is not a valid bot
|
||||
BOT_METHOD_INVALID The method can't be used by bots
|
||||
BOT_MISSING This method can only be run by a bot
|
||||
BOT_ONESIDE_NOT_AVAIL Bots can't pin messages for one side only in private chats
|
||||
BOT_PAYMENTS_DISABLED This method can only be run by a bot
|
||||
BOT_POLLS_DISABLED Sending polls by bots has been disabled
|
||||
BOT_RESPONSE_TIMEOUT The bot did not answer to the callback query in time
|
||||
|
|
@ -38,6 +39,7 @@ BROADCAST_REQUIRED The request can only be used with a channel
|
|||
BUTTON_DATA_INVALID The button callback data is invalid or too large
|
||||
BUTTON_TYPE_INVALID The type of one of the buttons you provided is invalid
|
||||
BUTTON_URL_INVALID The button url is invalid
|
||||
BUTTON_USER_PRIVACY_RESTRICTED The privacy settings of the user specified in a keyboard button do not allow creating such button
|
||||
CALL_ALREADY_ACCEPTED The call is already accepted
|
||||
CALL_ALREADY_DECLINED The call is already declined
|
||||
CALL_PEER_INVALID The provided call peer object is invalid
|
||||
|
|
@ -100,6 +102,7 @@ ENCRYPTION_ALREADY_DECLINED The secret chat is already declined
|
|||
ENCRYPTION_DECLINED The secret chat was declined
|
||||
ENCRYPTION_ID_INVALID The provided secret chat id is invalid
|
||||
ENTITIES_TOO_LONG The entity provided contains data that is too long, or you passed too many entities to this message
|
||||
ENTITY_BOUNDS_INVALID The message entity bounds are invalid
|
||||
ENTITY_MENTION_USER_INVALID The mentioned entity is not an user
|
||||
ERROR_TEXT_EMPTY The provided error message is empty
|
||||
EXPIRE_DATE_INVALID The expiration date is invalid
|
||||
|
|
@ -153,6 +156,7 @@ INPUT_USER_DEACTIVATED The target user has been deleted/deactivated
|
|||
INVITE_HASH_EMPTY The invite hash is empty
|
||||
INVITE_HASH_EXPIRED The chat invite link is no longer valid
|
||||
INVITE_HASH_INVALID The invite link hash is invalid
|
||||
INVITE_REQUEST_SENT The request to join this chat or channel has been successfully sent
|
||||
INVITE_REVOKED_MISSING The action required a chat invite link to be revoked first
|
||||
LANG_PACK_INVALID The provided language pack is invalid
|
||||
LASTNAME_INVALID The last name is invalid
|
||||
|
|
@ -296,8 +300,8 @@ STICKER_INVALID The provided sticker is invalid
|
|||
STICKER_PNG_DIMENSIONS The sticker png dimensions are invalid
|
||||
STICKER_PNG_NOPNG Stickers must be png files but the provided image was not a png
|
||||
STICKER_TGS_NOTGS A tgs sticker file was expected, but something else was provided
|
||||
STICKER_VIDEO_NOWEBM A webm video file was expected, but something else was provided
|
||||
STICKER_THUMB_PNG_NOPNG A png sticker thumbnail file was expected, but something else was provided
|
||||
STICKER_VIDEO_NOWEBM A webm video file was expected, but something else was provided
|
||||
TAKEOUT_INVALID The takeout id is invalid
|
||||
TAKEOUT_REQUIRED The method must be invoked inside a takeout session
|
||||
TEMP_AUTH_KEY_EMPTY The temporary auth key provided is empty
|
||||
|
|
@ -340,6 +344,7 @@ USER_NOT_MUTUAL_CONTACT The user is not a mutual contact
|
|||
USER_NOT_PARTICIPANT The user is not a member of this chat
|
||||
VIDEO_CONTENT_TYPE_INVALID The video content type is invalid (i.e.: not streamable)
|
||||
VIDEO_FILE_INVALID The video file is invalid
|
||||
VOICE_MESSAGES_FORBIDDEN Voice messages are restricted
|
||||
VOLUME_LOC_NOT_FOUND The volume location can't be found
|
||||
WALLPAPER_FILE_INVALID The provided file cannot be used as a wallpaper
|
||||
WALLPAPER_INVALID The input wallpaper was not valid
|
||||
|
|
@ -352,5 +357,4 @@ WEBDOCUMENT_URL_EMPTY The web document URL is empty
|
|||
WEBDOCUMENT_URL_INVALID The web document URL is invalid
|
||||
WEBPAGE_CURL_FAILED Telegram server could not fetch the provided URL
|
||||
WEBPAGE_MEDIA_EMPTY The URL doesn't contain any valid media
|
||||
YOU_BLOCKED_USER You blocked this user
|
||||
ENTITY_BOUNDS_INVALID The message entity bounds are invalid
|
||||
YOU_BLOCKED_USER You blocked this user
|
||||
|
|
|
@ -15,6 +15,7 @@ INLINE_BOT_REQUIRED The action must be performed through an inline bot callback
|
|||
MESSAGE_AUTHOR_REQUIRED You are not the author of this message
|
||||
MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat, most likely because you are not the author of them
|
||||
POLL_VOTE_REQUIRED Cast a vote in the poll before calling this method
|
||||
PREMIUM_ACCOUNT_REQUIRED This action requires a premium account
|
||||
RIGHT_FORBIDDEN You don't have enough rights for this action, or you tried to set one or more admin rights that can't be applied to this kind of chat (channel or supergroup)
|
||||
SENSITIVE_CHANGE_FORBIDDEN Your sensitive content settings can't be changed at this time
|
||||
TAKEOUT_REQUIRED The method must be invoked inside a takeout session
|
||||
|
|
@ -24,5 +25,4 @@ USER_INVALID The provided user is invalid
|
|||
USER_IS_BLOCKED The user is blocked
|
||||
USER_NOT_MUTUAL_CONTACT The provided user is not a mutual contact
|
||||
USER_PRIVACY_RESTRICTED The user's privacy settings is preventing you to perform this action
|
||||
USER_RESTRICTED You are limited/restricted. You can't perform this action
|
||||
PREMIUM_ACCOUNT_REQUIRED This action requires a premium account
|
||||
USER_RESTRICTED You are limited/restricted. You can't perform this action
|
||||
|
8
docs/requirements.txt
Normal file
8
docs/requirements.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
sphinx
|
||||
sphinx_rtd_theme==1.2.2
|
||||
sphinx-rtd-dark-mode
|
||||
sphinx_copybutton
|
||||
sphinx-autobuild
|
||||
tgcrypto
|
||||
sphinx-autobuild
|
||||
tornado>=6.3.2 # not directly required, pinned by Snyk to avoid a vulnerability
|
||||
5
docs/source/_includes/usable-by/bots.rst
Normal file
5
docs/source/_includes/usable-by/bots.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.. raw:: html
|
||||
|
||||
<strong>Usable by</strong>
|
||||
<span class="usable-by"><i class="fa-solid fa-xmark" style="color: var(--color-red)"></i> Users</span>
|
||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Bots</span>
|
||||
5
docs/source/_includes/usable-by/users-bots.rst
Normal file
5
docs/source/_includes/usable-by/users-bots.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.. raw:: html
|
||||
|
||||
<strong>Usable by</strong>
|
||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Users</span>
|
||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Bots</span>
|
||||
5
docs/source/_includes/usable-by/users.rst
Normal file
5
docs/source/_includes/usable-by/users.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.. raw:: html
|
||||
|
||||
<strong>Usable by</strong>
|
||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Users</span>
|
||||
<span class="usable-by"><i class="fa-solid fa-xmark" style="color: var(--color-red)"></i> Bots</span>
|
||||
3
docs/source/_static/css/my.css
Normal file
3
docs/source/_static/css/my.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.pre{
|
||||
color: #bfbfbf;
|
||||
}
|
||||
24
docs/source/api/client.rst
Normal file
24
docs/source/api/client.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
PyroFork Client
|
||||
===============
|
||||
|
||||
You have entered the API Reference section where you can find detailed information about PyroFork's API. The main Client
|
||||
class, all available methods and types, filters, handlers, decorators and bound-methods detailed descriptions can be
|
||||
found starting from this page.
|
||||
|
||||
This page is about the Client class, which exposes high-level methods for an easy access to the API.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
app.send_message("me", "Hi!")
|
||||
|
||||
-----
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
.. autoclass:: pyrogram.Client()
|
||||
68
docs/source/api/decorators.rst
Normal file
68
docs/source/api/decorators.rst
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
Decorators
|
||||
==========
|
||||
|
||||
Decorators are able to register callback functions for handling updates in a much easier and cleaner way compared to
|
||||
:doc:`Handlers <handlers>`; they do so by instantiating the correct handler and calling
|
||||
:meth:`~pyrogram.Client.add_handler` automatically. All you need to do is adding the decorators on top of your
|
||||
functions.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message()
|
||||
def log(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app.run()
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
.. currentmodule:: pyrogram
|
||||
|
||||
Index
|
||||
-----
|
||||
|
||||
.. hlist::
|
||||
:columns: 3
|
||||
|
||||
- :meth:`~Client.on_message`
|
||||
- :meth:`~Client.on_edited_message`
|
||||
- :meth:`~Client.on_callback_query`
|
||||
- :meth:`~Client.on_inline_query`
|
||||
- :meth:`~Client.on_chosen_inline_result`
|
||||
- :meth:`~Client.on_chat_member_updated`
|
||||
- :meth:`~Client.on_chat_join_request`
|
||||
- :meth:`~Client.on_deleted_messages`
|
||||
- :meth:`~Client.on_user_status`
|
||||
- :meth:`~Client.on_poll`
|
||||
- :meth:`~Client.on_disconnect`
|
||||
- :meth:`~Client.on_raw_update`
|
||||
|
||||
-----
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
.. Decorators
|
||||
.. autodecorator:: pyrogram.Client.on_message()
|
||||
.. autodecorator:: pyrogram.Client.on_edited_message()
|
||||
.. autodecorator:: pyrogram.Client.on_callback_query()
|
||||
.. autodecorator:: pyrogram.Client.on_inline_query()
|
||||
.. autodecorator:: pyrogram.Client.on_chosen_inline_result()
|
||||
.. autodecorator:: pyrogram.Client.on_chat_member_updated()
|
||||
.. autodecorator:: pyrogram.Client.on_chat_join_request()
|
||||
.. autodecorator:: pyrogram.Client.on_deleted_messages()
|
||||
.. autodecorator:: pyrogram.Client.on_user_status()
|
||||
.. autodecorator:: pyrogram.Client.on_poll()
|
||||
.. autodecorator:: pyrogram.Client.on_disconnect()
|
||||
.. autodecorator:: pyrogram.Client.on_raw_update()
|
||||
8
docs/source/api/enums/ChatAction.rst
Normal file
8
docs/source/api/enums/ChatAction.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
ChatAction
|
||||
==========
|
||||
|
||||
.. autoclass:: pyrogram.enums.ChatAction()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/ChatEventAction.rst
Normal file
8
docs/source/api/enums/ChatEventAction.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
ChatEventAction
|
||||
===============
|
||||
|
||||
.. autoclass:: pyrogram.enums.ChatEventAction()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/ChatMemberStatus.rst
Normal file
8
docs/source/api/enums/ChatMemberStatus.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
ChatMemberStatus
|
||||
================
|
||||
|
||||
.. autoclass:: pyrogram.enums.ChatMemberStatus()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/ChatMembersFilter.rst
Normal file
8
docs/source/api/enums/ChatMembersFilter.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
ChatMembersFilter
|
||||
=================
|
||||
|
||||
.. autoclass:: pyrogram.enums.ChatMembersFilter()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/ChatType.rst
Normal file
8
docs/source/api/enums/ChatType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
ChatType
|
||||
========
|
||||
|
||||
.. autoclass:: pyrogram.enums.ChatType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/MessageEntityType.rst
Normal file
8
docs/source/api/enums/MessageEntityType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
MessageEntityType
|
||||
=================
|
||||
|
||||
.. autoclass:: pyrogram.enums.MessageEntityType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/MessageMediaType.rst
Normal file
8
docs/source/api/enums/MessageMediaType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
MessageMediaType
|
||||
================
|
||||
|
||||
.. autoclass:: pyrogram.enums.MessageMediaType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/MessageServiceType.rst
Normal file
8
docs/source/api/enums/MessageServiceType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
MessageServiceType
|
||||
==================
|
||||
|
||||
.. autoclass:: pyrogram.enums.MessageServiceType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/MessagesFilter.rst
Normal file
8
docs/source/api/enums/MessagesFilter.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
MessagesFilter
|
||||
==============
|
||||
|
||||
.. autoclass:: pyrogram.enums.MessagesFilter()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/NextCodeType.rst
Normal file
8
docs/source/api/enums/NextCodeType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
NextCodeType
|
||||
============
|
||||
|
||||
.. autoclass:: pyrogram.enums.NextCodeType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/ParseMode.rst
Normal file
8
docs/source/api/enums/ParseMode.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
ParseMode
|
||||
=========
|
||||
|
||||
.. autoclass:: pyrogram.enums.ParseMode()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/PollType.rst
Normal file
8
docs/source/api/enums/PollType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
PollType
|
||||
========
|
||||
|
||||
.. autoclass:: pyrogram.enums.PollType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/SentCodeType.rst
Normal file
8
docs/source/api/enums/SentCodeType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
SentCodeType
|
||||
============
|
||||
|
||||
.. autoclass:: pyrogram.enums.SentCodeType()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
8
docs/source/api/enums/UserStatus.rst
Normal file
8
docs/source/api/enums/UserStatus.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
UserStatus
|
||||
==========
|
||||
|
||||
.. autoclass:: pyrogram.enums.UserStatus()
|
||||
:members:
|
||||
|
||||
.. raw:: html
|
||||
:file: ./cleanup.html
|
||||
9
docs/source/api/enums/cleanup.html
Normal file
9
docs/source/api/enums/cleanup.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
document
|
||||
.querySelectorAll("em.property")
|
||||
.forEach((elem, i) => i !== 0 ? elem.remove() : true)
|
||||
|
||||
document
|
||||
.querySelectorAll("a.headerlink")
|
||||
.forEach((elem, i) => [0, 1].includes(i) ? true : elem.remove())
|
||||
</script>
|
||||
47
docs/source/api/enums/index.rst
Normal file
47
docs/source/api/enums/index.rst
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
Enumerations
|
||||
============
|
||||
|
||||
This page is about PyroFork enumerations.
|
||||
Enumerations are types that hold a group of related values to be used whenever a constant value is required.
|
||||
They will help you deal with those values in a type-safe way and also enable code completion so that you can be sure
|
||||
to apply only a valid value among the expected ones.
|
||||
|
||||
-----
|
||||
|
||||
.. currentmodule:: pyrogram.enums
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
ChatAction
|
||||
ChatEventAction
|
||||
ChatMemberStatus
|
||||
ChatMembersFilter
|
||||
ChatType
|
||||
MessageEntityType
|
||||
MessageMediaType
|
||||
MessageServiceType
|
||||
MessagesFilter
|
||||
ParseMode
|
||||
PollType
|
||||
SentCodeType
|
||||
NextCodeType
|
||||
UserStatus
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
ChatAction
|
||||
ChatEventAction
|
||||
ChatMemberStatus
|
||||
ChatMembersFilter
|
||||
ChatType
|
||||
MessageEntityType
|
||||
MessageMediaType
|
||||
MessageServiceType
|
||||
MessagesFilter
|
||||
ParseMode
|
||||
PollType
|
||||
SentCodeType
|
||||
NextCodeType
|
||||
UserStatus
|
||||
7
docs/source/api/errors/bad-request.rst
Normal file
7
docs/source/api/errors/bad-request.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
400 - BadRequest
|
||||
----------------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/400_BAD_REQUEST.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
7
docs/source/api/errors/flood.rst
Normal file
7
docs/source/api/errors/flood.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
420 - Flood
|
||||
-----------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/420_FLOOD.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
7
docs/source/api/errors/forbidden.rst
Normal file
7
docs/source/api/errors/forbidden.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
403 - Forbidden
|
||||
---------------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/403_FORBIDDEN.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
37
docs/source/api/errors/index.rst
Normal file
37
docs/source/api/errors/index.rst
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
RPC Errors
|
||||
==========
|
||||
|
||||
All PyroFork API errors live inside the ``errors`` sub-package: ``pyrogram.errors``.
|
||||
The errors ids listed here are shown as *UPPER_SNAKE_CASE*, but the actual exception names to import from PyroFork
|
||||
follow the usual *PascalCase* convention.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
try:
|
||||
...
|
||||
except FloodWait as e:
|
||||
...
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :doc:`see-other`
|
||||
- :doc:`bad-request`
|
||||
- :doc:`unauthorized`
|
||||
- :doc:`forbidden`
|
||||
- :doc:`not-acceptable`
|
||||
- :doc:`flood`
|
||||
- :doc:`internal-server-error`
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
see-other
|
||||
bad-request
|
||||
unauthorized
|
||||
forbidden
|
||||
not-acceptable
|
||||
flood
|
||||
internal-server-error
|
||||
7
docs/source/api/errors/internal-server-error.rst
Normal file
7
docs/source/api/errors/internal-server-error.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
500 - InternalServerError
|
||||
-------------------------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
7
docs/source/api/errors/not-acceptable.rst
Normal file
7
docs/source/api/errors/not-acceptable.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
406 - NotAcceptable
|
||||
-------------------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/406_NOT_ACCEPTABLE.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
7
docs/source/api/errors/see-other.rst
Normal file
7
docs/source/api/errors/see-other.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
303 - SeeOther
|
||||
--------------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/303_SEE_OTHER.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
7
docs/source/api/errors/unauthorized.rst
Normal file
7
docs/source/api/errors/unauthorized.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
401 - Unauthorized
|
||||
------------------
|
||||
|
||||
.. csv-table::
|
||||
:file: ../../../../compiler/errors/source/401_UNAUTHORIZED.tsv
|
||||
:delim: tab
|
||||
:header-rows: 1
|
||||
11
docs/source/api/filters.rst
Normal file
11
docs/source/api/filters.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Update Filters
|
||||
==============
|
||||
|
||||
Filters are objects that can be used to filter the content of incoming updates.
|
||||
:doc:`Read more about how filters work <../topics/use-filters>`.
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
.. automodule:: pyrogram.filters
|
||||
:members:
|
||||
66
docs/source/api/handlers.rst
Normal file
66
docs/source/api/handlers.rst
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
Update Handlers
|
||||
===============
|
||||
|
||||
Handlers are used to instruct PyroFork about which kind of updates you'd like to handle with your callback functions.
|
||||
For a much more convenient way of registering callback functions have a look at :doc:`Decorators <decorators>` instead.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.handlers import MessageHandler
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
def dump(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app.add_handler(MessageHandler(dump))
|
||||
|
||||
app.run()
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
.. currentmodule:: pyrogram.handlers
|
||||
|
||||
Index
|
||||
-----
|
||||
|
||||
.. hlist::
|
||||
:columns: 3
|
||||
|
||||
- :class:`MessageHandler`
|
||||
- :class:`EditedMessageHandler`
|
||||
- :class:`DeletedMessagesHandler`
|
||||
- :class:`CallbackQueryHandler`
|
||||
- :class:`InlineQueryHandler`
|
||||
- :class:`ChosenInlineResultHandler`
|
||||
- :class:`ChatMemberUpdatedHandler`
|
||||
- :class:`UserStatusHandler`
|
||||
- :class:`PollHandler`
|
||||
- :class:`DisconnectHandler`
|
||||
- :class:`RawUpdateHandler`
|
||||
|
||||
-----
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
.. Handlers
|
||||
.. autoclass:: MessageHandler()
|
||||
.. autoclass:: EditedMessageHandler()
|
||||
.. autoclass:: DeletedMessagesHandler()
|
||||
.. autoclass:: CallbackQueryHandler()
|
||||
.. autoclass:: InlineQueryHandler()
|
||||
.. autoclass:: ChosenInlineResultHandler()
|
||||
.. autoclass:: ChatMemberUpdatedHandler()
|
||||
.. autoclass:: UserStatusHandler()
|
||||
.. autoclass:: PollHandler()
|
||||
.. autoclass:: DisconnectHandler()
|
||||
.. autoclass:: RawUpdateHandler()
|
||||
99
docs/source/conf.py
Normal file
99
docs/source/conf.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
# PyroFork - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||
# Copyright (C) 2022-present wulan17 <https://github.com/wulan17>
|
||||
#
|
||||
# This file is part of PyroFork.
|
||||
#
|
||||
# PyroFork 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.
|
||||
#
|
||||
# PyroFork 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 PyroFork. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../.."))
|
||||
|
||||
from pyrogram import __version__
|
||||
|
||||
from pygments.styles.friendly import FriendlyStyle
|
||||
|
||||
FriendlyStyle.background_color = "#f3f2f1"
|
||||
|
||||
project = "PyroFork"
|
||||
copyright = f"2022-present, wulan17"
|
||||
author = "wulan17"
|
||||
|
||||
version = ".".join(__version__.split(".")[:-1])
|
||||
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.napoleon",
|
||||
"sphinx.ext.autosummary",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx_copybutton",
|
||||
"sphinx_rtd_dark_mode"
|
||||
]
|
||||
|
||||
intersphinx_mapping = {
|
||||
"python": ("https://docs.python.org/3", None)
|
||||
}
|
||||
|
||||
master_doc = "index"
|
||||
source_suffix = ".rst"
|
||||
autodoc_member_order = "bysource"
|
||||
|
||||
templates_path = ["../resources/templates"]
|
||||
html_copy_source = False
|
||||
|
||||
napoleon_use_rtype = False
|
||||
napoleon_use_param = False
|
||||
|
||||
pygments_style = "friendly"
|
||||
|
||||
copybutton_prompt_text = "$ "
|
||||
|
||||
suppress_warnings = ["image.not_readable"]
|
||||
|
||||
html_title = "PyroFork Documentation"
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_static_path = ["../resources/static","_static"]
|
||||
html_show_sourcelink = True
|
||||
html_show_copyright = False
|
||||
html_theme_options = {
|
||||
"canonical_url": "https://docs.pyrogram.org/",
|
||||
"collapse_navigation": True,
|
||||
"sticky_navigation": False,
|
||||
"logo_only": True,
|
||||
"display_version": False,
|
||||
"style_external_links": True
|
||||
}
|
||||
|
||||
html_logo = "../resources/static/img/pyrogram.png"
|
||||
html_favicon = "../resources/static/img/favicon.ico"
|
||||
|
||||
latex_engine = "xelatex"
|
||||
latex_logo = "../resources/static/img/pyrogram.png"
|
||||
|
||||
latex_elements = {
|
||||
"pointsize": "12pt",
|
||||
"fontpkg": r"""
|
||||
\setmainfont{Open Sans}
|
||||
\setsansfont{Bitter}
|
||||
\setmonofont{Ubuntu Mono}
|
||||
"""
|
||||
}
|
||||
|
||||
html_css_files = [
|
||||
"css/my.css",
|
||||
"https://docs.pyrogram.org/_static/css/custom.css",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css",
|
||||
]
|
||||
11
docs/source/faq/client-started-but-nothing-happens.rst
Normal file
11
docs/source/faq/client-started-but-nothing-happens.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Client started, but nothing happens
|
||||
===================================
|
||||
|
||||
A possible cause might be network issues, either yours or Telegram's. To check this, add the following code at
|
||||
the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable
|
||||
network:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
Code hangs when calling stop, restart, add/remove_handler
|
||||
=========================================================
|
||||
|
||||
You tried to ``.stop()``, ``.restart()``, ``.add_handler()`` or ``.remove_handler()`` inside a running handler, but
|
||||
that can't be done because the way PyroFork deals with handlers would make it hang.
|
||||
|
||||
When calling one of the methods above inside an event handler, PyroFork needs to wait for all running handlers to finish
|
||||
in order to continue. Since your handler is blocking the execution by waiting for the called method to finish
|
||||
and since PyroFork needs to wait for your handler to finish, you are left with a deadlock.
|
||||
|
||||
The solution to this problem is to pass ``block=False`` to such methods so that they return immediately and the actual
|
||||
code called asynchronously.
|
||||
23
docs/source/faq/how-to-avoid-flood-waits.rst
Normal file
23
docs/source/faq/how-to-avoid-flood-waits.rst
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
How to avoid Flood Waits?
|
||||
=========================
|
||||
|
||||
Slow things down and make less requests. Moreover, exact limits are unknown and can change anytime based on normal
|
||||
usages.
|
||||
|
||||
When a flood wait happens the server will tell you how much time to wait before continuing.
|
||||
The following shows how to catch the exception in your code and wait the required seconds.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
...
|
||||
try:
|
||||
... # Your code
|
||||
except FloodWait as e:
|
||||
await asyncio.sleep(e.value) # Wait "value" seconds before continuing
|
||||
...
|
||||
|
||||
|
||||
More info about error handling can be found :doc:`here <../start/errors>`.
|
||||
9
docs/source/faq/how-to-use-webhooks.rst
Normal file
9
docs/source/faq/how-to-use-webhooks.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
How to use webhooks?
|
||||
====================
|
||||
|
||||
There is no webhook in PyroFork, simply because there is no HTTP involved. However, a similar technique is
|
||||
being used to make receiving updates efficient.
|
||||
|
||||
PyroFork uses persistent connections via TCP sockets to interact with the server and instead of actively asking for
|
||||
updates every time (polling), PyroFork will sit down and wait for the server to send updates by itself the very moment
|
||||
they are available (server push).
|
||||
45
docs/source/faq/index.rst
Normal file
45
docs/source/faq/index.rst
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
This FAQ page provides answers to common questions about PyroFork and, to some extent, Telegram in general.
|
||||
|
||||
**Contents**
|
||||
|
||||
- :doc:`why-is-the-api-key-needed-for-bots`
|
||||
- :doc:`how-to-use-webhooks`
|
||||
- :doc:`using-the-same-file-id-across-different-accounts`
|
||||
- :doc:`using-multiple-clients-at-once-on-the-same-account`
|
||||
- :doc:`client-started-but-nothing-happens`
|
||||
- :doc:`what-are-the-ip-addresses-of-telegram-data-centers`
|
||||
- :doc:`migrating-the-account-to-another-data-center`
|
||||
- :doc:`why-is-the-client-reacting-slowly-in-supergroups-channels`
|
||||
- :doc:`peer-id-invalid-error`
|
||||
- :doc:`code-hangs-when-calling-stop-restart-add-remove-handler`
|
||||
- :doc:`unicodeencodeerror-codec-cant-encode`
|
||||
- :doc:`uploading-with-urls-gives-error-webpage-curl-failed`
|
||||
- :doc:`sqlite3-operationalerror-database-is-locked`
|
||||
- :doc:`sqlite3-interfaceerror-error-binding-parameter`
|
||||
- :doc:`socket-send-oserror-timeouterror-connection-lost-reset`
|
||||
- :doc:`how-to-avoid-flood-waits`
|
||||
- :doc:`the-account-has-been-limited-deactivated`
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
why-is-the-api-key-needed-for-bots
|
||||
how-to-use-webhooks
|
||||
using-the-same-file-id-across-different-accounts
|
||||
using-multiple-clients-at-once-on-the-same-account
|
||||
client-started-but-nothing-happens
|
||||
what-are-the-ip-addresses-of-telegram-data-centers
|
||||
migrating-the-account-to-another-data-center
|
||||
why-is-the-client-reacting-slowly-in-supergroups-channels
|
||||
peer-id-invalid-error
|
||||
code-hangs-when-calling-stop-restart-add-remove-handler
|
||||
unicodeencodeerror-codec-cant-encode
|
||||
uploading-with-urls-gives-error-webpage-curl-failed
|
||||
sqlite3-operationalerror-database-is-locked
|
||||
sqlite3-interfaceerror-error-binding-parameter
|
||||
socket-send-oserror-timeouterror-connection-lost-reset
|
||||
how-to-avoid-flood-waits
|
||||
the-account-has-been-limited-deactivated
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Migrating the account to another data center
|
||||
============================================
|
||||
|
||||
This question is asked by people who find their account always being connected to one DC (data center), but are
|
||||
connecting from a place far away, thus resulting in slower interactions when using the API because of the greater
|
||||
physical distance between the user and the associated DC.
|
||||
|
||||
When registering an account for the first time, is up to Telegram to decide which DC the new user is going to be
|
||||
created in. It's also up to the server to decide whether to automatically migrate a user in case of prolonged usages
|
||||
from a distant location.
|
||||
14
docs/source/faq/peer-id-invalid-error.rst
Normal file
14
docs/source/faq/peer-id-invalid-error.rst
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
PEER_ID_INVALID error
|
||||
=====================
|
||||
|
||||
This error could mean several things:
|
||||
|
||||
- The chat id you tried to use is simply wrong, check it again.
|
||||
- The chat id refers to a group or channel you are not a member of.
|
||||
- The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``.
|
||||
- The chat id refers to a user or chat your current session hasn't met yet.
|
||||
|
||||
About the last point: in order for you to meet a user and thus communicate with them, you should ask yourself how to
|
||||
contact people using official apps. The answer is the same for PyroFork too and involves normal usages such as searching
|
||||
for usernames, meeting them in a common group, having their phone contacts saved, getting a message mentioning them
|
||||
or obtaining the dialogs list.
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
socket.send(), OSError(), TimeoutError(), Connection lost/reset
|
||||
===============================================================
|
||||
|
||||
If you get any of these errors chances are you ended up with a slow or inconsistent network connection.
|
||||
Another reason could be because you are blocking the event loop for too long.
|
||||
|
||||
You can consider the following:
|
||||
|
||||
- Use PyroFork asynchronously in its intended way.
|
||||
- Use shorter non-asynchronous processing loops.
|
||||
- Use ``asyncio.sleep()`` instead of ``time.sleep()``.
|
||||
- Use a stable network connection.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
sqlite3.InterfaceError: Error binding parameter
|
||||
===============================================
|
||||
|
||||
This error occurs when you pass a chat id value of the wrong type when trying to call a method. Most likely, you
|
||||
accidentally passed the whole user or chat object instead of the id or username.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Wrong. You passed the whole Chat instance
|
||||
app.send_message(chat, "text")
|
||||
|
||||
# Correct
|
||||
app.send_message(chat.id, "text")
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
sqlite3.OperationalError: database is locked
|
||||
============================================
|
||||
|
||||
This error occurs when more than one process is using the same session file, that is, when you run two or more clients
|
||||
at the same time using the same session name or in case another program has accessed the file.
|
||||
|
||||
For example, it could occur when a background script is still running and you forgot about it. In this case, you either
|
||||
restart your system or find and kill the process that is locking the database. On Unix based systems, you can try the
|
||||
following:
|
||||
|
||||
#. ``cd`` into your session file directory.
|
||||
#. ``fuser my_account.session`` to find the process id.
|
||||
#. ``kill 1234`` to gracefully stop the process.
|
||||
#. If the last command doesn't help, use ``kill -9 1234`` instead.
|
||||
|
||||
If you want to run multiple clients on the same account, you must authorize your account (either user or bot)
|
||||
from the beginning every time, and use different session names for each parallel client you are going to use.
|
||||
16
docs/source/faq/the-account-has-been-limited-deactivated.rst
Normal file
16
docs/source/faq/the-account-has-been-limited-deactivated.rst
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
The account has been limited/deactivated
|
||||
========================================
|
||||
|
||||
PyroFork is a framework that interfaces with Telegram; it is at your commands, meaning it only does what you tell it to
|
||||
do, the rest is up to you and Telegram (see `Telegram's ToS`_).
|
||||
|
||||
If you found your account being limited/deactivated, it could be due spam/flood/abuse of the API or the usage of certain
|
||||
virtual/VoIP numbers.
|
||||
|
||||
If you think your account was limited/deactivated by mistake, you can write to recover@telegram.org, contact
|
||||
`@SpamBot`_ or use `this form`_.
|
||||
|
||||
.. _@SpamBot: https://t.me/spambot
|
||||
.. _this form: https://telegram.org/support
|
||||
.. _Telegram's ToS: https://telegram.org/tos
|
||||
|
||||
7
docs/source/faq/unicodeencodeerror-codec-cant-encode.rst
Normal file
7
docs/source/faq/unicodeencodeerror-codec-cant-encode.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
UnicodeEncodeError: '...' codec can't encode ...
|
||||
================================================
|
||||
|
||||
Where ``<encoding>`` might be *ascii*, *cp932*, *charmap* or anything else other than *utf-8*. This error usually
|
||||
shows up when you try to print something and has very little to do with PyroFork itself as it is strictly related to
|
||||
your own terminal. To fix it, either find a way to change the encoding settings of your terminal to UTF-8 or switch to
|
||||
another terminal altogether.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Uploading with URLs gives error WEBPAGE_CURL_FAILED
|
||||
===================================================
|
||||
|
||||
When uploading media files using an URL, the server automatically tries to download the media and uploads it to the
|
||||
Telegram cloud. This error usually happens in case the provided URL is not publicly accessible by Telegram itself or the
|
||||
media file is too large. In such cases, your only option is to download the media yourself and upload it from your
|
||||
local machine.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Using multiple clients at once on the same account
|
||||
==================================================
|
||||
|
||||
Both user and bot accounts are able to run multiple sessions in parallel. However, you must not use the same session
|
||||
in more than one client at the same time. The correct way to run multiple clients on the same account is by authorizing
|
||||
your account (either user or bot) from the beginning each time, and use one separate session for each parallel client.
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Using the same file_id across different accounts
|
||||
================================================
|
||||
|
||||
Telegram file_id strings are bound to the account which generated them. An attempt in using a foreign file id will
|
||||
result in errors such as ``[400 MEDIA_EMPTY]``. The only exception are stickers' file ids; you can use them across
|
||||
different accounts without any problem.
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
What are the IP addresses of Telegram Data Centers?
|
||||
===================================================
|
||||
|
||||
Telegram is currently composed by a decentralized, multi-DC infrastructure (currently 5 DCs, each of which can
|
||||
work independently) spread across different locations worldwide. However, some of the less busy DCs have been lately
|
||||
dismissed and their IP addresses are now kept as aliases to the nearest one.
|
||||
|
||||
.. csv-table:: Production Environment
|
||||
:header: ID, Location, IPv4, IPv6
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
DC1, "MIA, Miami FL, USA", ``149.154.175.53``, ``2001:b28:f23d:f001::a``
|
||||
DC2, "AMS, Amsterdam, NL", ``149.154.167.51``, ``2001:67c:4e8:f002::a``
|
||||
DC3*, "MIA, Miami FL, USA", ``149.154.175.100``, ``2001:b28:f23d:f003::a``
|
||||
DC4, "AMS, Amsterdam, NL", ``149.154.167.91``, ``2001:67c:4e8:f004::a``
|
||||
DC5, "SIN, Singapore, SG", ``91.108.56.130``, ``2001:b28:f23f:f005::a``
|
||||
|
||||
.. csv-table:: Test Environment
|
||||
:header: ID, Location, IPv4, IPv6
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
DC1, "MIA, Miami FL, USA", ``149.154.175.10``, ``2001:b28:f23d:f001::e``
|
||||
DC2, "AMS, Amsterdam, NL", ``149.154.167.40``, ``2001:67c:4e8:f002::e``
|
||||
DC3*, "MIA, Miami FL, USA", ``149.154.175.117``, ``2001:b28:f23d:f003::e``
|
||||
|
||||
.. centered:: More info about the Test Environment can be found :doc:`here <../topics/test-servers>`.
|
||||
|
||||
***** Alias DC
|
||||
12
docs/source/faq/why-is-the-api-key-needed-for-bots.rst
Normal file
12
docs/source/faq/why-is-the-api-key-needed-for-bots.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Why is the API key needed for bots?
|
||||
===================================
|
||||
|
||||
Requests against the official bot API endpoints are made via JSON/HTTP and are handled by an intermediate server
|
||||
application that implements the MTProto protocol and uses its own API key to communicate with the MTProto servers.
|
||||
|
||||
.. figure:: //_static/img/mtproto-vs-bot-api.png
|
||||
:align: center
|
||||
|
||||
Using MTProto is the only way to communicate with the actual Telegram servers, and the main API requires developers to
|
||||
identify applications by means of a unique key; the bot token identifies a bot as a user and replaces the user's phone
|
||||
number only.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
Why is the client reacting slowly in supergroups/channels?
|
||||
==========================================================
|
||||
|
||||
Because of how Telegram works internally, every message you receive and send must pass through the creator's DC, and in
|
||||
the worst case where you, the creator and another member all belong to three different DCs, the other member messages
|
||||
have to go through from their DC to the creator's DC and finally to your DC. This is applied to each message and member
|
||||
of a supergroup/channel and the process will inevitably take its time.
|
||||
|
||||
Another reason that makes responses come slowly is that messages are dispatched by priority. Depending on the kind
|
||||
of member, some users receive messages faster than others and for big and busy supergroups the delay might become
|
||||
noticeable, especially if you are among the lower end of the priority list:
|
||||
|
||||
1. Creator.
|
||||
2. Administrators.
|
||||
3. Bots.
|
||||
4. Mentioned users.
|
||||
5. Recent online users.
|
||||
6. Everyone else.
|
||||
172
docs/source/index.rst
Normal file
172
docs/source/index.rst
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
Welcome to PyroFork
|
||||
===================
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div align="center">
|
||||
<a href="/">
|
||||
<div class="pyrogram-logo-index"><img src="_static/pyrogram.png" alt="PyroFork"></div>
|
||||
<div class="pyrogram-text pyrogram-text-index">PyroFork</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<b>Telegram MTProto API Framework for Python</b>
|
||||
|
||||
<br>
|
||||
<a href="https://pyrogram.org">
|
||||
Homepage
|
||||
</a>
|
||||
•
|
||||
<a href="https://github.com/pyrogram/pyrogram">
|
||||
Development
|
||||
</a>
|
||||
•
|
||||
<a href="https://docs.pyrogram.org/releases">
|
||||
Releases
|
||||
</a>
|
||||
•
|
||||
<a href="https://t.me/pyrogram">
|
||||
News
|
||||
</a>
|
||||
</p>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, filters
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def hello(client, message):
|
||||
await message.reply("Hello from PyroFork!")
|
||||
|
||||
|
||||
app.run()
|
||||
|
||||
**PyroFork** is a modern, elegant and asynchronous :doc:`MTProto API <topics/mtproto-vs-botapi>` framework.
|
||||
It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot identity
|
||||
(bot API alternative) using Python.
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
If you'd like to support PyroFork, you can consider:
|
||||
|
||||
- `Become a GitHub sponsor <https://github.com/sponsors/delivrance>`_.
|
||||
- `Become a LiberaPay patron <https://liberapay.com/delivrance>`_.
|
||||
- `Become an OpenCollective backer <https://opencollective.com/pyrogram>`_.
|
||||
|
||||
How the Documentation is Organized
|
||||
----------------------------------
|
||||
|
||||
Contents are organized into sections composed of self-contained topics which can be all accessed from the sidebar, or by
|
||||
following them in order using the :guilabel:`Next` button at the end of each page.
|
||||
You can also switch to Dark or Light theme or leave on Auto (follows system preferences) by using the dedicated button
|
||||
in the top left corner.
|
||||
|
||||
Here below you can, instead, find a list of the most relevant pages for a quick access.
|
||||
|
||||
First Steps
|
||||
^^^^^^^^^^^
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :doc:`Quick Start <intro/quickstart>`: Overview to get you started quickly.
|
||||
- :doc:`Invoking Methods <start/invoking>`: How to call PyroFork's methods.
|
||||
- :doc:`Handling Updates <start/updates>`: How to handle Telegram updates.
|
||||
- :doc:`Error Handling <start/errors>`: How to handle API errors correctly.
|
||||
|
||||
API Reference
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :doc:`PyroFork Client <api/client>`: Reference details about the Client class.
|
||||
- :doc:`Available Methods <api/methods/index>`: List of available high-level methods.
|
||||
- :doc:`Available Types <api/types/index>`: List of available high-level types.
|
||||
- :doc:`Enumerations <api/enums/index>`: List of available enumerations.
|
||||
- :doc:`Bound Methods <api/bound-methods/index>`: List of convenient bound methods.
|
||||
|
||||
Meta
|
||||
^^^^
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :doc:`PyroFork FAQ <faq/index>`: Answers to common PyroFork questions.
|
||||
- :doc:`Support PyroFork <support>`: Ways to show your appreciation.
|
||||
- :doc:`Release Notes <releases/index>`: Release notes for PyroFork releases.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Introduction
|
||||
|
||||
intro/quickstart
|
||||
intro/install
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Getting Started
|
||||
|
||||
start/setup
|
||||
start/auth
|
||||
start/invoking
|
||||
start/updates
|
||||
start/errors
|
||||
start/examples/index
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: API Reference
|
||||
|
||||
api/client
|
||||
api/methods/index
|
||||
api/types/index
|
||||
api/bound-methods/index
|
||||
api/enums/index
|
||||
api/handlers
|
||||
api/decorators
|
||||
api/errors/index
|
||||
api/filters
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Topic Guides
|
||||
|
||||
topics/use-filters
|
||||
topics/create-filters
|
||||
topics/more-on-updates
|
||||
topics/client-settings
|
||||
topics/speedups
|
||||
topics/text-formatting
|
||||
topics/synchronous
|
||||
topics/smart-plugins
|
||||
topics/storage-engines
|
||||
topics/serializing
|
||||
topics/proxy
|
||||
topics/scheduling
|
||||
topics/mtproto-vs-botapi
|
||||
topics/debugging
|
||||
topics/test-servers
|
||||
topics/advanced-usage
|
||||
topics/voice-calls
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Meta
|
||||
|
||||
faq/index
|
||||
support
|
||||
releases/index
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Telegram Raw API
|
||||
|
||||
telegram/functions/index
|
||||
telegram/types/index
|
||||
telegram/base/index
|
||||
41
docs/source/intro/install.rst
Normal file
41
docs/source/intro/install.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Install Guide
|
||||
=============
|
||||
|
||||
Being a modern Python framework, PyroFork requires an up to date version of Python to be installed in your system.
|
||||
We recommend using the latest versions of both Python 3 and pip.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Install PyroFork
|
||||
----------------
|
||||
|
||||
- The easiest way to install and upgrade PyroFork to its latest stable version is by using **pip**:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip3 install -U git+https://github.com/Mayuri-Chan/pyrofork@dev/pyrofork
|
||||
|
||||
- or, with :doc:`TgCrypto <../topics/speedups>` as extra requirement (recommended):
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip3 install -U git+https://github.com/Mayuri-Chan/pyrofork@dev/pyrofork tgcrypto
|
||||
|
||||
Verifying
|
||||
---------
|
||||
|
||||
To verify that PyroFork is correctly installed, open a Python shell and import it.
|
||||
If no error shows up you are good to go.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
>>> import pyrogram
|
||||
>>> pyrogram.__version__
|
||||
'x.y.z'
|
||||
|
||||
.. _`Github repo`: https://github.com/Mayuri-Chan/pyrofork
|
||||
56
docs/source/intro/quickstart.rst
Normal file
56
docs/source/intro/quickstart.rst
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Quick Start
|
||||
===========
|
||||
|
||||
The next few steps serve as a quick start to see PyroFork in action as fast as possible.
|
||||
|
||||
Get PyroFork Real Fast
|
||||
----------------------
|
||||
|
||||
.. admonition :: Cloud Credits
|
||||
:class: tip
|
||||
|
||||
If you need a cloud server to host your applications, try Hetzner Cloud. You can sign up with
|
||||
`this link <https://hetzner.cloud/?ref=9CyT92gZEINU>`_ to get €20 in cloud credits.
|
||||
|
||||
1. Install PyroFork with ``pip3 install -U pyrogram``.
|
||||
|
||||
2. Get your own Telegram API key from https://my.telegram.org/apps.
|
||||
|
||||
3. Open the text editor of your choice and paste the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from pyrogram import Client
|
||||
|
||||
api_id = 12345
|
||||
api_hash = "0123456789abcdef0123456789abcdef"
|
||||
|
||||
|
||||
async def main():
|
||||
async with Client("my_account", api_id, api_hash) as app:
|
||||
await app.send_message("me", "Greetings from **PyroFork**!")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
4. Replace *api_id* and *api_hash* values with your own.
|
||||
|
||||
5. Save the file as ``hello.py``.
|
||||
|
||||
6. Run the script with ``python3 hello.py``
|
||||
|
||||
7. Follow the instructions on your terminal to login.
|
||||
|
||||
8. Watch PyroFork send a message to yourself.
|
||||
|
||||
Enjoy the API
|
||||
-------------
|
||||
|
||||
That was just a quick overview. In the next few pages of the introduction, we'll take a much more in-depth look of what
|
||||
we have just done above.
|
||||
|
||||
If you are feeling eager to continue you can take a shortcut to :doc:`../start/invoking` and come back
|
||||
later to learn some more details.
|
||||
|
||||
.. _community: https://t.me/PyroFork
|
||||
93
docs/source/start/auth.rst
Normal file
93
docs/source/start/auth.rst
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
Authorization
|
||||
=============
|
||||
|
||||
Once a :doc:`project is set up <setup>`, you will still have to follow a few steps before you can actually use PyroFork to make
|
||||
API calls. This section provides all the information you need in order to authorize yourself as user or bot.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
User Authorization
|
||||
------------------
|
||||
|
||||
In order to use the API, Telegram requires that users be authorized via their phone numbers.
|
||||
PyroFork automatically manages this process, all you need to do is create an instance of the
|
||||
:class:`~pyrogram.Client` class by passing to it a ``name`` of your choice (e.g.: "my_account") and call
|
||||
the :meth:`~pyrogram.Client.run` method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
api_id = 12345
|
||||
api_hash = "0123456789abcdef0123456789abcdef"
|
||||
|
||||
app = Client("my_account", api_id=api_id, api_hash=api_hash)
|
||||
|
||||
app.run()
|
||||
|
||||
This starts an interactive shell asking you to input your **phone number**, including your `Country Code`_ (the plus
|
||||
``+`` and minus ``-`` symbols can be omitted) and the **phone code** you will receive in your devices that are already
|
||||
authorized or via SMS:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Enter phone number: +1-123-456-7890
|
||||
Is "+1-123-456-7890" correct? (y/n): y
|
||||
Enter phone code: 12345
|
||||
Logged in successfully
|
||||
|
||||
After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing PyroFork to
|
||||
execute API calls with your identity. This file is personal and will be loaded again when you restart your app.
|
||||
You can now remove the api_id and api_hash values from the code as they are not needed anymore.
|
||||
|
||||
.. note::
|
||||
|
||||
The code above does nothing except asking for credentials and keeping the client online, hit :guilabel:`CTRL+C` now
|
||||
to stop your application and keep reading.
|
||||
|
||||
Bot Authorization
|
||||
-----------------
|
||||
|
||||
Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by
|
||||
the `Bot Father`_. Bot tokens replace the users' phone numbers only — you still need to
|
||||
:doc:`configure a Telegram API key <../start/setup>` with PyroFork, even when using bots.
|
||||
|
||||
The authorization process is automatically managed. All you need to do is choose a ``name`` (can be anything,
|
||||
usually your bot username) and pass your bot token using the ``bot_token`` parameter. The session file will be named
|
||||
after the session name, which will be ``my_bot.session`` for the example below.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
api_id = 12345
|
||||
api_hash = "0123456789abcdef0123456789abcdef"
|
||||
bot_token = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
|
||||
app = Client(
|
||||
"my_bot",
|
||||
api_id=api_id, api_hash=api_hash,
|
||||
bot_token=bot_token
|
||||
)
|
||||
|
||||
app.run()
|
||||
|
||||
.. _Country Code: https://en.wikipedia.org/wiki/List_of_country_calling_codes
|
||||
.. _Bot Father: https://t.me/botfather
|
||||
|
||||
.. note::
|
||||
|
||||
The API key (api_id and api_hash) and the bot_token are not required anymore after a successful authorization.
|
||||
This means you can now simply use the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
app.run()
|
||||
101
docs/source/start/errors.rst
Normal file
101
docs/source/start/errors.rst
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
Error Handling
|
||||
==============
|
||||
|
||||
Errors can be correctly handled with ``try...except`` blocks in order to control the behaviour of your application.
|
||||
PyroFork errors all live inside the ``errors`` package:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import errors
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
RPCError
|
||||
--------
|
||||
|
||||
The father of all errors is named ``RPCError`` and is able to catch all Telegram API related errors.
|
||||
This error is raised every time a method call against Telegram's API was unsuccessful.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram.errors import RPCError
|
||||
|
||||
.. warning::
|
||||
|
||||
Avoid catching this error everywhere, especially when no feedback is given (i.e. by logging/printing the full error
|
||||
traceback), because it makes it impossible to understand what went wrong.
|
||||
|
||||
Error Categories
|
||||
----------------
|
||||
|
||||
The ``RPCError`` packs together all the possible errors Telegram could raise, but to make things tidier, PyroFork
|
||||
provides categories of errors, which are named after the common HTTP errors and are subclass-ed from the ``RPCError``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram.errors import BadRequest, Forbidden, ...
|
||||
|
||||
- :doc:`303 - SeeOther <../api/errors/see-other>`
|
||||
- :doc:`400 - BadRequest <../api/errors/bad-request>`
|
||||
- :doc:`401 - Unauthorized <../api/errors/unauthorized>`
|
||||
- :doc:`403 - Forbidden <../api/errors/forbidden>`
|
||||
- :doc:`406 - NotAcceptable <../api/errors/not-acceptable>`
|
||||
- :doc:`420 - Flood <../api/errors/flood>`
|
||||
- :doc:`500 - InternalServerError <../api/errors/internal-server-error>`
|
||||
|
||||
Single Errors
|
||||
-------------
|
||||
|
||||
For a fine-grained control over every single error, PyroFork does also expose errors that deal each with a specific
|
||||
issue. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
These errors subclass directly from the category of errors they belong to, which in turn subclass from the father
|
||||
``RPCError``, thus building a class of error hierarchy such as this:
|
||||
|
||||
- RPCError
|
||||
- BadRequest
|
||||
- ``MessageEmpty``
|
||||
- ``UsernameOccupied``
|
||||
- ``...``
|
||||
- InternalServerError
|
||||
- ``RpcCallFail``
|
||||
- ``InterDcCallError``
|
||||
- ``...``
|
||||
- ``...``
|
||||
|
||||
.. _Errors: api/errors
|
||||
|
||||
Unknown Errors
|
||||
--------------
|
||||
|
||||
In case PyroFork does not know anything about a specific error yet, it raises a generic error from its known category,
|
||||
for example, an unknown error with error code ``400``, will be raised as a ``BadRequest``. This way you can catch the
|
||||
whole category of errors and be sure to also handle these unknown errors.
|
||||
|
||||
Errors with Values
|
||||
------------------
|
||||
|
||||
Exception objects may also contain some informative values. For example, ``FloodWait`` holds the amount of seconds you
|
||||
have to wait before you can try again, some other errors contain the DC number on which the request must be repeated on.
|
||||
The value is stored in the ``value`` attribute of the exception object:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
...
|
||||
try:
|
||||
... # Your code
|
||||
except FloodWait as e:
|
||||
await asyncio.sleep(e.value) # Wait N seconds before continuing
|
||||
...
|
||||
68
docs/source/start/examples/bot_keyboards.rst
Normal file
68
docs/source/start/examples/bot_keyboards.rst
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
bot_keyboards
|
||||
=============
|
||||
|
||||
This example will show you how to send normal and inline keyboards (as bot).
|
||||
|
||||
You must log-in as a regular bot in order to send keyboards (use the token from @BotFather).
|
||||
Any attempt in sending keyboards with a user account will be simply ignored by the server.
|
||||
|
||||
send_message() is used as example, but a keyboard can be sent with any other send_* methods,
|
||||
like send_audio(), send_document(), send_location(), etc...
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.types import (ReplyKeyboardMarkup, InlineKeyboardMarkup,
|
||||
InlineKeyboardButton)
|
||||
|
||||
# Create a client using your bot token
|
||||
app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message(
|
||||
"me", # Edit this
|
||||
"This is a ReplyKeyboardMarkup example",
|
||||
reply_markup=ReplyKeyboardMarkup(
|
||||
[
|
||||
["A", "B", "C", "D"], # First row
|
||||
["E", "F", "G"], # Second row
|
||||
["H", "I"], # Third row
|
||||
["J"] # Fourth row
|
||||
],
|
||||
resize_keyboard=True # Make the keyboard smaller
|
||||
)
|
||||
)
|
||||
|
||||
await app.send_message(
|
||||
"me", # Edit this
|
||||
"This is a InlineKeyboardMarkup example",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
[ # First row
|
||||
InlineKeyboardButton( # Generates a callback query when pressed
|
||||
"Button",
|
||||
callback_data="data"
|
||||
),
|
||||
InlineKeyboardButton( # Opens a web URL
|
||||
"URL",
|
||||
url="https://docs.pyrogram.org"
|
||||
),
|
||||
],
|
||||
[ # Second row
|
||||
InlineKeyboardButton( # Opens the inline interface
|
||||
"Choose chat",
|
||||
switch_inline_query="pyrogram"
|
||||
),
|
||||
InlineKeyboardButton( # Opens the inline interface in the current chat
|
||||
"Inline here",
|
||||
switch_inline_query_current_chat="pyrogram"
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
app.run(main())
|
||||
21
docs/source/start/examples/callback_queries.rst
Normal file
21
docs/source/start/examples/callback_queries.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
callback_queries
|
||||
================
|
||||
|
||||
This example shows how to handle callback queries, i.e.: queries coming from inline button presses.
|
||||
It uses the @on_callback_query decorator to register a CallbackQueryHandler.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
|
||||
|
||||
@app.on_callback_query()
|
||||
async def answer(client, callback_query):
|
||||
await callback_query.answer(
|
||||
f"Button contains: '{callback_query.data}'",
|
||||
show_alert=True)
|
||||
|
||||
|
||||
app.run() # Automatically start() and idle()
|
||||
21
docs/source/start/examples/echo_bot.rst
Normal file
21
docs/source/start/examples/echo_bot.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
echo_bot
|
||||
========
|
||||
|
||||
This simple echo bot replies to every private text message.
|
||||
|
||||
It uses the ``@on_message`` decorator to register a ``MessageHandler`` and applies two filters on it:
|
||||
``filters.text`` and ``filters.private`` to make sure it will reply to private text messages only.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, filters
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message(filters.text & filters.private)
|
||||
async def echo(client, message):
|
||||
await message.reply(message.text)
|
||||
|
||||
|
||||
app.run() # Automatically start() and idle()
|
||||
20
docs/source/start/examples/get_chat_history.rst
Normal file
20
docs/source/start/examples/get_chat_history.rst
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
get_history
|
||||
===========
|
||||
|
||||
This example shows how to get the full message history of a chat, starting from the latest message.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
# "me" refers to your own chat (Saved Messages)
|
||||
async for message in app.get_chat_history("me"):
|
||||
print(message)
|
||||
|
||||
|
||||
app.run(main())
|
||||
22
docs/source/start/examples/get_chat_members.rst
Normal file
22
docs/source/start/examples/get_chat_members.rst
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
get_chat_members
|
||||
================
|
||||
|
||||
This example shows how to get all the members of a chat.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
# Target channel/supergroup
|
||||
TARGET = -100123456789
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
async for member in app.get_chat_members(TARGET):
|
||||
print(member)
|
||||
|
||||
|
||||
app.run(main())
|
||||
19
docs/source/start/examples/get_dialogs.rst
Normal file
19
docs/source/start/examples/get_dialogs.rst
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
get_dialogs
|
||||
===========
|
||||
|
||||
This example shows how to get the full dialogs list (as user).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
async for dialog in app.get_dialogs():
|
||||
print(dialog.chat.title or dialog.chat.first_name)
|
||||
|
||||
|
||||
app.run(main())
|
||||
20
docs/source/start/examples/hello_world.rst
Normal file
20
docs/source/start/examples/hello_world.rst
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
hello_world
|
||||
===========
|
||||
|
||||
This example demonstrates a basic API usage
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
# Create a new Client instance
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
# Send a message, Markdown is enabled by default
|
||||
await app.send_message("me", "Hi there! I'm using **PyroFork**")
|
||||
|
||||
|
||||
app.run(main())
|
||||
46
docs/source/start/examples/index.rst
Normal file
46
docs/source/start/examples/index.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Examples
|
||||
========
|
||||
|
||||
This page contains example scripts to show you how PyroFork looks like.
|
||||
|
||||
Every script is working right away (provided you correctly set up your credentials), meaning you can simply copy-paste
|
||||
and run. The only things you have to change are session names and target chats, where applicable.
|
||||
|
||||
The examples listed below can be treated as building blocks for your own applications and are meant to be simple enough
|
||||
to give you a basic idea.
|
||||
|
||||
-----
|
||||
|
||||
.. csv-table::
|
||||
:header: Example, Description
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
:doc:`hello_world`, "Demonstration of basic API usage"
|
||||
:doc:`echo_bot`, "Echo every private text message"
|
||||
:doc:`welcome_bot`, "The Welcome Bot in @PyroForkChat"
|
||||
:doc:`get_chat_history`, "Get the full message history of a chat"
|
||||
:doc:`get_chat_members`, "Get all the members of a chat"
|
||||
:doc:`get_dialogs`, "Get all of your dialog chats"
|
||||
:doc:`callback_queries`, "Handle callback queries (as bot) coming from inline button presses"
|
||||
:doc:`inline_queries`, "Handle inline queries (as bot) and answer with results"
|
||||
:doc:`use_inline_bots`, "Query an inline bot (as user) and send a result to a chat"
|
||||
:doc:`bot_keyboards`, "Send normal and inline keyboards using regular bots"
|
||||
:doc:`raw_updates`, "Handle raw updates (old, should be avoided)"
|
||||
|
||||
For more advanced examples, see https://snippets.pyrogram.org.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
hello_world
|
||||
echo_bot
|
||||
welcome_bot
|
||||
get_chat_history
|
||||
get_chat_members
|
||||
get_dialogs
|
||||
callback_queries
|
||||
inline_queries
|
||||
use_inline_bots
|
||||
bot_keyboards
|
||||
raw_updates
|
||||
59
docs/source/start/examples/inline_queries.rst
Normal file
59
docs/source/start/examples/inline_queries.rst
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
inline_queries
|
||||
==============
|
||||
|
||||
This example shows how to handle inline queries.
|
||||
|
||||
Two results are generated when users invoke the bot inline mode, e.g.: @pyrogrambot hi.
|
||||
It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.types import (InlineQueryResultArticle, InputTextMessageContent,
|
||||
InlineKeyboardMarkup, InlineKeyboardButton)
|
||||
|
||||
app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
|
||||
|
||||
@app.on_inline_query()
|
||||
async def answer(client, inline_query):
|
||||
await inline_query.answer(
|
||||
results=[
|
||||
InlineQueryResultArticle(
|
||||
title="Installation",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"Here's how to install **PyroFork**"
|
||||
),
|
||||
url="https://docs.pyrogram.org/intro/install",
|
||||
description="How to install PyroFork",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
[InlineKeyboardButton(
|
||||
"Open website",
|
||||
url="https://docs.pyrogram.org/intro/install"
|
||||
)]
|
||||
]
|
||||
)
|
||||
),
|
||||
InlineQueryResultArticle(
|
||||
title="Usage",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"Here's how to use **PyroFork**"
|
||||
),
|
||||
url="https://docs.pyrogram.org/start/invoking",
|
||||
description="How to use PyroFork",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
[InlineKeyboardButton(
|
||||
"Open website",
|
||||
url="https://docs.pyrogram.org/start/invoking"
|
||||
)]
|
||||
]
|
||||
)
|
||||
)
|
||||
],
|
||||
cache_time=1
|
||||
)
|
||||
|
||||
|
||||
app.run() # Automatically start() and idle()
|
||||
18
docs/source/start/examples/raw_updates.rst
Normal file
18
docs/source/start/examples/raw_updates.rst
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
raw_updates
|
||||
===========
|
||||
|
||||
This example shows how to handle raw updates.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_raw_update()
|
||||
async def raw(client, update, users, chats):
|
||||
print(update)
|
||||
|
||||
|
||||
app.run() # Automatically start() and idle()
|
||||
25
docs/source/start/examples/use_inline_bots.rst
Normal file
25
docs/source/start/examples/use_inline_bots.rst
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use_inline_bots
|
||||
===============
|
||||
|
||||
This example shows how to query an inline bot (as user).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
# Create a new Client
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
# Get bot results for "hello" from the inline bot @vid
|
||||
bot_results = await app.get_inline_bot_results("vid", "hello")
|
||||
|
||||
# Send the first result to your own chat (Saved Messages)
|
||||
await app.send_inline_bot_result(
|
||||
"me", bot_results.query_id,
|
||||
bot_results.results[0].id)
|
||||
|
||||
|
||||
app.run(main())
|
||||
30
docs/source/start/examples/welcome_bot.rst
Normal file
30
docs/source/start/examples/welcome_bot.rst
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
welcome_bot
|
||||
===========
|
||||
|
||||
This example uses the ``emoji`` module to easily add emoji in your text messages and ``filters``
|
||||
to make it only work for specific messages in a specific chat.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, emoji, filters
|
||||
|
||||
# Target chat. Can also be a list of multiple chat ids/usernames
|
||||
TARGET = -100123456789
|
||||
# Welcome message template
|
||||
MESSAGE = "{} Welcome to [PyroFork](https://docs.pyrogram.org/)'s group chat {}!"
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
# Filter in only new_chat_members updates generated in TARGET chat
|
||||
@app.on_message(filters.chat(TARGET) & filters.new_chat_members)
|
||||
async def welcome(client, message):
|
||||
# Build the new members list (with mentions) by using their first_name
|
||||
new_members = [u.mention for u in message.new_chat_members]
|
||||
# Build the welcome message by using an emoji and the list we built above
|
||||
text = MESSAGE.format(emoji.SPARKLES, ", ".join(new_members))
|
||||
# Send the welcome message, without the web page preview
|
||||
await message.reply_text(text, disable_web_page_preview=True)
|
||||
|
||||
|
||||
app.run() # Automatically start() and idle()
|
||||
110
docs/source/start/invoking.rst
Normal file
110
docs/source/start/invoking.rst
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
Invoking Methods
|
||||
================
|
||||
|
||||
At this point, we have successfully :doc:`installed PyroFork <../intro/install>` and :doc:`authorized <auth>` our
|
||||
account; we are now aiming towards the core of the framework.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
Making API calls with PyroFork is very simple. Here's a basic example we are going to examine step by step:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
|
||||
app.run(main())
|
||||
|
||||
Step-by-step
|
||||
^^^^^^^^^^^^
|
||||
|
||||
#. Let's begin by importing the Client class.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
#. Now instantiate a new Client object, "my_account" is a session name of your choice.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
#. Async methods must be invoked within an async context.
|
||||
Here we define an async function and put our code inside. Also notice the ``await`` keyword in front of the method
|
||||
call; this is required for all asynchronous methods.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
#. Finally, we tell Python to schedule our ``main()`` async function by using PyroFork's :meth:`~pyrogram.Client.run`
|
||||
method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app.run(main())
|
||||
|
||||
Context Manager
|
||||
---------------
|
||||
|
||||
The ``async with`` statement starts a context manager, which is used as a shortcut for starting, executing and stopping
|
||||
the Client, asynchronously. It does so by automatically calling :meth:`~pyrogram.Client.start` and
|
||||
:meth:`~pyrogram.Client.stop` in a more convenient way which also gracefully stops the client, even in case of
|
||||
unhandled exceptions in your code.
|
||||
|
||||
Below there's the same example as above, but without the use of the context manager:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def main():
|
||||
await app.start()
|
||||
await app.send_message("me", "Hi!")
|
||||
await app.stop()
|
||||
|
||||
|
||||
app.run(main())
|
||||
|
||||
Using asyncio.run()
|
||||
-------------------
|
||||
|
||||
Alternatively to the :meth:`~pyrogram.Client.run` method, you can use Python's ``asyncio.run()`` to execute the main
|
||||
function, with one little caveat: the Client instance (and possibly other asyncio resources you are going to use) must
|
||||
be instantiated inside the main function.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from pyrogram import Client
|
||||
|
||||
|
||||
async def main():
|
||||
app = Client("my_account")
|
||||
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
40
docs/source/start/setup.rst
Normal file
40
docs/source/start/setup.rst
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
Project Setup
|
||||
=============
|
||||
|
||||
We have just :doc:`installed PyroFork <../intro/install>`. In this page we'll discuss what you need to do in order to set up a
|
||||
project with the framework.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
API Key
|
||||
-------
|
||||
|
||||
The first step requires you to obtain a valid Telegram API key (api_id and api_hash pair):
|
||||
|
||||
#. Visit https://my.telegram.org/apps and log in with your Telegram account.
|
||||
#. Fill out the form with your details and register a new Telegram application.
|
||||
#. Done. The API key consists of two parts: **api_id** and **api_hash**. Keep it secret.
|
||||
|
||||
.. note::
|
||||
|
||||
The API key defines a token for a Telegram *application* you are going to build.
|
||||
This means that you are able to authorize multiple users or bots with a single API key.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Having the API key from the previous step in handy, we can now begin to configure a PyroFork project: pass your API key to PyroFork by using the *api_id* and *api_hash* parameters of the Client class:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
api_id = 12345
|
||||
api_hash = "0123456789abcdef0123456789abcdef"
|
||||
|
||||
app = Client("my_account", api_id=api_id, api_hash=api_hash)
|
||||
78
docs/source/start/updates.rst
Normal file
78
docs/source/start/updates.rst
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
Handling Updates
|
||||
================
|
||||
|
||||
:doc:`Invoking API methods <invoking>` sequentially is one way to use PyroFork. This page deals with Telegram updates
|
||||
and how to handle new incoming messages or other events in PyroFork.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Defining Updates
|
||||
----------------
|
||||
|
||||
Updates are events that happen in your Telegram account (incoming messages, new members join,
|
||||
bot button presses, etc.), which are meant to notify you about a new specific state that has changed. These updates are
|
||||
handled by registering one or more callback functions in your app using :doc:`Handlers <../api/handlers>`.
|
||||
|
||||
Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback
|
||||
function will be called back by the framework and its body executed.
|
||||
|
||||
Registering a Handler
|
||||
---------------------
|
||||
|
||||
To explain how handlers work let's examine the one which will be in charge for handling :class:`~pyrogram.types.Message`
|
||||
updates coming from all around your chats. Every other kind of handler shares the same setup logic and you should not
|
||||
have troubles settings them up once you learn from this section.
|
||||
|
||||
Using Decorators
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
The most elegant way to register a message handler is by using the :meth:`~pyrogram.Client.on_message` decorator:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message()
|
||||
async def my_handler(client, message):
|
||||
await message.forward("me")
|
||||
|
||||
|
||||
app.run()
|
||||
|
||||
The defined function ``my_handler``, which accepts the two arguments *(client, message)*, will be the function that gets
|
||||
executed every time a new message arrives.
|
||||
|
||||
In the last line we see again the :meth:`~pyrogram.Client.run` method, this time used without any argument.
|
||||
Its purpose here is simply to automatically :meth:`~pyrogram.Client.start`, keep the Client online so that it can listen
|
||||
for updates and :meth:`~pyrogram.Client.stop` it once you hit ``CTRL+C``.
|
||||
|
||||
Using add_handler()
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :meth:`~pyrogram.Client.add_handler` method takes any handler instance that wraps around your defined callback
|
||||
function and registers it in your Client. It is useful in case you want to programmatically add handlers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.handlers import MessageHandler
|
||||
|
||||
|
||||
async def my_function(client, message):
|
||||
await message.forward("me")
|
||||
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
my_handler = MessageHandler(my_function)
|
||||
app.add_handler(my_handler)
|
||||
|
||||
app.run()
|
||||
32
docs/source/support.rst
Normal file
32
docs/source/support.rst
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Support PyroFork
|
||||
================
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
|
||||
<div style="float: right; margin-bottom: 10px">
|
||||
<a class="github-button"
|
||||
href="https://github.com/Mayuri-Chan/pyrofork"
|
||||
data-color-scheme="no-preference: light; light: light; dark: dark;"
|
||||
data-icon="octicon-star" data-size="large" data-show-count="true"
|
||||
aria-label="Star pyrogram/pyrogram on GitHub">Star</a>
|
||||
|
||||
<a class="github-button"
|
||||
href="https://github.com/Mayuri-Chan/pyrofork/fork"
|
||||
data-color-scheme="no-preference: light; light: light; dark: dark;"
|
||||
data-icon="octicon-repo-forked" data-size="large"
|
||||
data-show-count="true" aria-label="Fork pyrogram/pyrogram on GitHub">Fork</a>
|
||||
</div>
|
||||
|
||||
<br style="clear: both"/>
|
||||
|
||||
PyroFork is a free and open source project.
|
||||
If you enjoy PyroFork and would like to show your appreciation, consider donating or becoming
|
||||
a sponsor of the project. You can support PyroFork via the ways shown below:
|
||||
|
||||
-----
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script src="https://opencollective.com/pyrogram/banner.js"></script>
|
||||
124
docs/source/topics/advanced-usage.rst
Normal file
124
docs/source/topics/advanced-usage.rst
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
Advanced Usage
|
||||
==============
|
||||
|
||||
PyroFork's API -- which consists of well documented :doc:`methods <../api/methods/index>` and
|
||||
:doc:`types <../api/types/index>` -- exists to provide an easier interface to the more complex Telegram API.
|
||||
|
||||
In this section, you'll be shown the alternative way of communicating with Telegram using PyroFork: the main "raw"
|
||||
Telegram API with its functions and types.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Telegram Raw API
|
||||
----------------
|
||||
|
||||
If you can't find a high-level method for your needs or if you want complete, low-level access to the whole
|
||||
Telegram API, you have to use the raw :mod:`~pyrogram.raw.functions` and :mod:`~pyrogram.raw.types`.
|
||||
|
||||
As already hinted, raw functions and types can be less convenient. This section will therefore explain some pitfalls to
|
||||
take into consideration when working with the raw API.
|
||||
|
||||
.. tip::
|
||||
|
||||
Every available high-level method in PyroFork is built on top of these raw functions.
|
||||
|
||||
Invoking Functions
|
||||
------------------
|
||||
|
||||
Unlike the :doc:`methods <../api/methods/index>` found in PyroFork's API, which can be called in the usual simple way,
|
||||
functions to be invoked from the raw Telegram API have a different way of usage.
|
||||
|
||||
First of all, both :doc:`raw functions <../telegram/functions/index>` and :doc:`raw types <../telegram/types/index>`
|
||||
live in their respective packages (and sub-packages): ``pyrogram.raw.functions``, ``pyrogram.raw.types``. They all exist
|
||||
as Python classes, meaning you need to create an instance of each every time you need them and fill them in with the
|
||||
correct values using named arguments.
|
||||
|
||||
Next, to actually invoke the raw function you have to use the :meth:`~pyrogram.Client.invoke` method provided by the
|
||||
Client class and pass the function object you created.
|
||||
|
||||
Here's some examples:
|
||||
|
||||
- Update first name, last name and bio:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.raw import functions
|
||||
|
||||
async with Client("my_account") as app:
|
||||
await app.invoke(
|
||||
functions.account.UpdateProfile(
|
||||
first_name="First Name", last_name="Last Name",
|
||||
about="New bio text"
|
||||
)
|
||||
)
|
||||
|
||||
- Set online/offline status:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.raw import functions, types
|
||||
|
||||
async with Client("my_account") as app:
|
||||
# Set online status
|
||||
await app.invoke(functions.account.UpdateStatus(offline=False))
|
||||
|
||||
# Set offline status
|
||||
await app.invoke(functions.account.UpdateStatus(offline=True))
|
||||
|
||||
- Get chat info:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.raw import functions, types
|
||||
|
||||
async with Client("my_account") as app:
|
||||
r = await app.invoke(
|
||||
functions.channels.GetFullChannel(
|
||||
channel=app.resolve_peer("username")
|
||||
)
|
||||
)
|
||||
|
||||
print(r)
|
||||
|
||||
Chat IDs
|
||||
--------
|
||||
|
||||
The way Telegram works makes it not possible to directly send a message to a user or a chat by using their IDs only.
|
||||
Instead, a pair of ``id`` and ``access_hash`` wrapped in a so called ``InputPeer`` is always needed. PyroFork allows
|
||||
sending messages with IDs only thanks to cached access hashes.
|
||||
|
||||
There are three different InputPeer types, one for each kind of Telegram entity.
|
||||
Whenever an InputPeer is needed you must pass one of these:
|
||||
|
||||
- :class:`~pyrogram.raw.types.InputPeerUser` - Users
|
||||
- :class:`~pyrogram.raw.types.InputPeerChat` - Basic Chats
|
||||
- :class:`~pyrogram.raw.types.InputPeerChannel` - Channels & Supergroups
|
||||
|
||||
But you don't necessarily have to manually instantiate each object because PyroFork already provides
|
||||
:meth:`~pyrogram.Client.resolve_peer` as a convenience utility method that returns the correct InputPeer
|
||||
by accepting a peer ID only.
|
||||
|
||||
Another thing to take into consideration about chat IDs is the way they are represented: they are all integers and
|
||||
all positive within their respective raw types.
|
||||
|
||||
Things are different when working with PyroFork's API because having them in the same space could lead to
|
||||
collisions, and that's why PyroFork uses a slightly different representation for each kind of ID.
|
||||
|
||||
For example, given the ID *123456789*, here's how PyroFork can tell entities apart:
|
||||
|
||||
- ``+ID`` User: *123456789*
|
||||
- ``-ID`` Chat: *-123456789*
|
||||
- ``-100ID`` Channel or Supergroup: *-100123456789*
|
||||
|
||||
So, every time you take a raw ID, make sure to translate it into the correct ID when you want to use it with an
|
||||
high-level method.
|
||||
|
||||
.. _Community: https://t.me/PyroFork
|
||||
46
docs/source/topics/client-settings.rst
Normal file
46
docs/source/topics/client-settings.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Client Settings
|
||||
===============
|
||||
|
||||
You can control the way your client appears in the Active Sessions menu of an official client by changing some client
|
||||
settings. By default you will see something like the following:
|
||||
|
||||
- Device Model: ``CPython x.y.z``
|
||||
- Application: ``PyroFork x.y.z``
|
||||
- System Version: ``Linux x.y.z``
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Set Custom Values
|
||||
-----------------
|
||||
|
||||
To set custom values, you can pass the arguments directly in the Client's constructor.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app = Client(
|
||||
"my_account",
|
||||
app_version="1.2.3",
|
||||
device_model="PC",
|
||||
system_version="Linux"
|
||||
)
|
||||
|
||||
Set Custom Languages
|
||||
--------------------
|
||||
|
||||
To tell Telegram in which language should speak to you (terms of service, bots, service messages, ...) you can
|
||||
set ``lang_code`` in `ISO 639-1 <https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes>`_ standard (defaults to "en",
|
||||
English).
|
||||
|
||||
With the following code we make Telegram know we want it to speak in Italian (it):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app = Client(
|
||||
"my_account",
|
||||
lang_code="it",
|
||||
)
|
||||
109
docs/source/topics/create-filters.rst
Normal file
109
docs/source/topics/create-filters.rst
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
Creating Filters
|
||||
================
|
||||
|
||||
PyroFork already provides lots of built-in :class:`~pyrogram.filters` to work with, but in case you can't find a
|
||||
specific one for your needs or want to build a custom filter by yourself you can use
|
||||
:meth:`filters.create() <pyrogram.filters.create>`.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Custom Filters
|
||||
--------------
|
||||
|
||||
An example to demonstrate how custom filters work is to show how to create and use one for the
|
||||
:class:`~pyrogram.handlers.CallbackQueryHandler`. Note that callback queries updates are only received by bots as result
|
||||
of a user pressing an inline button attached to the bot's message; create and :doc:`authorize your bot <../start/auth>`,
|
||||
then send a message with an inline keyboard to yourself. This allows you to test your filter by pressing the inline
|
||||
button:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||
|
||||
await app.send_message(
|
||||
"username", # Change this to your username or id
|
||||
"PyroFork custom filter test",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton("Press me", "pyrogram")]]
|
||||
)
|
||||
)
|
||||
|
||||
Basic Filters
|
||||
-------------
|
||||
|
||||
For this basic filter we will be using only the first parameter of :meth:`~pyrogram.filters.create`.
|
||||
|
||||
The heart of a filter is its callback function, which accepts three arguments *(self, client, update)* and returns
|
||||
either ``True``, in case you want the update to pass the filter or ``False`` otherwise.
|
||||
|
||||
In this example we are matching the query data to "pyrogram", which means that the filter will only allow callback
|
||||
queries containing "pyrogram" as data:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import filters
|
||||
|
||||
async def func(_, __, query):
|
||||
return query.data == "pyrogram"
|
||||
|
||||
static_data_filter = filters.create(func)
|
||||
|
||||
|
||||
The first two arguments of the callback function are unused here and because of this we named them using underscores.
|
||||
|
||||
Finally, the filter usage remains the same:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_callback_query(static_data_filter)
|
||||
async def pyrogram_data(_, query):
|
||||
query.answer("it works!")
|
||||
|
||||
Filters with Arguments
|
||||
----------------------
|
||||
|
||||
A more flexible filter would be one that accepts "pyrogram" or any other string as argument at usage time.
|
||||
A dynamic filter like this will make use of named arguments for the :meth:`~pyrogram.filters.create` method and the
|
||||
first argument of the callback function, which is a reference to the filter object itself holding the extra data passed
|
||||
via named arguments.
|
||||
|
||||
This is how a dynamic custom filter looks like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import filters
|
||||
|
||||
def dynamic_data_filter(data):
|
||||
async def func(flt, _, query):
|
||||
return flt.data == query.data
|
||||
|
||||
# "data" kwarg is accessed with "flt.data" above
|
||||
return filters.create(func, data=data)
|
||||
|
||||
And finally its usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_callback_query(dynamic_data_filter("pyrogram"))
|
||||
async def pyrogram_data(_, query):
|
||||
query.answer("it works!")
|
||||
|
||||
|
||||
Method Calls Inside Filters
|
||||
---------------------------
|
||||
|
||||
The missing piece we haven't covered yet is the second argument of a filter callback function, namely, the ``client``
|
||||
argument. This is a reference to the :obj:`~pyrogram.Client` instance that is running the filter and it is useful in
|
||||
case you would like to make some API calls before deciding whether the filter should allow the update or not:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def func(_, client, query):
|
||||
# r = await client.some_api_method()
|
||||
# check response "r" and decide to return True or False
|
||||
...
|
||||
122
docs/source/topics/debugging.rst
Normal file
122
docs/source/topics/debugging.rst
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Debugging
|
||||
=========
|
||||
|
||||
When working with the API, chances are you'll stumble upon bugs, get stuck and start wondering how to continue. Nothing
|
||||
to actually worry about since PyroFork provides some commodities to help you in this.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Caveman Debugging
|
||||
-----------------
|
||||
|
||||
*The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.*
|
||||
|
||||
-- Brian Kernighan, "Unix for Beginners" (1979)
|
||||
|
||||
Adding ``print()`` statements in crucial parts of your code is by far the most ancient, yet efficient technique for
|
||||
debugging programs, especially considering the concurrent nature of the framework itself. PyroFork goodness in this
|
||||
respect comes with the fact that any object can be nicely printed just by calling ``print(obj)``, thus giving to you
|
||||
an insight of all its inner details.
|
||||
|
||||
Consider the following code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
me = await app.get_users("me")
|
||||
print(me) # User
|
||||
|
||||
This will show a JSON representation of the object returned by :meth:`~pyrogram.Client.get_users`, which is a
|
||||
:class:`~pyrogram.types.User` instance, in this case. The output on your terminal will be something similar to this:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"_": "User",
|
||||
"id": 123456789,
|
||||
"is_self": true,
|
||||
"is_contact": false,
|
||||
"is_mutual_contact": false,
|
||||
"is_deleted": false,
|
||||
"is_bot": false,
|
||||
"is_verified": false,
|
||||
"is_restricted": false,
|
||||
"is_support": false,
|
||||
"first_name": "PyroFork",
|
||||
"photo": {
|
||||
"_": "ChatPhoto",
|
||||
"small_file_id": "AbCdE...EdCbA",
|
||||
"small_photo_unique_id": "VwXyZ...ZyXwV",
|
||||
"big_file_id": "AbCdE...EdCbA",
|
||||
"big_photo_unique_id": "VwXyZ...ZyXwV"
|
||||
}
|
||||
}
|
||||
|
||||
As you've probably guessed already, PyroFork objects can be nested. That's how compound data are built, and nesting
|
||||
keeps going until we are left with base data types only, such as ``str``, ``int``, ``bool``, etc.
|
||||
|
||||
Accessing Attributes
|
||||
--------------------
|
||||
|
||||
Even though you see a JSON output, it doesn't mean we are dealing with dictionaries; in fact, all PyroFork types are
|
||||
fully-fledged Python objects and the correct way to access any attribute of them is by using the dot notation ``.``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
photo = me.photo
|
||||
print(photo) # ChatPhoto
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"_": "ChatPhoto",
|
||||
"small_file_id": "AbCdE...EdCbA",
|
||||
"small_photo_unique_id": "VwXyZ...ZyXwV",
|
||||
"big_file_id": "AbCdE...EdCbA",
|
||||
"big_photo_unique_id": "VwXyZ...ZyXwV"
|
||||
}
|
||||
|
||||
Checking an Object's Type
|
||||
-------------------------
|
||||
|
||||
Another thing worth talking about is how to tell and check for an object's type.
|
||||
|
||||
As you noticed already, when printing an object you'll see the special attribute ``"_"``. This is just a visual thing
|
||||
useful to show humans the object type, but doesn't really exist anywhere; any attempt in accessing it will lead to an
|
||||
error. The correct way to get the object type is by using the built-in function ``type()``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
status = me.status
|
||||
print(type(status))
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<class 'pyrogram.types.UserStatus'>
|
||||
|
||||
And to check if an object is an instance of a given class, you use the built-in function ``isinstance()``:
|
||||
|
||||
.. code-block:: python
|
||||
:name: this-py
|
||||
|
||||
from pyrogram.types import UserStatus
|
||||
|
||||
status = me.status
|
||||
print(isinstance(status, UserStatus))
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
True
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script>
|
||||
var e = document.querySelector("blockquote p.attribution");
|
||||
var s = e.innerHTML;
|
||||
|
||||
e.innerHTML = s[0] + " " + s.slice(1);
|
||||
</script>
|
||||
226
docs/source/topics/more-on-updates.rst
Normal file
226
docs/source/topics/more-on-updates.rst
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
More on Updates
|
||||
===============
|
||||
|
||||
Here we'll show some advanced usages when working with :doc:`update handlers <../start/updates>` and
|
||||
:doc:`filters <use-filters>`.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Handler Groups
|
||||
--------------
|
||||
|
||||
If you register handlers with overlapping (conflicting) filters, only the first one is executed and any other handler
|
||||
will be ignored. This is intended by design.
|
||||
|
||||
In order to handle the very same update more than once, you have to register your handler in a different dispatching
|
||||
group. Dispatching groups hold one or more handlers and are processed sequentially, they are identified by a number
|
||||
(number 0 being the default) and sorted, that is, a lower group number has a higher priority:
|
||||
|
||||
For example, take these two handlers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(filters.text | filters.sticker)
|
||||
async def text_or_sticker(client, message):
|
||||
print("Text or Sticker")
|
||||
|
||||
|
||||
@app.on_message(filters.text)
|
||||
async def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
Here, ``just_text`` is never executed because ``text_or_sticker``, which has been registered first, already handles
|
||||
texts (``filters.text`` is shared and conflicting). To enable it, register the handler using a different group:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(filters.text, group=1)
|
||||
async def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
Or, if you want ``just_text`` to be executed *before* ``text_or_sticker`` (note ``-1``, which is less than ``0``):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(filters.text, group=-1)
|
||||
async def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
With :meth:`~pyrogram.Client.add_handler` (without decorators) the same can be achieved with:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app.add_handler(MessageHandler(just_text, filters.text), -1)
|
||||
|
||||
Update propagation
|
||||
------------------
|
||||
|
||||
Registering multiple handlers, each in a different group, becomes useful when you want to handle the same update more
|
||||
than once. Any incoming update will be sequentially processed by all of your registered functions by respecting the
|
||||
groups priority policy described above. Even in case any handler raises an unhandled exception, PyroFork will still
|
||||
continue to propagate the same update to the next groups until all the handlers are done. Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(0)
|
||||
|
||||
|
||||
@app.on_message(filters.private, group=1)
|
||||
async def _(client, message):
|
||||
raise Exception("Unhandled exception!") # Simulate an unhandled exception
|
||||
|
||||
|
||||
@app.on_message(filters.private, group=2)
|
||||
async def _(client, message):
|
||||
print(2)
|
||||
|
||||
All these handlers will handle the same kind of messages, that are, messages sent or received in private chats.
|
||||
The output for each incoming update will therefore be:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
0
|
||||
Exception: Unhandled exception!
|
||||
2
|
||||
|
||||
Stop Propagation
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
In order to prevent further propagation of an update in the dispatching phase, you can do *one* of the following:
|
||||
|
||||
- Call the update's bound-method ``.stop_propagation()`` (preferred way).
|
||||
- Manually ``raise StopPropagation`` exception (more suitable for raw updates only).
|
||||
|
||||
.. note::
|
||||
|
||||
Internally, the propagation is stopped by handling a custom exception. ``.stop_propagation()`` is just an elegant
|
||||
and intuitive way to ``raise StopPropagation``; this also means that any code coming *after* calling the method
|
||||
won't be executed as your function just raised an exception to signal the dispatcher not to propagate the
|
||||
update anymore.
|
||||
|
||||
Example with ``stop_propagation()``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(0)
|
||||
|
||||
|
||||
@app.on_message(filters.private, group=1)
|
||||
async def _(client, message):
|
||||
print(1)
|
||||
message.stop_propagation()
|
||||
|
||||
|
||||
@app.on_message(filters.private, group=2)
|
||||
async def _(client, message):
|
||||
print(2)
|
||||
|
||||
Example with ``raise StopPropagation``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import StopPropagation
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(0)
|
||||
|
||||
|
||||
@app.on_message(filters.private, group=1)
|
||||
async ef _(client, message):
|
||||
print(1)
|
||||
raise StopPropagation
|
||||
|
||||
|
||||
@app.on_message(filters.private, group=2)
|
||||
async def _(client, message):
|
||||
print(2)
|
||||
|
||||
Each handler is registered in a different group, but the handler in group number 2 will never be executed because the
|
||||
propagation was stopped earlier. The output of both (equivalent) examples will be:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
0
|
||||
1
|
||||
|
||||
Continue Propagation
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As opposed to `stopping the update propagation <#stop-propagation>`_ and also as an alternative to the
|
||||
`handler groups <#handler-groups>`_, you can signal the internal dispatcher to continue the update propagation within
|
||||
**the same group** despite having conflicting filters in the next registered handler. This allows you to register
|
||||
multiple handlers with overlapping filters in the same group; to let the dispatcher process the next handler you can do
|
||||
*one* of the following in each handler you want to grant permission to continue:
|
||||
|
||||
- Call the update's bound-method ``.continue_propagation()`` (preferred way).
|
||||
- Manually ``raise ContinuePropagation`` exception (more suitable for raw updates only).
|
||||
|
||||
.. note::
|
||||
|
||||
Internally, the propagation is continued by handling a custom exception. ``.continue_propagation()`` is just an
|
||||
elegant and intuitive way to ``raise ContinuePropagation``; this also means that any code coming *after* calling the
|
||||
method won't be executed as your function just raised an exception to signal the dispatcher to continue with the
|
||||
next available handler.
|
||||
|
||||
|
||||
Example with ``continue_propagation()``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(0)
|
||||
message.continue_propagation()
|
||||
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(1)
|
||||
message.continue_propagation()
|
||||
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(2)
|
||||
|
||||
Example with ``raise ContinuePropagation``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import ContinuePropagation
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(0)
|
||||
raise ContinuePropagation
|
||||
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(1)
|
||||
raise ContinuePropagation
|
||||
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def _(client, message):
|
||||
print(2)
|
||||
|
||||
Three handlers are registered in the same group, and all of them will be executed because the propagation was continued
|
||||
in each handler (except in the last one, where is useless to do so since there is no more handlers after).
|
||||
The output of both (equivalent) examples will be:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
112
docs/source/topics/mtproto-vs-botapi.rst
Normal file
112
docs/source/topics/mtproto-vs-botapi.rst
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
MTProto vs. Bot API
|
||||
===================
|
||||
|
||||
PyroFork is a framework written from the ground up that acts as a fully-fledged Telegram client based on the MTProto
|
||||
API. This means that PyroFork is able to execute any official client and bot API action and more. This page will
|
||||
therefore show you why PyroFork might be a better choice for your project by comparing the two APIs, but first, let's
|
||||
make it clear what actually is the MTProto and the Bot API.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
What is the MTProto API?
|
||||
------------------------
|
||||
|
||||
`MTProto`_, took alone, is the name of the custom-made, open and encrypted communication protocol created by Telegram
|
||||
itself --- it's the only protocol used to exchange information between a client and the actual Telegram servers.
|
||||
|
||||
The MTProto API on the other hand, is what people for convenience call the main Telegram API in order to distinguish it
|
||||
from the Bot API. The main Telegram API is able to authorize both users and bots and is built on top of the MTProto
|
||||
encryption protocol by means of `binary data serialized`_ in a specific way, as described by the `TL language`_, and
|
||||
delivered using UDP, TCP or even HTTP as transport-layer protocol. Clients that make use of Telegram's main API, such as
|
||||
PyroFork, implement all these details.
|
||||
|
||||
.. _MTProto: https://core.telegram.org/mtproto
|
||||
.. _binary data serialized: https://core.telegram.org/mtproto/serialize
|
||||
.. _TL language: https://core.telegram.org/mtproto/TL
|
||||
|
||||
What is the Bot API?
|
||||
--------------------
|
||||
|
||||
The `Bot API`_ is an HTTP(S) interface for building normal bots using a sub-set of the main Telegram API. Bots are
|
||||
special accounts that are authorized via tokens instead of phone numbers. The Bot API is built yet again on top of the
|
||||
main Telegram API, but runs on an intermediate server application that in turn communicates with the actual Telegram
|
||||
servers using MTProto.
|
||||
|
||||
.. figure:: //_static/img/mtproto-vs-bot-api.png
|
||||
:align: center
|
||||
|
||||
.. _Bot API: https://core.telegram.org/bots/api
|
||||
|
||||
Advantages of the MTProto API
|
||||
-----------------------------
|
||||
|
||||
Here is a non-exhaustive list of all the advantages in using MTProto-based libraries -- such as PyroFork -- instead of
|
||||
the official HTTP Bot API. Using PyroFork you can:
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Authorize both user and bot identities**
|
||||
- :guilabel:`--` The Bot API only allows bot accounts
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Upload & download any file, up to 2000 MiB each (~2 GB)**
|
||||
- :guilabel:`--` The Bot API allows uploads and downloads of files only up to 50 MB / 20 MB in size (respectively).
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Has less overhead due to direct connections to Telegram**
|
||||
- :guilabel:`--` The Bot API uses an intermediate server to handle HTTP requests before they are sent to the actual
|
||||
Telegram servers.
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Run multiple sessions at once (for both user and bot identities)**
|
||||
- :guilabel:`--` The Bot API intermediate server will terminate any other session in case you try to use the same
|
||||
bot again in a parallel connection.
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Has much more detailed types and powerful methods**
|
||||
- :guilabel:`--` The Bot API types often miss some useful information about Telegram entities and some of the
|
||||
methods are limited as well.
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Obtain information about any message existing in a chat using their ids**
|
||||
- :guilabel:`--` The Bot API simply doesn't support this
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Retrieve the whole chat members list of either public or private chats**
|
||||
- :guilabel:`--` The Bot API simply doesn't support this
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Receive extra updates, such as the one about a user name change**
|
||||
- :guilabel:`--` The Bot API simply doesn't support this
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Has more meaningful errors in case something went wrong**
|
||||
- :guilabel:`--` The Bot API reports less detailed errors
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Get API version updates, and thus new features, sooner**
|
||||
- :guilabel:`--` The Bot API is simply slower in implementing new features
|
||||
34
docs/source/topics/proxy.rst
Normal file
34
docs/source/topics/proxy.rst
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
Proxy Settings
|
||||
==============
|
||||
|
||||
PyroFork supports proxies with and without authentication. This feature allows PyroFork to exchange data with Telegram
|
||||
through an intermediate SOCKS 4/5 or HTTP (CONNECT) proxy server.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To use PyroFork with a proxy, use the *proxy* parameter in the Client class. If your proxy doesn't require authorization
|
||||
you can omit ``username`` and ``password``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
proxy = {
|
||||
"scheme": "socks5", # "socks4", "socks5" and "http" are supported
|
||||
"hostname": "11.22.33.44",
|
||||
"port": 1234,
|
||||
"username": "username",
|
||||
"password": "password"
|
||||
}
|
||||
|
||||
app = Client("my_account", proxy=proxy)
|
||||
|
||||
app.run()
|
||||
65
docs/source/topics/scheduling.rst
Normal file
65
docs/source/topics/scheduling.rst
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
Scheduling Tasks
|
||||
================
|
||||
|
||||
Scheduling tasks means executing one or more functions periodically at pre-defined intervals or after a delay. This is
|
||||
useful, for example, to send recurring messages to specific chats or users.
|
||||
|
||||
This page will show examples on how to integrate PyroFork with ``apscheduler`` in both asynchronous and
|
||||
non-asynchronous contexts. For more detailed information, you can visit and learn from the library documentation.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Using apscheduler
|
||||
-----------------
|
||||
|
||||
- Install with ``pip3 install apscheduler``
|
||||
- Documentation: https://apscheduler.readthedocs.io
|
||||
|
||||
Asynchronously
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
async def job():
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
|
||||
scheduler = AsyncIOScheduler()
|
||||
scheduler.add_job(job, "interval", seconds=3)
|
||||
|
||||
scheduler.start()
|
||||
app.run()
|
||||
|
||||
Non-Asynchronously
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
def job():
|
||||
app.send_message("me", "Hi!")
|
||||
|
||||
|
||||
scheduler = BackgroundScheduler()
|
||||
scheduler.add_job(job, "interval", seconds=3)
|
||||
|
||||
scheduler.start()
|
||||
app.run()
|
||||
56
docs/source/topics/serializing.rst
Normal file
56
docs/source/topics/serializing.rst
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Object Serialization
|
||||
====================
|
||||
|
||||
Serializing means converting a PyroFork object, which exists as Python class instance, to a text string that can be
|
||||
easily shared and stored anywhere. PyroFork provides two formats for serializing its objects: one good looking for
|
||||
humans and another more compact for machines that is able to recover the original structures.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
For Humans - str(obj)
|
||||
---------------------
|
||||
|
||||
If you want a nicely formatted, human readable JSON representation of any object in the API you can use ``str(obj)``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
...
|
||||
|
||||
async with app:
|
||||
r = await app.get_chat("me")
|
||||
print(str(r))
|
||||
|
||||
.. tip::
|
||||
|
||||
When using ``print()`` you don't actually need to use ``str()`` on the object because it is called automatically, we
|
||||
have done that above just to show you how to explicitly convert a PyroFork object to JSON.
|
||||
|
||||
For Machines - repr(obj)
|
||||
------------------------
|
||||
|
||||
If you want to share or store objects for future references in a more compact way, you can use ``repr(obj)``. While
|
||||
still pretty much readable, this format is not intended for humans. The advantage of this format is that once you
|
||||
serialize your object, you can use ``eval()`` to get back the original structure; just make sure to ``import pyrogram``,
|
||||
as the process requires the package to be in scope.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pyrogram
|
||||
|
||||
...
|
||||
|
||||
async with app:
|
||||
r = await app.get_chat("me")
|
||||
|
||||
print(repr(r))
|
||||
print(eval(repr(r)) == r) # True
|
||||
|
||||
.. note::
|
||||
|
||||
Type definitions are subject to changes between versions. You should make sure to store and load objects using the
|
||||
same PyroFork version.
|
||||
306
docs/source/topics/smart-plugins.rst
Normal file
306
docs/source/topics/smart-plugins.rst
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
Smart Plugins
|
||||
=============
|
||||
|
||||
PyroFork embeds a smart, lightweight yet powerful plugin system that is meant to further simplify the organization
|
||||
of large projects and to provide a way for creating pluggable (modular) components that can be easily shared across
|
||||
different PyroFork applications with minimal boilerplate code.
|
||||
|
||||
.. tip::
|
||||
|
||||
Smart Plugins are completely optional and disabled by default.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
|
||||
your applications, you had to put your function definitions in separate files and register them inside your main script
|
||||
after importing your modules, like this:
|
||||
|
||||
.. note::
|
||||
|
||||
This is an example application that replies in private chats with two messages: one containing the same
|
||||
text message you sent and the other containing the reversed text message.
|
||||
|
||||
Example: *"PyroFork"* replies with *"PyroFork"* and *"margoryP"*
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
myproject/
|
||||
handlers.py
|
||||
main.py
|
||||
|
||||
- ``handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def echo(client, message):
|
||||
await message.reply(message.text)
|
||||
|
||||
|
||||
async def echo_reversed(client, message):
|
||||
await message.reply(message.text[::-1])
|
||||
|
||||
- ``main.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.handlers import MessageHandler
|
||||
|
||||
from handlers import echo, echo_reversed
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
app.add_handler(
|
||||
MessageHandler(
|
||||
echo,
|
||||
filters.text & filters.private))
|
||||
|
||||
app.add_handler(
|
||||
MessageHandler(
|
||||
echo_reversed,
|
||||
filters.text & filters.private),
|
||||
group=1)
|
||||
|
||||
app.run()
|
||||
|
||||
This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
|
||||
manually ``import``, manually :meth:`~pyrogram.Client.add_handler` and manually instantiate each
|
||||
:class:`~pyrogram.handlers.MessageHandler` object because you can't use decorators for your functions.
|
||||
So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically.
|
||||
|
||||
Using Smart Plugins
|
||||
-------------------
|
||||
|
||||
Setting up your PyroFork project to accommodate Smart Plugins is pretty straightforward:
|
||||
|
||||
#. Create a new folder to store all the plugins (e.g.: "plugins", "handlers", ...).
|
||||
#. Put your python files full of plugins inside. Organize them as you wish.
|
||||
#. Enable plugins in your Client.
|
||||
|
||||
.. note::
|
||||
|
||||
This is the same example application as shown above, written using the Smart Plugin system.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
myproject/
|
||||
plugins/
|
||||
handlers.py
|
||||
main.py
|
||||
|
||||
- ``plugins/handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, filters
|
||||
|
||||
|
||||
@Client.on_message(filters.text & filters.private)
|
||||
async def echo(client, message):
|
||||
await message.reply(message.text)
|
||||
|
||||
|
||||
@Client.on_message(filters.text & filters.private, group=1)
|
||||
async def echo_reversed(client, message):
|
||||
await message.reply(message.text[::-1])
|
||||
|
||||
- ``main.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
plugins = dict(root="plugins")
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
|
||||
The first important thing to note is the new ``plugins`` folder. You can put *any python file* in *any subfolder* and
|
||||
each file can contain *any decorated function* (handlers) with one limitation: within a single module (file) you must
|
||||
use different names for each decorated function.
|
||||
|
||||
The second thing is telling PyroFork where to look for your plugins: you can use the Client parameter "plugins";
|
||||
the *root* value must match the name of your plugins root folder. Your PyroFork Client instance will **automatically**
|
||||
scan the folder upon starting to search for valid handlers and register them for you.
|
||||
|
||||
Then you'll notice you can now use decorators. That's right, you can apply the usual decorators to your callback
|
||||
functions in a static way, i.e. **without having the Client instance around**: simply use ``@Client`` (Client class)
|
||||
instead of the usual ``@app`` (Client instance) and things will work just the same.
|
||||
|
||||
Specifying the Plugins to include
|
||||
---------------------------------
|
||||
|
||||
By default, if you don't explicitly supply a list of plugins, every valid one found inside your plugins root folder will
|
||||
be included by following the alphabetical order of the directory structure (files and subfolders); the single handlers
|
||||
found inside each module will be, instead, loaded in the order they are defined, from top to bottom.
|
||||
|
||||
.. note::
|
||||
|
||||
Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping
|
||||
filters included a second time will not work, by design. Learn more at :doc:`More on Updates <more-on-updates>`.
|
||||
|
||||
This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or
|
||||
exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude``
|
||||
directives in the dictionary passed as Client argument. Here's how they work:
|
||||
|
||||
- If both ``include`` and ``exclude`` are omitted, all plugins are loaded as described above.
|
||||
- If ``include`` is given, only the specified plugins will be loaded, in the order they are passed.
|
||||
- If ``exclude`` is given, the plugins specified here will be unloaded.
|
||||
|
||||
The ``include`` and ``exclude`` value is a **list of strings**. Each string containing the path of the module relative
|
||||
to the plugins root folder, in Python notation (dots instead of slashes).
|
||||
|
||||
E.g.: ``subfolder.module`` refers to ``plugins/subfolder/module.py``, with ``root="plugins"``.
|
||||
|
||||
You can also choose the order in which the single handlers inside a module are loaded, thus overriding the default
|
||||
top-to-bottom loading policy. You can do this by appending the name of the functions to the module path, each one
|
||||
separated by a blank space.
|
||||
|
||||
E.g.: ``subfolder.module fn2 fn1 fn3`` will load *fn2*, *fn1* and *fn3* from *subfolder.module*, in this order.
|
||||
|
||||
Examples
|
||||
^^^^^^^^
|
||||
|
||||
Given this plugins folder structure with three modules, each containing their own handlers (fn1, fn2, etc...), which are
|
||||
also organized in subfolders:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
myproject/
|
||||
plugins/
|
||||
subfolder1/
|
||||
plugins1.py
|
||||
- fn1
|
||||
- fn2
|
||||
- fn3
|
||||
subfolder2/
|
||||
plugins2.py
|
||||
...
|
||||
plugins0.py
|
||||
...
|
||||
...
|
||||
|
||||
- Load every handler from every module, namely *plugins0.py*, *plugins1.py* and *plugins2.py* in alphabetical order
|
||||
(files) and definition order (handlers inside files):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
plugins = dict(root="plugins")
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
- Load only handlers defined inside *plugins2.py* and *plugins0.py*, in this order:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
plugins = dict(
|
||||
root="plugins",
|
||||
include=[
|
||||
"subfolder2.plugins2",
|
||||
"plugins0"
|
||||
]
|
||||
)
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
- Load everything except the handlers inside *plugins2.py*:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
plugins = dict(
|
||||
root="plugins",
|
||||
exclude=["subfolder2.plugins2"]
|
||||
)
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
- Load only *fn3*, *fn1* and *fn2* (in this order) from *plugins1.py*:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
plugins = dict(
|
||||
root="plugins",
|
||||
include=["subfolder1.plugins1 fn3 fn1 fn2"]
|
||||
)
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
Load/Unload Plugins at Runtime
|
||||
------------------------------
|
||||
|
||||
In the previous section we've explained how to specify which plugins to load and which to ignore before your Client
|
||||
starts. Here we'll show, instead, how to unload and load again a previously registered plugin at runtime.
|
||||
|
||||
Each function decorated with the usual ``on_message`` decorator (or any other decorator that deals with Telegram
|
||||
updates) will be modified in such a way that a special ``handlers`` attribute pointing to a list of tuples of
|
||||
*(handler: Handler, group: int)* is attached to the function object itself.
|
||||
|
||||
- ``plugins/handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@Client.on_message(filters.text & filters.private)
|
||||
async def echo(client, message):
|
||||
await message.reply(message.text)
|
||||
|
||||
print(echo)
|
||||
print(echo.handlers)
|
||||
|
||||
- Printing ``echo`` will show something like ``<function echo at 0x10e3b6598>``.
|
||||
|
||||
- Printing ``echo.handlers`` will reveal the handlers, that is, a list of tuples containing the actual handlers and
|
||||
the groups they were registered on ``[(<MessageHandler object at 0x10e3abc50>, 0)]``.
|
||||
|
||||
Unloading
|
||||
^^^^^^^^^
|
||||
|
||||
In order to unload a plugin, all you need to do is obtain a reference to it by importing the relevant module and call
|
||||
:meth:`~pyrogram.Client.remove_handler` Client's method with your function's *handler* instance:
|
||||
|
||||
- ``main.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from plugins.handlers import echo
|
||||
|
||||
handlers = echo.handlers
|
||||
|
||||
for h in handlers:
|
||||
app.remove_handler(*h)
|
||||
|
||||
The star ``*`` operator is used to unpack the tuple into positional arguments so that *remove_handler* will receive
|
||||
exactly what is needed. The same could have been achieved with:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
handlers = echo.handlers
|
||||
handler, group = handlers[0]
|
||||
|
||||
app.remove_handler(handler, group)
|
||||
|
||||
Loading
|
||||
^^^^^^^
|
||||
|
||||
Similarly to the unloading process, in order to load again a previously unloaded plugin you do the same, but this time
|
||||
using :meth:`~pyrogram.Client.add_handler` instead. Example:
|
||||
|
||||
- ``main.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from plugins.handlers import echo
|
||||
|
||||
...
|
||||
|
||||
handlers = echo.handlers
|
||||
|
||||
for h in handlers:
|
||||
app.add_handler(*h)
|
||||
88
docs/source/topics/speedups.rst
Normal file
88
docs/source/topics/speedups.rst
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
Speedups
|
||||
========
|
||||
|
||||
PyroFork's speed can be boosted up by using TgCrypto and uvloop.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
TgCrypto
|
||||
--------
|
||||
|
||||
TgCrypto_ is a high-performance, easy-to-install cryptography library specifically written in C for PyroFork as a Python
|
||||
extension. It is a replacement for a slower Python-only alternative and implements the cryptographic algorithms Telegram
|
||||
requires, namely: AES-256-IGE, AES-256-CTR and AES-256-CBC.
|
||||
|
||||
Installation
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip3 install -U tgcrypto
|
||||
|
||||
Usage
|
||||
^^^^^
|
||||
|
||||
PyroFork will automatically make use of TgCrypto when detected, all you need to do is to install it.
|
||||
|
||||
uvloop
|
||||
------
|
||||
|
||||
uvloop_ is a fast, drop-in replacement of the built-in asyncio event loop. uvloop is implemented in Cython and uses
|
||||
libuv under the hood. It makes asyncio 2-4x faster.
|
||||
|
||||
Installation
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip3 install -U uvloop
|
||||
|
||||
Usage
|
||||
^^^^^
|
||||
|
||||
Call ``uvloop.install()`` before calling ``asyncio.run()`` or ``app.run()``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import uvloop
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
|
||||
async def main():
|
||||
app = Client("my_account")
|
||||
|
||||
async with app:
|
||||
print(await app.get_me())
|
||||
|
||||
|
||||
uvloop.install()
|
||||
asyncio.run(main())
|
||||
|
||||
The ``uvloop.install()`` call also needs to be placed before creating a Client instance.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import uvloop
|
||||
from pyrogram import Client
|
||||
|
||||
uvloop.install()
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message()
|
||||
async def hello(client, message):
|
||||
print(await client.get_me())
|
||||
|
||||
|
||||
app.run()
|
||||
|
||||
.. _TgCrypto: https://github.com/pyrogram/tgcrypto
|
||||
.. _uvloop: https://github.com/MagicStack/uvloop
|
||||
123
docs/source/topics/storage-engines.rst
Normal file
123
docs/source/topics/storage-engines.rst
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
Storage Engines
|
||||
===============
|
||||
|
||||
Every time you login to Telegram, some personal piece of data are created and held by both parties (the client, PyroFork
|
||||
and the server, Telegram). This session data is uniquely bound to your own account, indefinitely (until you logout or
|
||||
decide to manually terminate it) and is used to authorize a client to execute API calls on behalf of your identity.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Persisting Sessions
|
||||
-------------------
|
||||
|
||||
In order to make a client reconnect successfully between restarts, that is, without having to start a new
|
||||
authorization process from scratch each time, PyroFork needs to store the generated session data somewhere.
|
||||
|
||||
Different Storage Engines
|
||||
-------------------------
|
||||
|
||||
PyroFork offers two different types of storage engines: a **File Storage** and a **Memory Storage**.
|
||||
These engines are well integrated in the framework and require a minimal effort to set up. Here's how they work:
|
||||
|
||||
File Storage
|
||||
^^^^^^^^^^^^
|
||||
|
||||
This is the most common storage engine. It is implemented by using **SQLite**, which will store the session details.
|
||||
The database will be saved to disk as a single portable file and is designed to efficiently store and retrieve
|
||||
data whenever they are needed.
|
||||
|
||||
To use this type of engine, simply pass any name of your choice to the ``name`` parameter of the
|
||||
:obj:`~pyrogram.Client` constructor, as usual:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
async with Client("my_account") as app:
|
||||
print(await app.get_me())
|
||||
|
||||
Once you successfully log in (either with a user or a bot identity), a session file will be created and saved to disk as
|
||||
``my_account.session``. Any subsequent client restart will make PyroFork search for a file named that way and the
|
||||
session database will be automatically loaded.
|
||||
|
||||
Memory Storage
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
In case you don't want to have any session file saved to disk, you can use an in-memory storage by passing True to the
|
||||
``in_memory`` parameter of the :obj:`~pyrogram.Client` constructor:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
async with Client("my_account", in_memory=True) as app:
|
||||
print(await app.get_me())
|
||||
|
||||
This storage engine is still backed by SQLite, but the database exists purely in memory. This means that, once you stop
|
||||
a client, the entire database is discarded and the session details used for logging in again will be lost forever.
|
||||
|
||||
Mongodb Storage
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
In case you want to have persistent session but you don't have persistent storage you can use mongodb storage by passing
|
||||
mongodb config as ``dict`` to the ``mongodb`` parameter of the :obj:`~pyrogram.Client` constructor:
|
||||
|
||||
*Using async_pymongo (Recommended for python3.9+):*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from async_pymongo import AsyncClient
|
||||
from pyrogram import Client
|
||||
|
||||
conn = AsyncClient("mongodb://...")
|
||||
|
||||
async with Client("my_account", mongodb=dict(connection=conn, remove_peers=False)) as app:
|
||||
print(await app.get_me())
|
||||
|
||||
*Using motor:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from pyrogram import Client
|
||||
|
||||
conn = AsyncIOMotorClient("mongodb://...")
|
||||
|
||||
async with Client("my_account", mongodb=dict(connection=conn, remove_peers=False)) as app:
|
||||
print(await app.get_me())
|
||||
|
||||
This storage engine is backed by MongoDB, a session will be created and saved to mongodb database. Any subsequent client
|
||||
restart will make PyroFork search for a database named that way and the session database will be automatically loaded.
|
||||
|
||||
Session Strings
|
||||
---------------
|
||||
|
||||
In case you want to use an in-memory storage, but also want to keep access to the session you created, call
|
||||
:meth:`~pyrogram.Client.export_session_string` anytime before stopping the client...
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
async with Client("my_account", in_memory=True) as app:
|
||||
print(await app.export_session_string())
|
||||
|
||||
...and save the resulting string. You can use this string by passing it as Client argument the next time you want to
|
||||
login using the same session; the storage used will still be in-memory:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
session_string = "...ZnUIFD8jsjXTb8g_vpxx48k1zkov9sapD-tzjz-S4WZv70M..."
|
||||
|
||||
async with Client("my_account", session_string=session_string) as app:
|
||||
print(await app.get_me())
|
||||
|
||||
Session strings are useful when you want to run authorized PyroFork clients on platforms where their ephemeral
|
||||
filesystems makes it harder for a file-based storage engine to properly work as intended.
|
||||
88
docs/source/topics/synchronous.rst
Normal file
88
docs/source/topics/synchronous.rst
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
Synchronous Usage
|
||||
=================
|
||||
|
||||
PyroFork is an asynchronous framework and as such is subject to the asynchronous rules. It can, however, run in
|
||||
synchronous mode (also known as non-asynchronous or sync/non-async for short). This mode exists mainly as a convenience
|
||||
way for invoking methods without the need of ``async``/``await`` keywords and the extra boilerplate, but **it's not the
|
||||
intended way to use the framework**.
|
||||
|
||||
You can use PyroFork in this synchronous mode when you want to write something short and contained without the
|
||||
async boilerplate or in case you want to combine PyroFork with other libraries that are not async.
|
||||
|
||||
.. warning::
|
||||
|
||||
You have to be very careful when using the framework in its synchronous, non-native form, especially when combined
|
||||
with other non-async libraries because thread blocking operations that clog the asynchronous event loop underneath
|
||||
will make the program run erratically.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Synchronous Invocations
|
||||
-----------------------
|
||||
|
||||
The following is a standard example of running asynchronous functions with Python's asyncio.
|
||||
PyroFork is being used inside the main function with its asynchronous interface.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from pyrogram import Client
|
||||
|
||||
|
||||
async def main():
|
||||
app = Client("my_account")
|
||||
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
To run PyroFork synchronously, use the non-async context manager as shown in the following example.
|
||||
As you can see, the non-async example becomes less cluttered.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
app.send_message("me", "Hi!")
|
||||
|
||||
Synchronous handlers
|
||||
--------------------
|
||||
|
||||
You can also have synchronous handlers; you only need to define the callback function without using ``async def`` and
|
||||
invoke API methods by not placing ``await`` in front of them. Mixing ``def`` and ``async def`` handlers together is also
|
||||
possible.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message()
|
||||
async def handler1(client, message):
|
||||
await message.forward("me")
|
||||
|
||||
@app.on_edited_message()
|
||||
def handler2(client, message):
|
||||
message.forward("me")
|
||||
|
||||
uvloop usage
|
||||
------------
|
||||
|
||||
When using PyroFork in its synchronous mode combined with uvloop, you need to call ``uvloop.install()`` before importing
|
||||
PyroFork.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import uvloop
|
||||
uvloop.install()
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
...
|
||||
41
docs/source/topics/test-servers.rst
Normal file
41
docs/source/topics/test-servers.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Test Servers
|
||||
============
|
||||
|
||||
If you wish to test your application in a separate environment, PyroFork is able to authorize your account into
|
||||
Telegram's test servers without hassle. All you need to do is start a new session (e.g.: "my_account_test") using
|
||||
``test_mode=True``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
async with Client("my_account_test", test_mode=True) as app:
|
||||
print(await app.get_me())
|
||||
|
||||
.. note::
|
||||
|
||||
If this is the first time you login into test servers, you will be asked to register your account first.
|
||||
Accounts registered on test servers reside in a different, parallel instance of a Telegram server.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Test Mode in Official Apps
|
||||
--------------------------
|
||||
|
||||
You can also login yourself into test servers using official desktop apps, such as Telegram Web and Telegram Desktop:
|
||||
|
||||
- **Telegram Web**: Login here: https://web.telegram.org/?test=1
|
||||
- **Telegram Desktop**: Hold ``Alt+Shift`` and right click on "Add account", then choose "Test server".
|
||||
|
||||
Test Numbers
|
||||
------------
|
||||
|
||||
Beside normal numbers, the test environment allows you to login with reserved test numbers.
|
||||
Valid phone numbers follow the pattern ``99966XYYYY``, where ``X`` is the DC number (1 to 3) and ``YYYY`` are random
|
||||
numbers. Users with such numbers always get ``XXXXX`` or ``XXXXXX`` as the confirmation code (the DC number, repeated
|
||||
five or six times).
|
||||
243
docs/source/topics/text-formatting.rst
Normal file
243
docs/source/topics/text-formatting.rst
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
Text Formatting
|
||||
===============
|
||||
|
||||
.. role:: strike
|
||||
:class: strike
|
||||
|
||||
.. role:: underline
|
||||
:class: underline
|
||||
|
||||
.. role:: bold-underline
|
||||
:class: bold-underline
|
||||
|
||||
.. role:: strike-italic
|
||||
:class: strike-italic
|
||||
|
||||
PyroFork uses a custom Markdown dialect for text formatting which adds some unique features that make writing styled
|
||||
texts easier in both Markdown and HTML. You can send sophisticated text messages and media captions using a
|
||||
variety of decorations that can also be nested in order to combine multiple styles together.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Basic Styles
|
||||
------------
|
||||
|
||||
When formatting your messages, you can choose between Markdown-style, HTML-style or both (default). The following is a
|
||||
list of the basic styles currently supported by PyroFork.
|
||||
|
||||
- **bold**
|
||||
- *italic*
|
||||
- :strike:`strike`
|
||||
- :underline:`underline`
|
||||
- spoiler
|
||||
- `text URL <https://pyrogram.org>`_
|
||||
- `user text mention <tg://user?id=123456789>`_
|
||||
- ``inline fixed-width code``
|
||||
- .. code-block:: text
|
||||
|
||||
pre-formatted
|
||||
fixed-width
|
||||
code block
|
||||
|
||||
Markdown Style
|
||||
--------------
|
||||
|
||||
To strictly use this mode, pass :obj:`~pyrogram.enums.ParseMode.MARKDOWN` to the *parse_mode* parameter when using
|
||||
:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
**bold**
|
||||
|
||||
__italic__
|
||||
|
||||
--underline--
|
||||
|
||||
~~strike~~
|
||||
|
||||
||spoiler||
|
||||
|
||||
[text URL](https://pyrogram.org/)
|
||||
|
||||
[text user mention](tg://user?id=123456789)
|
||||
|
||||
`inline fixed-width code`
|
||||
|
||||
```
|
||||
pre-formatted
|
||||
fixed-width
|
||||
code block
|
||||
```
|
||||
|
||||
**Example**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import enums
|
||||
|
||||
await app.send_message(
|
||||
"me",
|
||||
(
|
||||
"**bold**, "
|
||||
"__italic__, "
|
||||
"--underline--, "
|
||||
"~~strike~~, "
|
||||
"||spoiler||, "
|
||||
"[URL](https://pyrogram.org), "
|
||||
"`code`, "
|
||||
"```"
|
||||
"for i in range(10):\n"
|
||||
" print(i)"
|
||||
"```"
|
||||
),
|
||||
parse_mode=enums.ParseMode.MARKDOWN
|
||||
)
|
||||
|
||||
HTML Style
|
||||
----------
|
||||
|
||||
To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode* parameter when using
|
||||
:meth:`~pyrogram.Client.send_message`. The following tags are currently supported:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<b>bold</b>, <strong>bold</strong>
|
||||
|
||||
<i>italic</i>, <em>italic</em>
|
||||
|
||||
<u>underline</u>
|
||||
|
||||
<s>strike</s>, <del>strike</del>, <strike>strike</strike>
|
||||
|
||||
<spoiler>spoiler</spoiler>
|
||||
|
||||
<a href="https://pyrogram.org/">text URL</a>
|
||||
|
||||
<a href="tg://user?id=123456789">inline mention</a>
|
||||
|
||||
<code>inline fixed-width code</code>
|
||||
|
||||
<emoji id="12345678901234567890">🔥</emoji>
|
||||
|
||||
<pre>
|
||||
pre-formatted
|
||||
fixed-width
|
||||
code block
|
||||
</pre>
|
||||
|
||||
**Example**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import enums
|
||||
|
||||
await app.send_message(
|
||||
"me",
|
||||
(
|
||||
"<b>bold</b>, "
|
||||
"<i>italic</i>, "
|
||||
"<u>underline</u>, "
|
||||
"<s>strike</s>, "
|
||||
"<spoiler>spoiler</spoiler>, "
|
||||
"<a href=\"https://pyrogram.org/\">URL</a>, "
|
||||
"<code>code</code>\n\n"
|
||||
"<pre>"
|
||||
"for i in range(10):\n"
|
||||
" print(i)"
|
||||
"</pre>"
|
||||
),
|
||||
parse_mode=enums.ParseMode.HTML
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
All ``<``, ``>`` and ``&`` symbols that are not a part of a tag or an HTML entity must be replaced with the
|
||||
corresponding HTML entities (``<`` with ``<``, ``>`` with ``>`` and ``&`` with ``&``). You can use this
|
||||
snippet to quickly escape those characters:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import html
|
||||
|
||||
text = "<my text>"
|
||||
text = html.escape(text)
|
||||
|
||||
print(text)
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<my text>
|
||||
|
||||
Different Styles
|
||||
----------------
|
||||
|
||||
By default, when ignoring the *parse_mode* parameter, both Markdown and HTML styles are enabled together.
|
||||
This means you can combine together both syntaxes in the same text:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
await app.send_message("me", "**bold**, <i>italic</i>")
|
||||
|
||||
Result:
|
||||
|
||||
**bold**, *italic*
|
||||
|
||||
If you don't like this behaviour you can always choose to only enable either Markdown or HTML in strict mode by passing
|
||||
:obj:`~pyrogram.enums.MARKDOWN` or :obj:`~pyrogram.enums.HTML` as argument to the *parse_mode* parameter.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import enums
|
||||
|
||||
await app.send_message("me", "**bold**, <i>italic</i>", parse_mode=enums.ParseMode.MARKDOWN)
|
||||
await app.send_message("me", "**bold**, <i>italic</i>", parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
Result:
|
||||
|
||||
**bold**, <i>italic</i>
|
||||
|
||||
\*\*bold**, *italic*
|
||||
|
||||
In case you want to completely turn off the style parser, simply pass :obj:`~pyrogram.enums.DISABLED` to *parse_mode*.
|
||||
The text will be sent as-is.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import enums
|
||||
|
||||
await app.send_message("me", "**bold**, <i>italic</i>", parse_mode=enums.ParseMode.DISABLED)
|
||||
|
||||
Result:
|
||||
|
||||
\*\*bold**, <i>italic</i>
|
||||
|
||||
Nested and Overlapping Entities
|
||||
-------------------------------
|
||||
|
||||
You can also style texts with more than one decoration at once by nesting entities together. For example, you can send
|
||||
a text message with both :bold-underline:`bold and underline` styles, or a text that has both :strike-italic:`italic and
|
||||
strike` styles, and you can still combine both Markdown and HTML together.
|
||||
|
||||
Here there are some example texts you can try sending:
|
||||
|
||||
**Markdown**:
|
||||
|
||||
- ``**bold, --underline--**``
|
||||
- ``**bold __italic --underline ~~strike~~--__**``
|
||||
- ``**bold __and** italic__``
|
||||
|
||||
**HTML**:
|
||||
|
||||
- ``<b>bold, <u>underline</u></b>``
|
||||
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
||||
- ``<b>bold <i>and</b> italic</i>``
|
||||
|
||||
**Combined**:
|
||||
|
||||
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
||||
- ``**and also <i>overlap** --entities</i> this way--``
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue