Compare commits

...

92 commits
main ... 2.1.7

Author SHA1 Message Date
wulan17
cdc46b10c8
PyroFork: Bump version to 2.1.7
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-05-10 19:31:34 +07:00
Animesh Murmu
6b29171e29
Pyrofork: Add Mongodb Session Storage
Signed-off-by: wulan17 <wulan17@nusantararom.org>
Co-authored-by: wulan17 <wulan17@nusantararom.org>
2023-05-10 19:29:35 +07:00
Dan
91ff2dc82d
Move the CDN DC IPv6 to the correct mapping
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-05-10 19:10:10 +07:00
Dan
c3eddf234c
Add RSA public keys & IP addresses for some CDN DCs
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-05-10 19:10:10 +07:00
Dan
fadd6bc147
Update API schema to Layer 158
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-05-10 19:10:09 +07:00
ff4ee9dae8
Update FUNDING.yml 2023-05-09 22:58:41 +07:00
wulan17
c0d9564843
PyroFork: Bump version to 2.1.6
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:36:43 +07:00
MrMissx
2378fb7800
Fix AttributeError when received ChatForbidden
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:39 +07:00
Alisson Lauffer
5c78995343
Bump aiosqlite to latest version
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:39 +07:00
reaitten
344256d92b
InputMessageContent.write is a coroutine
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:39 +07:00
Deshdeepak
08248222bb
Add file_name where missing and pass thumb as Union
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:39 +07:00
Devesh Pal
9bb83e9319
Add bound method stop() to the Poll object
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:38 +07:00
Hitalo
c35e60de94
Move to aiosqlite and enable WAL
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:38 +07:00
Alisson Lauffer
5d5e4b4845
Make some methods static
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:38 +07:00
wulan17
1cfad73e95
PyroFork: Add usernames field to User
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-15 01:28:38 +07:00
664b525530
Merge pull request #1 from DoellBarr/master
Fix NameError on line 240
2023-04-12 17:21:59 +07:00
Shohih Abdul
1d4948309f
Fix NameError on line 240 2023-04-12 14:03:22 +07:00
wulan17
caf80f239b
PyroFork: Fix derps
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 23:11:14 +07:00
wulan17
d5b2a76fc6
PyroFork: Bump version to 2.1.5
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:29:36 +07:00
wulan17
f38d90cc0a
PyroFork: Add AddStickerToSet Methods
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:56 +07:00
wulan17
7a58c865b5
PyroFork: Add CreateStickerSet Methods
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:56 +07:00
wulan17
9966bd92a5
PyroFork: Add GetStickerSet methods and StickerSet types
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:56 +07:00
wulan17
2cd117f301
PyroFork: Add usernames field to Chat
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:56 +07:00
Alisson Lauffer
4401c62244
Add full_name property to User and Chat objects
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:56 +07:00
Nick
2afbe7f4fd
Update API schema to Layer 157
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:55 +07:00
Nick
66c7d64b6b
Update API schema to Layer 156
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-04-10 22:28:55 +07:00
wulan17
cbbd0e0dd2
PyroFork: Build docs only on new release
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 19:29:46 +07:00
wulan17
99e3f3e317
PyroFork: Bump version to 2.1.4
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 01:04:07 +07:00
Nick
ab1dde5f79
Update API schema to Layer 155
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 01:01:56 +07:00
Nick
252a49332d
Update API schema to Layer 154
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 01:01:56 +07:00
Dan
d398b5b29c
Separate cases between Channel and ChannelForbidden
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 00:59:21 +07:00
Dan
8940c7d1f6
Update chat username parsing in case of multiple usernames
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 00:59:20 +07:00
Dan
3163030574
Update send_inline_bot_result return type hint
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 00:59:20 +07:00
Jins Mathew
cb7ba4f821
Add missing has_spoiler parameter to reply_{animation,photo,video}
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-03-17 00:58:52 +07:00
wulan17
cb60c6ae8d
PyroFork: Update API schema to Layer 152
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-02-04 20:08:24 +07:00
wulan17
84b4d2181b
PyroFork: Bump version to 2.1.3
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-30 01:22:44 +07:00
ab7ab16356
Pyrofork: Release to pypi 2023-01-30 01:21:53 +07:00
wulan17
6331a5500e
PyroFork: Update README.md and setup,py
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-30 01:21:53 +07:00
wulan17
fbe56d5426
PyroFork: Bump version to 2.1.2
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-30 01:20:48 +07:00
kkwilllo
1d113f8aa4
add min & max id support
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-17 22:13:54 +07:00
wulan17
034a4d6041
PyroFork: More cleanup
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-17 20:45:50 +07:00
wulan17
42a2f04d8e
Revert "PyroFork: Add listen and ask"
This reverts commit e39fdcca0e.

Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-17 20:43:44 +07:00
wulan17
f55d75d3bb
PyroFork: Add support to send animation in media group
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-14 01:02:14 +07:00
Dan
c484e82810
Sort the lists of known errors 2023-01-11 21:43:31 +07:00
Mahesh
30822dabff
Add BUTTON_USER_PRIVACY_RESTRICTED to the list of known errors (#1193)
* Add BUTTON_USER_PRIVACY_RESTRICTED to known errors

* Update 400_BAD_REQUEST.tsv

Co-authored-by: Dan <14043624+delivrance@users.noreply.github.com>
2023-01-11 21:43:31 +07:00
Dan
3a88297a9a
Add INVITE_REQUEST_SENT to known errors 2023-01-11 21:43:31 +07:00
Nick
231f1a1620
Add BOT_ONESIDE_NOT_AVAIL to known errors (#1073)
* `BOT_ONESIDE_NOT_AVAIL`

* Update 400_BAD_REQUEST.tsv

Co-authored-by: Dan <14043624+delivrance@users.noreply.github.com>
2023-01-11 21:43:17 +07:00
wulan17
0f60e05fce
PyroFork: Bump version to 2.1.1
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-05 01:59:32 +07:00
Cezar Pauxis
e39fdcca0e
PyroFork: Add listen and ask
Co-authored-by: wulan17 <wulan17@nusantararom.org>
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-05 01:58:09 +07:00
wulan17
00fb071215
PyroFork: docs: Add missing ChatJoinedByRequest, PeerUser and PeerChannel
and some cleanup

Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-04 11:02:48 +07:00
wulan17
609d8985d4
PyroFork: Cleanup parameter description
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-04 09:52:13 +07:00
wulan17
e15e3d7d50
PyroFork: Add get_forum_topic and get_forum_topic_by_id methods
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-03 15:52:31 +07:00
wulan17
b1354d5579
PyroFork: docs: Add usable by
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-02 18:50:49 +07:00
wulan17
2a8a01aeb5
PyroFork: Update READNE
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-02 15:49:05 +07:00
wulan17
bec44280a4
PyroFork: Rebrand docs
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-02 15:49:05 +07:00
wulan17
41b771f4bf
PyroFork: Update docs
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-02 15:49:03 +07:00
wulan17
d91b933715
PyroFork: Bring back docs
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-02 15:04:23 +07:00
wulan17
b2158f702a
PyroFork: Cleanup
Signed-off-by: wulan17 <galihgustip@gmail.com>
2023-01-02 10:00:36 +07:00
wulan17
97f0ecc7c9
PyroFork: Add CloseGeneralTopic, EditGeneralTopic, ReopenGeneralTopic, HideGeneralTopic. UnhideGeneralTopic, and some cleanup
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-02 00:40:04 +07:00
wulan17
b64d33dca0
PyroFork: rebrand
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-01 23:41:56 +07:00
Dan
482798c2fc
Set has_media_spoiler only in case of Photo, Video or Animation media 2023-01-01 23:12:45 +07:00
Dan
64177b533c
Fix resolving peers for users with multiple usernames
This currently makes it work for the first available username only
2023-01-01 23:12:45 +07:00
Dan
3c0e86a167
Add support for email sign in codes
Fixes #1183
2023-01-01 23:12:45 +07:00
Dan
09ad827374
Add media spoiler support for other relevant methods
- send_media_group()
- edit_message_media()
- edit_inline_media()
2023-01-01 23:12:45 +07:00
Dan
94c589ed43
Add the field is_persistent to the class ReplyKeyboardMarkup 2023-01-01 23:12:44 +07:00
Dan
77cfaa0ff4
Add the field has_spoiler to relevant InputMedia* classes
- InputMediaPhoto
- InputMediaVideo
- InputMediaAnimation
2023-01-01 23:12:44 +07:00
Dan
28307ca58e
Add media_spoiler filter 2023-01-01 23:12:44 +07:00
Dan
65b045ff2d
Add the parameter has_spoiler to relevant send_* media methods
- send_photo()
- send_video()
- send_animation()
2023-01-01 23:11:28 +07:00
Dan
b865512c68
Add the field has_media_spoiler to the class Message 2023-01-01 23:11:15 +07:00
KyMaP13
b0ac808f2e
Add VOICE_MESSAGES_FORBIDDEN (#1151)
* add VOICE_MESSAGES_FORBIDDEN

* Update 400_BAD_REQUEST.tsv

Co-authored-by: onefedov <onefedov@yandex-team.ru>
Co-authored-by: Dan <14043624+delivrance@users.noreply.github.com>
2023-01-01 23:11:07 +07:00
omg-xtao
3e219771bd
Add support for Fragment SMS codes (#1170) 2023-01-01 23:11:07 +07:00
wulan17
aedade2ff2
Pyrogram: add message_thread_id parameter to send_chat_action
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-01 22:53:36 +07:00
wulan17
8428de1722
Pyrogram: add GeneralTopicHidden and GeneralTopicUnhidden service messages types
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2023-01-01 22:48:39 +07:00
Nick
85184be318
Update API schema to Layer 151
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-28 01:04:35 +07:00
wulan17
d89b083bf0
Pyrogram: Add message_thread_id parameter to send_inline_bot_result()
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-17 15:39:11 +07:00
wulan17
ede9af3e00
Pyrogram: types: Message: Add error handling and is_topic_message
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-17 15:30:58 +07:00
Dan
abf1b2fece
Update Pyrogram to v2.0.70 2022-12-14 13:36:53 +07:00
Anton Kovalevich
b038890745
Handle all given updates, avoid short circuit (#1162) 2022-12-14 13:36:52 +07:00
wulan17
e0b7576418
Pyrogram: Add chat_joined_by_request
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-14 13:36:52 +07:00
wulan17
86883a3b91
Pyrogram: Cleanup
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-14 13:34:43 +07:00
wulan17
e38ceb08cc
Pyrogram: utils: Check if messages has topics atribut
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-10 13:52:57 +07:00
wulan17
b76bf48862
Pyrogram: Add {CREATED,EDITED,DELETED}_FORUM_TOPIC ChatEvent
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 23:41:40 +07:00
wulan17
9f32305c3a
Pyrogram: Add message_thread_id parameter to copy_message method
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 23:41:40 +07:00
wulan17
6edc4256c3
Pyrogram: Add {create,close,reopen,edit,delete}_forum_topic methods
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 23:41:39 +07:00
wulan17
a1aa281614
Pyrogram: Add ForumTopic and some cleanup
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:24:31 +07:00
wulan17
00520678f6
Pyrogram: Add message_thread_id parameter to send_game() method and copy() bound method
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:12:06 +07:00
wulan17
f22cc34c9a
Pyrogram: Add message_thread_id parameter to forward_message() method and forward() bound method
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:12:05 +07:00
wulan17
9b92492553
Pyrogram: Add message_thread_id parameter to send_{animation,audio,cached_media,contact,dice,document,location,media_group,message,photo,poll,sticker,venue,video,video_note,voice} methods
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:07:36 +07:00
wulan17
c9e36cc150
Pyrogram: Add manage_topics parameter to promote_chat_member, restrict_chat_member, and set_chat_permissions methods
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:07:36 +07:00
wulan17
eeb1338c48
Pyrogram: Add can_manage_topics fields to ChatPrivileges and ChatPermissions class
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:07:35 +07:00
wulan17
115b9877b6
Pyrogram: Add ForumTopicCreated, ForumTopicClosed, ForumTopicReopened, ForumTopicEdited service message types
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:07:35 +07:00
wulan17
6f8aaa449c
Pyrogram: Add message_thread_id and is_topic_message fields to Message class, and is_forum fields to Chat class
Signed-off-by: wulan17 <wulan17@nusantararom.org>
2022-12-09 18:07:27 +07:00
191 changed files with 6958 additions and 344 deletions

5
.github/FUNDING.yml vendored
View file

@ -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"]

17
.github/workflows/build-docs.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Build-docs
on:
release:
types: [published]
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 }}

40
.github/workflows/python-publish.yml vendored Normal file
View file

@ -0,0 +1,40 @@
# 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:
release:
types: [published]
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/*

View file

@ -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)

View file

@ -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
View 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

View file

@ -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

View file

@ -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

View file

@ -73,6 +73,19 @@ Chats
{chats}
Stickers
-----
.. autosummary::
:nosignatures:
{stickers}
.. toctree::
:hidden:
{stickers}
Users
-----

View file

@ -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
1 id message
28 BOT_INVALID This is not a valid bot
29 BOT_METHOD_INVALID The method can't be used by bots
30 BOT_MISSING This method can only be run by a bot
31 BOT_ONESIDE_NOT_AVAIL Bots can't pin messages for one side only in private chats
32 BOT_PAYMENTS_DISABLED This method can only be run by a bot
33 BOT_POLLS_DISABLED Sending polls by bots has been disabled
34 BOT_RESPONSE_TIMEOUT The bot did not answer to the callback query in time
39 BUTTON_DATA_INVALID The button callback data is invalid or too large
40 BUTTON_TYPE_INVALID The type of one of the buttons you provided is invalid
41 BUTTON_URL_INVALID The button url is invalid
42 BUTTON_USER_PRIVACY_RESTRICTED The privacy settings of the user specified in a keyboard button do not allow creating such button
43 CALL_ALREADY_ACCEPTED The call is already accepted
44 CALL_ALREADY_DECLINED The call is already declined
45 CALL_PEER_INVALID The provided call peer object is invalid
102 ENCRYPTION_DECLINED The secret chat was declined
103 ENCRYPTION_ID_INVALID The provided secret chat id is invalid
104 ENTITIES_TOO_LONG The entity provided contains data that is too long, or you passed too many entities to this message
105 ENTITY_BOUNDS_INVALID The message entity bounds are invalid
106 ENTITY_MENTION_USER_INVALID The mentioned entity is not an user
107 ERROR_TEXT_EMPTY The provided error message is empty
108 EXPIRE_DATE_INVALID The expiration date is invalid
156 INVITE_HASH_EMPTY The invite hash is empty
157 INVITE_HASH_EXPIRED The chat invite link is no longer valid
158 INVITE_HASH_INVALID The invite link hash is invalid
159 INVITE_REQUEST_SENT The request to join this chat or channel has been successfully sent
160 INVITE_REVOKED_MISSING The action required a chat invite link to be revoked first
161 LANG_PACK_INVALID The provided language pack is invalid
162 LASTNAME_INVALID The last name is invalid
300 STICKER_PNG_DIMENSIONS The sticker png dimensions are invalid
301 STICKER_PNG_NOPNG Stickers must be png files but the provided image was not a png
302 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
303 STICKER_THUMB_PNG_NOPNG A png sticker thumbnail file was expected, but something else was provided
304 STICKER_VIDEO_NOWEBM A webm video file was expected, but something else was provided
305 TAKEOUT_INVALID The takeout id is invalid
306 TAKEOUT_REQUIRED The method must be invoked inside a takeout session
307 TEMP_AUTH_KEY_EMPTY The temporary auth key provided is empty
344 USER_NOT_PARTICIPANT The user is not a member of this chat
345 VIDEO_CONTENT_TYPE_INVALID The video content type is invalid (i.e.: not streamable)
346 VIDEO_FILE_INVALID The video file is invalid
347 VOICE_MESSAGES_FORBIDDEN Voice messages are restricted
348 VOLUME_LOC_NOT_FOUND The volume location can't be found
349 WALLPAPER_FILE_INVALID The provided file cannot be used as a wallpaper
350 WALLPAPER_INVALID The input wallpaper was not valid
357 WEBDOCUMENT_URL_INVALID The web document URL is invalid
358 WEBPAGE_CURL_FAILED Telegram server could not fetch the provided URL
359 WEBPAGE_MEDIA_EMPTY The URL doesn't contain any valid media
360 YOU_BLOCKED_USER You blocked this user
ENTITY_BOUNDS_INVALID The message entity bounds are invalid

View file

@ -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
1 id message
15 MESSAGE_AUTHOR_REQUIRED You are not the author of this message
16 MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat, most likely because you are not the author of them
17 POLL_VOTE_REQUIRED Cast a vote in the poll before calling this method
18 PREMIUM_ACCOUNT_REQUIRED This action requires a premium account
19 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)
20 SENSITIVE_CHANGE_FORBIDDEN Your sensitive content settings can't be changed at this time
21 TAKEOUT_REQUIRED The method must be invoked inside a takeout session
25 USER_IS_BLOCKED The user is blocked
26 USER_NOT_MUTUAL_CONTACT The provided user is not a mutual contact
27 USER_PRIVACY_RESTRICTED The user's privacy settings is preventing you to perform this action
28 USER_RESTRICTED You are limited/restricted. You can't perform this action
PREMIUM_ACCOUNT_REQUIRED This action requires a premium account

8
docs/requirements.txt Normal file
View file

@ -0,0 +1,8 @@
pyston_lite-autoload
sphinx
sphinx_rtd_theme==1.0.0
sphinx-rtd-dark-mode
sphinx_copybutton
sphinx-autobuild
tgcrypto
sphinx-autobuild

View 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>

View 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>

View 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>

View file

@ -0,0 +1,3 @@
.pre{
color: #bfbfbf;
}

View 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()

View 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()

View file

@ -0,0 +1,8 @@
ChatAction
==========
.. autoclass:: pyrogram.enums.ChatAction()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
ChatEventAction
===============
.. autoclass:: pyrogram.enums.ChatEventAction()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
ChatMemberStatus
================
.. autoclass:: pyrogram.enums.ChatMemberStatus()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
ChatMembersFilter
=================
.. autoclass:: pyrogram.enums.ChatMembersFilter()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
ChatType
========
.. autoclass:: pyrogram.enums.ChatType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
MessageEntityType
=================
.. autoclass:: pyrogram.enums.MessageEntityType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
MessageMediaType
================
.. autoclass:: pyrogram.enums.MessageMediaType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
MessageServiceType
==================
.. autoclass:: pyrogram.enums.MessageServiceType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
MessagesFilter
==============
.. autoclass:: pyrogram.enums.MessagesFilter()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
NextCodeType
============
.. autoclass:: pyrogram.enums.NextCodeType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
ParseMode
=========
.. autoclass:: pyrogram.enums.ParseMode()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
PollType
========
.. autoclass:: pyrogram.enums.PollType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
SentCodeType
============
.. autoclass:: pyrogram.enums.SentCodeType()
:members:
.. raw:: html
:file: ./cleanup.html

View file

@ -0,0 +1,8 @@
UserStatus
==========
.. autoclass:: pyrogram.enums.UserStatus()
:members:
.. raw:: html
:file: ./cleanup.html

View 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>

View 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

View file

@ -0,0 +1,7 @@
400 - BadRequest
----------------
.. csv-table::
:file: ../../../../compiler/errors/source/400_BAD_REQUEST.tsv
:delim: tab
:header-rows: 1

View file

@ -0,0 +1,7 @@
420 - Flood
-----------
.. csv-table::
:file: ../../../../compiler/errors/source/420_FLOOD.tsv
:delim: tab
:header-rows: 1

View file

@ -0,0 +1,7 @@
403 - Forbidden
---------------
.. csv-table::
:file: ../../../../compiler/errors/source/403_FORBIDDEN.tsv
:delim: tab
:header-rows: 1

View 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

View file

@ -0,0 +1,7 @@
500 - InternalServerError
-------------------------
.. csv-table::
:file: ../../../../compiler/errors/source/500_INTERNAL_SERVER_ERROR.tsv
:delim: tab
:header-rows: 1

View file

@ -0,0 +1,7 @@
406 - NotAcceptable
-------------------
.. csv-table::
:file: ../../../../compiler/errors/source/406_NOT_ACCEPTABLE.tsv
:delim: tab
:header-rows: 1

View file

@ -0,0 +1,7 @@
303 - SeeOther
--------------
.. csv-table::
:file: ../../../../compiler/errors/source/303_SEE_OTHER.tsv
:delim: tab
:header-rows: 1

View file

@ -0,0 +1,7 @@
401 - Unauthorized
------------------
.. csv-table::
:file: ../../../../compiler/errors/source/401_UNAUTHORIZED.tsv
:delim: tab
:header-rows: 1

View 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:

View 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
View 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",
]

View 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)

View file

@ -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.

View 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>`.

View 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
View 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

View file

@ -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.

View 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.

View file

@ -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.

View file

@ -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")

View file

@ -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.

View 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

View 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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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

View 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.

View file

@ -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
View 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

View 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

View 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

View 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()

View 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
...

View 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())

View 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()

View 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()

View 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())

View 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())

View 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())

View 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())

View 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

View 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()

View 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()

View 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())

View 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()

View 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())

View 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)

View 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
View 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>

View 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

View 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",
)

View 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
...

View 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>

View 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

View 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

View 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()

View 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()

View 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.

View 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)

View 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

View file

@ -0,0 +1,111 @@
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:
.. code-block:: python
from pyrogram import Client
# uri (``str``):
# mongodb database uri
# db_name (``str``, *optional*):
# custom database name, default = pyrofork-session
# remove_peers (``bool``, *optional*):
# remove peers collection on logout, default = False
async with Client("my_account", mongodb=dict(uri="mongodb://...", db_name="pyrofork-session", 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.

View 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
...

View 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).

View 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 ``&lt;``, ``>`` with ``&gt;`` and ``&`` with ``&amp;``). 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
&lt;my text&gt;
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--``

View file

@ -0,0 +1,114 @@
Using Filters
=============
So far we've seen :doc:`how to register a callback function <../start/updates>` that executes every time an update comes
from the server, but there's much more than that to come.
Here we'll discuss about :obj:`~pyrogram.filters`. Filters enable a fine-grain control over what kind of
updates are allowed or not to be passed in your callback functions, based on their inner details.
.. contents:: Contents
:backlinks: none
:depth: 1
:local:
-----
Single Filters
--------------
Let's start right away with a simple example:
- This example will show you how to **only** handle messages containing a :class:`~pyrogram.types.Sticker` object and
ignore any other message. Filters are passed as the first argument of the decorator:
.. code-block:: python
from pyrogram import filters
@app.on_message(filters.sticker)
async def my_handler(client, message):
print(message)
- or, without decorators. Here filters are passed as the second argument of the handler constructor; the first is the
callback function itself:
.. code-block:: python
from pyrogram import filters
from pyrogram.handlers import MessageHandler
async def my_handler(client, message):
print(message)
app.add_handler(MessageHandler(my_handler, filters.sticker))
Combining Filters
-----------------
Filters can be used in a more advanced way by inverting and combining more filters together using bitwise
operators ``~``, ``&`` and ``|``:
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
Here are some examples:
- Message is a **text** message **or** a **photo**.
.. code-block:: python
@app.on_message(filters.text | filters.photo)
async def my_handler(client, message):
print(message)
- Message is a **sticker** **and** is coming from a **channel or** a **private** chat.
.. code-block:: python
@app.on_message(filters.sticker & (filters.channel | filters.private))
async def my_handler(client, message):
print(message)
Advanced Filters
----------------
Some filters, like :meth:`~pyrogram.filters.command` or :meth:`~pyrogram.filters.regex`
can also accept arguments:
- Message is either a */start* or */help* **command**.
.. code-block:: python
@app.on_message(filters.command(["start", "help"]))
async def my_handler(client, message):
print(message)
- Message is a **text** message or a media **caption** matching the given **regex** pattern.
.. code-block:: python
@app.on_message(filters.regex("pyrogram"))
async def my_handler(client, message):
print(message)
More handlers using different filters can also live together.
.. code-block:: python
@app.on_message(filters.command("start"))
async def start_command(client, message):
print("This is the /start command")
@app.on_message(filters.command("help"))
async def help_command(client, message):
print("This is the /help command")
@app.on_message(filters.chat("PyroForkChat"))
async def from_pyrogramchat(client, message):
print("New message in @PyroForkChat")

Some files were not shown because too many files have changed in this diff Show more