mirror of
https://github.com/Mayuri-Chan/pyrofork.git
synced 2025-12-29 12:04:51 +00:00
Compare commits
421 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bbff46417 | ||
|
|
2c32c152cb | ||
|
|
97db9130bb | ||
|
|
47a3b6179d | ||
|
|
2f2d515575 | ||
|
|
e9c40679d2 | ||
|
|
b43e857ed2 | ||
|
|
72b043b743 | ||
|
|
ac8e8fef4d | ||
|
|
0876ac31bd | ||
|
|
4f4988e808 | ||
|
|
94c474a646 | ||
|
|
66753e44f2 | ||
|
|
d35abe89c4 | ||
|
|
77f50c6a82 | ||
|
|
c15a59e998 | ||
|
|
945dcfca56 | ||
|
|
12cf466b23 | ||
|
|
8c6bad6aa4 | ||
|
|
dddb0d75e7 | ||
|
|
f0cc3afe5d | ||
|
|
7105b131dc | ||
|
|
4afd74d26e | ||
|
|
73027fecf7 | ||
|
|
7db5e1423f | ||
|
|
802c394f91 | ||
|
|
4570b3b5a9 | ||
|
|
fa9781d62c | ||
|
|
9a772a8c8a | ||
|
|
cb38d6a02b | ||
|
|
cf6141feb4 | ||
|
|
8acc457458 | ||
|
|
413556a3f2 | ||
|
|
4a109b3dc2 | ||
|
|
46e755f297 | ||
|
|
c8b22bb5e7 | ||
|
|
9b670a78b3 | ||
|
|
621c690e55 | ||
|
|
07bdefb017 | ||
|
|
9d795911b4 | ||
|
|
cb19b742ad | ||
|
|
1ba1a051c4 | ||
|
|
6151813555 | ||
|
|
cc4eb21b84 | ||
|
|
12d9297c02 | ||
|
|
52abec6e01 | ||
|
|
fd4eb09f7a | ||
|
|
dbcbadc400 | ||
|
|
b65279046e | ||
|
|
9ff40dc90b | ||
|
|
6f616ebed8 | ||
|
|
e33d0bde65 | ||
|
|
e5b5ef5072 | ||
|
|
a1e3f0f5db | ||
|
|
b6c615df7a | ||
|
|
a2f3a6a27b | ||
|
|
bd5603a6a7 | ||
|
|
1ed7add4dd | ||
|
|
068181682e | ||
|
|
c0dcac1fde | ||
|
|
ffec107a2c | ||
|
|
390786d92c | ||
|
|
a9c4ef4c2e | ||
|
|
78467e30a2 | ||
|
|
3d343a49ff | ||
|
|
83f3f52681 | ||
|
|
8880a92483 | ||
|
|
71c0a1176a | ||
|
|
ddf90f26cf | ||
|
|
907f03197a | ||
|
|
eb2b854ea6 | ||
|
|
7d10a6fb9c | ||
|
|
315f61d1ed | ||
|
|
f6599d8ef4 | ||
|
|
47b054c996 | ||
|
|
2a84c33607 | ||
|
|
6c07a1b165 | ||
|
|
2c3fb1caa6 | ||
|
|
ce74587e4f | ||
|
|
910e7fe730 | ||
|
|
7f5547a6a8 | ||
|
|
04c25b760f | ||
|
|
1b6d86ea77 | ||
|
|
5e35c47b61 | ||
|
|
99e6005cf1 | ||
|
|
57feed8b45 | ||
|
|
d749f50140 | ||
|
|
2992b6cc2f | ||
|
|
ac7ad7d3bc | ||
|
|
40cd7badd5 | ||
|
|
c0c76342d5 | ||
|
|
37d0e5ae72 | ||
|
|
52c13cdd48 | ||
|
|
e2e4f13946 | ||
|
|
beb5b5138b | ||
|
|
95e97b11f6 | ||
|
|
548f404d67 | ||
|
|
4df4478a80 | ||
|
|
4a8e73fc97 | ||
|
|
3a632d4590 | ||
|
|
8655deb92c | ||
|
|
b6fdbb0a07 | ||
|
|
aac5425334 | ||
|
|
3e24f006e0 | ||
|
|
f5296145cd | ||
|
|
24d3ea0e48 | ||
|
|
70fc7d9eff | ||
|
|
8c47410bba | ||
|
|
c427601210 | ||
|
|
aa1757676c | ||
|
|
c4166957d3 | ||
|
|
389a135883 | ||
|
|
6b28d305c0 | ||
|
|
7ae98099db | ||
|
|
96917949a9 | ||
|
|
757b081eeb | ||
|
|
8074557922 | ||
|
|
7562d04596 | ||
|
|
149dd4a708 | ||
|
|
4926eda4c5 | ||
|
|
c4b587b493 | ||
|
|
1108c52f53 | ||
|
|
fc84041397 | ||
|
|
71c39b8e6f | ||
|
|
bec31032cc | ||
|
|
5c9470fd4f | ||
|
|
13681302a0 | ||
|
|
c31d41e3d3 | ||
|
|
8528eea303 | ||
|
|
39cd79794e | ||
|
|
ea8ff2806f | ||
|
|
e33a9d95df | ||
|
|
ee3e9002fc | ||
|
|
4e200e2a5d | ||
|
|
ecf469973e | ||
|
|
5e72850eee | ||
|
|
ad0aed4cf3 | ||
|
|
5c1c72f068 | ||
|
|
7662cc164f | ||
|
|
2923328bbb | ||
|
|
e9eaa48650 | ||
|
|
03c2f5ff8c | ||
|
|
3e504edcc1 | ||
|
|
8f9797f57c | ||
|
|
361acdbfd7 | ||
|
|
4a50a9183d | ||
|
|
0f65486aba | ||
|
|
fabe0464fa | ||
|
|
0b220def26 | ||
|
|
3e36412e68 | ||
|
|
3180267107 | ||
|
|
377fda434b | ||
|
|
ca5c406a00 | ||
|
|
276bc0affd | ||
|
|
60533eb92c | ||
|
|
885a832aa3 | ||
|
|
a653065774 | ||
|
|
5676006a10 | ||
|
|
71f1147b65 | ||
|
|
8db18a7734 | ||
|
|
d82a3fb1f7 | ||
|
|
2e0ec55dd3 | ||
|
|
f767fd3e3a | ||
|
|
b12b4a62f4 | ||
|
|
7cda52ac39 | ||
|
|
7404c46d7d | ||
|
|
14fb99cf77 | ||
|
|
9e101ef4d9 | ||
|
|
a04c91db31 | ||
|
|
8ceec293ba | ||
|
|
6c538f026d | ||
|
|
1ddc2d268b | ||
|
|
5c93020bbe | ||
|
|
1955de7a20 | ||
|
|
2bb299c163 | ||
|
|
8e7e5fb9ff | ||
|
|
e67a016828 | ||
|
|
aaf9c0cd3d | ||
|
|
5187bae266 | ||
|
|
ecc15f67a4 | ||
|
|
56e9173579 | ||
|
|
945ff8b642 | ||
|
|
21a3045890 | ||
|
|
481817649b | ||
|
|
bd46ff3977 | ||
|
|
b21db6f931 | ||
|
|
6dcb6bfa67 | ||
|
|
252882851e | ||
|
|
ae3bc516fb | ||
|
|
5b79294276 | ||
|
|
08af7a1b66 | ||
|
|
d3c945f6b6 | ||
|
|
f8103a2890 | ||
|
|
f6f003d25a | ||
|
|
bba87d6e52 | ||
|
|
c9bbeec525 | ||
|
|
dd9ae86d8b | ||
|
|
d7018d8ed1 | ||
|
|
efc0272186 | ||
|
|
03226965ab | ||
|
|
45b47af9b2 | ||
|
|
ab8f854385 | ||
|
|
6f5bd1392b | ||
|
|
1bcf2f7be6 | ||
|
|
efce392266 | ||
|
|
5dda91d3b0 | ||
|
|
0c23296be5 | ||
|
|
4e909508e5 | ||
|
|
4ced5fbd8b | ||
|
|
52f1b97c84 | ||
|
|
680918eed7 | ||
|
|
3426ad59a2 | ||
|
|
cf67f9534c | ||
|
|
b437bc1c46 | ||
|
|
307b700df3 | ||
|
|
91e7506a6a | ||
|
|
591cd3ac86 | ||
|
|
7726e22161 | ||
|
|
072cc0cead | ||
|
|
4bcc690083 | ||
|
|
db562461ad | ||
|
|
261490f63b | ||
|
|
e5ae90c335 | ||
|
|
f990b1e7f9 | ||
|
|
2130f089d6 | ||
|
|
5086c9ccc3 | ||
|
|
6e66a7d4b2 | ||
|
|
a6046806b8 | ||
|
|
6e6a689953 | ||
|
|
f30aa0077a | ||
|
|
0a6cc8b5a4 | ||
|
|
f23f450c62 | ||
|
|
d4649275e9 | ||
|
|
bb96ca8597 | ||
|
|
e4968df4c9 | ||
|
|
b152bd9c84 | ||
|
|
4e823b153e | ||
|
|
95eba2ce77 | ||
|
|
a6b69228e8 | ||
|
|
faef0b0699 | ||
|
|
266fc738b6 | ||
|
|
d594fe58cb | ||
|
|
923ad51dd7 | ||
|
|
c3df58b4c7 | ||
|
|
2d83118f0f | ||
|
|
3ee16dac4e | ||
|
|
45e2872fab | ||
|
|
74376f8da5 | ||
|
|
44d4c0ff55 | ||
|
|
65190eb195 | ||
|
|
a403d83f7e | ||
|
|
6543fa11b6 | ||
|
|
57155cbdfa | ||
|
|
caea59cc17 | ||
|
|
63db641f59 | ||
|
|
f7e1f214c6 | ||
|
|
c2cd506be9 | ||
|
|
01e200e8ce | ||
|
|
4e2d553f35 | ||
|
|
ee8f11e2a0 | ||
|
|
930da9b858 | ||
|
|
d70927e5a2 | ||
|
|
f07d6563e3 | ||
|
|
76deb77f1c | ||
|
|
02eed79861 | ||
|
|
2faae08064 | ||
|
|
e5327d2216 | ||
|
|
11836faab7 | ||
|
|
2a70654537 | ||
|
|
d062b6795f | ||
|
|
053232b15a | ||
|
|
b412622bc7 | ||
|
|
74699d8bdf | ||
|
|
489337d5d0 | ||
|
|
d9c6286044 | ||
|
|
755d23028b | ||
|
|
430cc9f534 | ||
|
|
2ebfb80761 | ||
|
|
37e39bd6ce | ||
|
|
7a063e4a72 | ||
|
|
8e95ffcd6c | ||
|
|
8d8768cce4 | ||
|
|
efe3d90718 | ||
|
|
d3ffd68690 | ||
|
|
1d0ad21328 | ||
|
|
375d165a9c | ||
|
|
a598ab6144 | ||
|
|
9697a7f3cd | ||
|
|
ecfa97f115 | ||
|
|
3061115d57 | ||
|
|
2317643727 | ||
|
|
56efb88047 | ||
|
|
8854710399 | ||
|
|
889c32ca2b | ||
|
|
a138170e1e | ||
|
|
945290692e | ||
|
|
cbd632c600 | ||
|
|
b6d9e2c782 | ||
|
|
4112298666 | ||
|
|
90dc694588 | ||
|
|
4ac0fcc35f | ||
|
|
22bc0140e9 | ||
|
|
d0a70e2929 | ||
|
|
ce382c2f11 | ||
|
|
b4d2d30fca | ||
|
|
ccfac93e84 | ||
|
|
74f5a3fe29 | ||
|
|
daf6f91600 | ||
|
|
e0e5bdb2cd | ||
|
|
f030f00e9d | ||
|
|
1abd0673b7 | ||
|
|
69179879fc | ||
|
|
569c515732 | ||
|
|
ee8c19d3f4 | ||
|
|
b081928452 | ||
|
|
e97f441a41 | ||
|
|
780ea9fd64 | ||
|
|
56621a6f4d | ||
|
|
c880277a4e | ||
|
|
280248f243 | ||
|
|
2e4b2d3348 | ||
|
|
5a9c11934a | ||
|
|
9669d62562 | ||
|
|
7c81723649 | ||
|
|
9dbd784e7c | ||
|
|
d906970d99 | ||
|
|
f1e2b493b6 | ||
|
|
bed95d6ec2 | ||
|
|
116a353477 | ||
|
|
87e0314f4a | ||
|
|
73da5c1aef | ||
|
|
9510ff9fdb | ||
|
|
9785e96ac4 | ||
|
|
4c99132f3b | ||
|
|
2abb3543ce | ||
|
|
3120fb2340 | ||
|
|
30f5ae2994 | ||
|
|
defda31c28 | ||
|
|
4bbbd5c460 | ||
|
|
6ba25aa4f5 | ||
|
|
18e81882c3 | ||
|
|
c0ee103efe | ||
|
|
a55b56d611 | ||
|
|
5316a16a83 | ||
|
|
869965acf3 | ||
|
|
561d3d3def | ||
|
|
d46e8f1da4 | ||
|
|
b0f449a0d6 | ||
|
|
e999da461d | ||
|
|
61398bc5a4 | ||
|
|
48e8d0c4a1 | ||
|
|
9d0c11caf5 | ||
|
|
fb2d49efbd | ||
|
|
8584ea3599 | ||
|
|
c394a3ea3a | ||
|
|
f37c5c9f2f | ||
|
|
58f0031ead | ||
|
|
4795bdbd5b | ||
|
|
ff69bbaf3b | ||
|
|
30dad015ae | ||
|
|
918a55de3b | ||
|
|
de5d2e747b | ||
|
|
5130e0a2e5 | ||
|
|
32175f33c0 | ||
|
|
50a3919ed7 | ||
|
|
344f835441 | ||
|
|
43809a91b1 | ||
|
|
48cf8bcb23 | ||
|
|
83543da3e6 | ||
|
|
c8d2c6a152 | ||
|
|
0a844bd5ed | ||
|
|
86831843d9 | ||
|
|
08f9bd81f5 | ||
|
|
57175dedba | ||
|
|
47ede16039 | ||
|
|
a95517fa19 | ||
|
|
6bad69f04f | ||
|
|
b6a8ab87c7 | ||
|
|
6f8dde7ad0 | ||
|
|
240d3bfde5 | ||
|
|
b5a00aa539 | ||
|
|
d2dd55864c | ||
|
|
2e263190a2 | ||
|
|
4ae45da1ec | ||
|
|
12239964ec | ||
|
|
2891c15fa5 | ||
|
|
2284a2c852 | ||
|
|
8902f8be9e | ||
|
|
ced07dd421 | ||
|
|
adf5ad50d1 | ||
|
|
2fe3eeb96b | ||
|
|
3a41a51359 | ||
|
|
bb4ea00d4e | ||
|
|
3232a3f139 | ||
|
|
0387a09079 | ||
|
|
4d6fb409b8 | ||
|
|
d501b66f93 | ||
|
|
8fa49a9c43 | ||
|
|
ca6870502e | ||
|
|
8c51a192af | ||
|
|
1e44386a7c | ||
|
|
f1bea2c32f | ||
|
|
c4ec16b742 | ||
|
|
d863655769 | ||
|
|
7a9ffa2506 | ||
|
|
b8b014129e | ||
|
|
bb29cc86bc | ||
|
|
955b261101 | ||
|
|
7c0481d2f0 | ||
|
|
30272728be | ||
|
|
e823160c61 | ||
|
|
d4b904675a | ||
|
|
caf61d8dab | ||
|
|
d162ee1542 | ||
|
|
ed6dad7426 | ||
|
|
ca6bf75910 | ||
|
|
b4c6f66244 | ||
|
|
75d6e79917 | ||
|
|
fa7b7f3c58 | ||
|
|
454c2614e2 | ||
|
|
ad4dc01c8d |
389 changed files with 18030 additions and 2261 deletions
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
|
|
@ -1,3 +1,2 @@
|
||||||
github: Mayuri-Chan
|
github: Mayuri-Chan
|
||||||
ko_fi: wulan17
|
custom: ["https://t.me/Mayuri17_bot?start=donate"]
|
||||||
custom: ["https://saweria.co/wulan17", "https://paypal.me/wulan17", "https://trakteer.id/wulan17"]
|
|
||||||
|
|
|
||||||
21
.github/workflows/build-docs.yml
vendored
21
.github/workflows/build-docs.yml
vendored
|
|
@ -14,8 +14,25 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: bash build-docs.sh configure
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
run: bash build-docs.sh cleanup
|
||||||
|
|
||||||
|
- name: Create virtual environment
|
||||||
|
run: bash build-docs.sh virtualenv
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: bash build-docs.sh
|
run: bash build-docs.sh build
|
||||||
|
|
||||||
|
- name: Clone gh-pages repository
|
||||||
|
run: bash build-docs.sh clone
|
||||||
env:
|
env:
|
||||||
DOCS_KEY: ${{ secrets.DOCS_KEY }}
|
DOCS_KEY: ${{ secrets.DOCS_KEY }}
|
||||||
|
|
||||||
|
- name: Push changes
|
||||||
|
run: bash build-docs.sh push
|
||||||
|
|
|
||||||
13
.github/workflows/python-publish.yml
vendored
13
.github/workflows/python-publish.yml
vendored
|
|
@ -20,11 +20,14 @@ jobs:
|
||||||
deploy:
|
deploy:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
environment: release
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
@ -34,8 +37,4 @@ jobs:
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: hatch build
|
run: hatch build
|
||||||
- name: Publish package
|
- name: Publish package
|
||||||
env:
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
HATCH_INDEX_USER: __token__
|
|
||||||
HATCH_INDEX_AUTH: ${{ secrets.PYPI_API_TOKEN }}
|
|
||||||
run: |
|
|
||||||
hatch publish
|
|
||||||
|
|
|
||||||
8
.github/workflows/python.yml
vendored
8
.github/workflows/python.yml
vendored
|
|
@ -9,13 +9,13 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
|
@ -31,4 +31,4 @@ jobs:
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
tox
|
tox
|
||||||
|
|
|
||||||
651
.pylintrc
Normal file
651
.pylintrc
Normal file
|
|
@ -0,0 +1,651 @@
|
||||||
|
[MAIN]
|
||||||
|
|
||||||
|
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||||
|
# 3 compatible code, which means that the block might have code that exists
|
||||||
|
# only in one or another interpreter, leading to false positives when analysed.
|
||||||
|
analyse-fallback-blocks=no
|
||||||
|
|
||||||
|
# Clear in-memory caches upon conclusion of linting. Useful if running pylint
|
||||||
|
# in a server-like mode.
|
||||||
|
clear-cache-post-run=no
|
||||||
|
|
||||||
|
# Load and enable all available extensions. Use --list-extensions to see a list
|
||||||
|
# all available extensions.
|
||||||
|
#enable-all-extensions=
|
||||||
|
|
||||||
|
# In error mode, messages with a category besides ERROR or FATAL are
|
||||||
|
# suppressed, and no reports are done by default. Error mode is compatible with
|
||||||
|
# disabling specific errors.
|
||||||
|
#errors-only=
|
||||||
|
|
||||||
|
# Always return a 0 (non-error) status code, even if lint errors are found.
|
||||||
|
# This is primarily useful in continuous integration scripts.
|
||||||
|
#exit-zero=
|
||||||
|
|
||||||
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
|
# run arbitrary code.
|
||||||
|
extension-pkg-allow-list=
|
||||||
|
|
||||||
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
|
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
||||||
|
# for backward compatibility.)
|
||||||
|
extension-pkg-whitelist=
|
||||||
|
|
||||||
|
# Return non-zero exit code if any of these messages/categories are detected,
|
||||||
|
# even if score is above --fail-under value. Syntax same as enable. Messages
|
||||||
|
# specified are enabled, while categories only check already-enabled messages.
|
||||||
|
fail-on=
|
||||||
|
|
||||||
|
# Specify a score threshold under which the program will exit with error.
|
||||||
|
fail-under=10
|
||||||
|
|
||||||
|
# Interpret the stdin as a python script, whose filename needs to be passed as
|
||||||
|
# the module_or_package argument.
|
||||||
|
#from-stdin=
|
||||||
|
|
||||||
|
# Files or directories to be skipped. They should be base names, not paths.
|
||||||
|
ignore=CVS
|
||||||
|
|
||||||
|
# Add files or directories matching the regular expressions patterns to the
|
||||||
|
# ignore-list. The regex matches against paths and can be in Posix or Windows
|
||||||
|
# format. Because '\\' represents the directory delimiter on Windows systems,
|
||||||
|
# it can't be used as an escape character.
|
||||||
|
ignore-paths=
|
||||||
|
|
||||||
|
# Files or directories matching the regular expression patterns are skipped.
|
||||||
|
# The regex matches against base names, not paths. The default value ignores
|
||||||
|
# Emacs file locks
|
||||||
|
ignore-patterns=^\.#
|
||||||
|
|
||||||
|
# List of module names for which member attributes should not be checked and
|
||||||
|
# will not be imported (useful for modules/projects where namespaces are
|
||||||
|
# manipulated during runtime and thus existing member attributes cannot be
|
||||||
|
# deduced by static analysis). It supports qualified module names, as well as
|
||||||
|
# Unix pattern matching.
|
||||||
|
ignored-modules=
|
||||||
|
|
||||||
|
# Python code to execute, usually for sys.path manipulation such as
|
||||||
|
# pygtk.require().
|
||||||
|
#init-hook=
|
||||||
|
|
||||||
|
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
||||||
|
# number of processors available to use, and will cap the count on Windows to
|
||||||
|
# avoid hangs.
|
||||||
|
jobs=1
|
||||||
|
|
||||||
|
# Control the amount of potential inferred values when inferring a single
|
||||||
|
# object. This can help the performance when dealing with large functions or
|
||||||
|
# complex, nested conditions.
|
||||||
|
limit-inference-results=100
|
||||||
|
|
||||||
|
# List of plugins (as comma separated values of python module names) to load,
|
||||||
|
# usually to register additional checkers.
|
||||||
|
load-plugins=
|
||||||
|
|
||||||
|
# Pickle collected data for later comparisons.
|
||||||
|
persistent=yes
|
||||||
|
|
||||||
|
# Resolve imports to .pyi stubs if available. May reduce no-member messages and
|
||||||
|
# increase not-an-iterable messages.
|
||||||
|
prefer-stubs=no
|
||||||
|
|
||||||
|
# Minimum Python version to use for version dependent checks. Will default to
|
||||||
|
# the version used to run pylint.
|
||||||
|
py-version=3.13
|
||||||
|
|
||||||
|
# Discover python modules and packages in the file system subtree.
|
||||||
|
recursive=no
|
||||||
|
|
||||||
|
# Add paths to the list of the source roots. Supports globbing patterns. The
|
||||||
|
# source root is an absolute path or a path relative to the current working
|
||||||
|
# directory used to determine a package namespace for modules located under the
|
||||||
|
# source root.
|
||||||
|
source-roots=
|
||||||
|
|
||||||
|
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||||
|
# user-friendly hints instead of false-positive error messages.
|
||||||
|
suggestion-mode=yes
|
||||||
|
|
||||||
|
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||||
|
# active Python interpreter and may run arbitrary code.
|
||||||
|
unsafe-load-any-extension=no
|
||||||
|
|
||||||
|
# In verbose mode, extra non-checker-related info will be displayed.
|
||||||
|
#verbose=
|
||||||
|
|
||||||
|
|
||||||
|
[BASIC]
|
||||||
|
|
||||||
|
# Naming style matching correct argument names.
|
||||||
|
argument-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct argument names. Overrides argument-
|
||||||
|
# naming-style. If left empty, argument names will be checked with the set
|
||||||
|
# naming style.
|
||||||
|
#argument-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct attribute names.
|
||||||
|
attr-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||||
|
# style. If left empty, attribute names will be checked with the set naming
|
||||||
|
# style.
|
||||||
|
#attr-rgx=
|
||||||
|
|
||||||
|
# Bad variable names which should always be refused, separated by a comma.
|
||||||
|
bad-names=foo,
|
||||||
|
bar,
|
||||||
|
baz,
|
||||||
|
toto,
|
||||||
|
tutu,
|
||||||
|
tata
|
||||||
|
|
||||||
|
# Bad variable names regexes, separated by a comma. If names match any regex,
|
||||||
|
# they will always be refused
|
||||||
|
bad-names-rgxs=
|
||||||
|
|
||||||
|
# Naming style matching correct class attribute names.
|
||||||
|
class-attribute-naming-style=any
|
||||||
|
|
||||||
|
# Regular expression matching correct class attribute names. Overrides class-
|
||||||
|
# attribute-naming-style. If left empty, class attribute names will be checked
|
||||||
|
# with the set naming style.
|
||||||
|
#class-attribute-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct class constant names.
|
||||||
|
class-const-naming-style=UPPER_CASE
|
||||||
|
|
||||||
|
# Regular expression matching correct class constant names. Overrides class-
|
||||||
|
# const-naming-style. If left empty, class constant names will be checked with
|
||||||
|
# the set naming style.
|
||||||
|
#class-const-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct class names.
|
||||||
|
class-naming-style=PascalCase
|
||||||
|
|
||||||
|
# Regular expression matching correct class names. Overrides class-naming-
|
||||||
|
# style. If left empty, class names will be checked with the set naming style.
|
||||||
|
#class-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct constant names.
|
||||||
|
const-naming-style=UPPER_CASE
|
||||||
|
|
||||||
|
# Regular expression matching correct constant names. Overrides const-naming-
|
||||||
|
# style. If left empty, constant names will be checked with the set naming
|
||||||
|
# style.
|
||||||
|
#const-rgx=
|
||||||
|
|
||||||
|
# Minimum line length for functions/classes that require docstrings, shorter
|
||||||
|
# ones are exempt.
|
||||||
|
docstring-min-length=-1
|
||||||
|
|
||||||
|
# Naming style matching correct function names.
|
||||||
|
function-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct function names. Overrides function-
|
||||||
|
# naming-style. If left empty, function names will be checked with the set
|
||||||
|
# naming style.
|
||||||
|
#function-rgx=
|
||||||
|
|
||||||
|
# Good variable names which should always be accepted, separated by a comma.
|
||||||
|
good-names=i,
|
||||||
|
j,
|
||||||
|
k,
|
||||||
|
ex,
|
||||||
|
Run,
|
||||||
|
_
|
||||||
|
|
||||||
|
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||||
|
# they will always be accepted
|
||||||
|
good-names-rgxs=
|
||||||
|
|
||||||
|
# Include a hint for the correct naming format with invalid-name.
|
||||||
|
include-naming-hint=no
|
||||||
|
|
||||||
|
# Naming style matching correct inline iteration names.
|
||||||
|
inlinevar-naming-style=any
|
||||||
|
|
||||||
|
# Regular expression matching correct inline iteration names. Overrides
|
||||||
|
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
||||||
|
# with the set naming style.
|
||||||
|
#inlinevar-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct method names.
|
||||||
|
method-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct method names. Overrides method-naming-
|
||||||
|
# style. If left empty, method names will be checked with the set naming style.
|
||||||
|
#method-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct module names.
|
||||||
|
module-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct module names. Overrides module-naming-
|
||||||
|
# style. If left empty, module names will be checked with the set naming style.
|
||||||
|
#module-rgx=
|
||||||
|
|
||||||
|
# Colon-delimited sets of names that determine each other's naming style when
|
||||||
|
# the name regexes allow several styles.
|
||||||
|
name-group=
|
||||||
|
|
||||||
|
# Regular expression which should only match function or class names that do
|
||||||
|
# not require a docstring.
|
||||||
|
no-docstring-rgx=^_
|
||||||
|
|
||||||
|
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||||
|
# to this list to register other decorators that produce valid properties.
|
||||||
|
# These decorators are taken in consideration only for invalid-name.
|
||||||
|
property-classes=abc.abstractproperty
|
||||||
|
|
||||||
|
# Regular expression matching correct type alias names. If left empty, type
|
||||||
|
# alias names will be checked with the set naming style.
|
||||||
|
#typealias-rgx=
|
||||||
|
|
||||||
|
# Regular expression matching correct type variable names. If left empty, type
|
||||||
|
# variable names will be checked with the set naming style.
|
||||||
|
#typevar-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct variable names.
|
||||||
|
variable-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct variable names. Overrides variable-
|
||||||
|
# naming-style. If left empty, variable names will be checked with the set
|
||||||
|
# naming style.
|
||||||
|
#variable-rgx=
|
||||||
|
|
||||||
|
|
||||||
|
[CLASSES]
|
||||||
|
|
||||||
|
# Warn about protected attribute access inside special methods
|
||||||
|
check-protected-access-in-special-methods=no
|
||||||
|
|
||||||
|
# List of method names used to declare (i.e. assign) instance attributes.
|
||||||
|
defining-attr-methods=__init__,
|
||||||
|
__new__,
|
||||||
|
setUp,
|
||||||
|
asyncSetUp,
|
||||||
|
__post_init__
|
||||||
|
|
||||||
|
# List of member names, which should be excluded from the protected access
|
||||||
|
# warning.
|
||||||
|
exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a class method.
|
||||||
|
valid-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a metaclass class method.
|
||||||
|
valid-metaclass-classmethod-first-arg=mcs
|
||||||
|
|
||||||
|
|
||||||
|
[DESIGN]
|
||||||
|
|
||||||
|
# List of regular expressions of class ancestor names to ignore when counting
|
||||||
|
# public methods (see R0903)
|
||||||
|
exclude-too-few-public-methods=
|
||||||
|
|
||||||
|
# List of qualified class names to ignore when counting class parents (see
|
||||||
|
# R0901)
|
||||||
|
ignored-parents=
|
||||||
|
|
||||||
|
# Maximum number of arguments for function / method.
|
||||||
|
max-args=5
|
||||||
|
|
||||||
|
# Maximum number of attributes for a class (see R0902).
|
||||||
|
max-attributes=7
|
||||||
|
|
||||||
|
# Maximum number of boolean expressions in an if statement (see R0916).
|
||||||
|
max-bool-expr=5
|
||||||
|
|
||||||
|
# Maximum number of branch for function / method body.
|
||||||
|
max-branches=12
|
||||||
|
|
||||||
|
# Maximum number of locals for function / method body.
|
||||||
|
max-locals=15
|
||||||
|
|
||||||
|
# Maximum number of parents for a class (see R0901).
|
||||||
|
max-parents=7
|
||||||
|
|
||||||
|
# Maximum number of positional arguments for function / method.
|
||||||
|
max-positional-arguments=5
|
||||||
|
|
||||||
|
# Maximum number of public methods for a class (see R0904).
|
||||||
|
max-public-methods=20
|
||||||
|
|
||||||
|
# Maximum number of return / yield for function / method body.
|
||||||
|
max-returns=6
|
||||||
|
|
||||||
|
# Maximum number of statements in function / method body.
|
||||||
|
max-statements=50
|
||||||
|
|
||||||
|
# Minimum number of public methods for a class (see R0903).
|
||||||
|
min-public-methods=2
|
||||||
|
|
||||||
|
|
||||||
|
[EXCEPTIONS]
|
||||||
|
|
||||||
|
# Exceptions that will emit a warning when caught.
|
||||||
|
overgeneral-exceptions=builtins.BaseException,builtins.Exception
|
||||||
|
|
||||||
|
|
||||||
|
[FORMAT]
|
||||||
|
|
||||||
|
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||||
|
expected-line-ending-format=
|
||||||
|
|
||||||
|
# Regexp for a line that is allowed to be longer than the limit.
|
||||||
|
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||||
|
|
||||||
|
# Number of spaces of indent required inside a hanging or continued line.
|
||||||
|
indent-after-paren=4
|
||||||
|
|
||||||
|
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||||
|
# tab).
|
||||||
|
indent-string=' '
|
||||||
|
|
||||||
|
# Maximum number of characters on a single line.
|
||||||
|
max-line-length=100
|
||||||
|
|
||||||
|
# Maximum number of lines in a module.
|
||||||
|
max-module-lines=1000
|
||||||
|
|
||||||
|
# Allow the body of a class to be on the same line as the declaration if body
|
||||||
|
# contains single statement.
|
||||||
|
single-line-class-stmt=no
|
||||||
|
|
||||||
|
# Allow the body of an if to be on the same line as the test if there is no
|
||||||
|
# else.
|
||||||
|
single-line-if-stmt=no
|
||||||
|
|
||||||
|
|
||||||
|
[IMPORTS]
|
||||||
|
|
||||||
|
# List of modules that can be imported at any level, not just the top level
|
||||||
|
# one.
|
||||||
|
allow-any-import-level=
|
||||||
|
|
||||||
|
# Allow explicit reexports by alias from a package __init__.
|
||||||
|
allow-reexport-from-package=no
|
||||||
|
|
||||||
|
# Allow wildcard imports from modules that define __all__.
|
||||||
|
allow-wildcard-with-all=no
|
||||||
|
|
||||||
|
# Deprecated modules which should not be used, separated by a comma.
|
||||||
|
deprecated-modules=
|
||||||
|
|
||||||
|
# Output a graph (.gv or any supported image format) of external dependencies
|
||||||
|
# to the given file (report RP0402 must not be disabled).
|
||||||
|
ext-import-graph=
|
||||||
|
|
||||||
|
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
||||||
|
# external) dependencies to the given file (report RP0402 must not be
|
||||||
|
# disabled).
|
||||||
|
import-graph=
|
||||||
|
|
||||||
|
# Output a graph (.gv or any supported image format) of internal dependencies
|
||||||
|
# to the given file (report RP0402 must not be disabled).
|
||||||
|
int-import-graph=
|
||||||
|
|
||||||
|
# Force import order to recognize a module as part of the standard
|
||||||
|
# compatibility libraries.
|
||||||
|
known-standard-library=
|
||||||
|
|
||||||
|
# Force import order to recognize a module as part of a third party library.
|
||||||
|
known-third-party=enchant
|
||||||
|
|
||||||
|
# Couples of modules and preferred modules, separated by a comma.
|
||||||
|
preferred-modules=
|
||||||
|
|
||||||
|
|
||||||
|
[LOGGING]
|
||||||
|
|
||||||
|
# The type of string formatting that logging methods do. `old` means using %
|
||||||
|
# formatting, `new` is for `{}` formatting.
|
||||||
|
logging-format-style=old
|
||||||
|
|
||||||
|
# Logging modules to check that the string format arguments are in logging
|
||||||
|
# function parameter format.
|
||||||
|
logging-modules=logging
|
||||||
|
|
||||||
|
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
|
||||||
|
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||||
|
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
|
||||||
|
# UNDEFINED.
|
||||||
|
confidence=HIGH,
|
||||||
|
CONTROL_FLOW,
|
||||||
|
INFERENCE,
|
||||||
|
INFERENCE_FAILURE,
|
||||||
|
UNDEFINED
|
||||||
|
|
||||||
|
# Disable the message, report, category or checker with the given id(s). You
|
||||||
|
# can either give multiple identifiers separated by comma (,) or put this
|
||||||
|
# option multiple times (only on the command line, not in the configuration
|
||||||
|
# file where it should appear only once). You can also use "--disable=all" to
|
||||||
|
# disable everything first and then re-enable specific checks. For example, if
|
||||||
|
# you want to run only the similarities checker, you can use "--disable=all
|
||||||
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
|
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||||
|
# --disable=W".
|
||||||
|
disable=raw-checker-failed,
|
||||||
|
bad-inline-option,
|
||||||
|
locally-disabled,
|
||||||
|
file-ignored,
|
||||||
|
suppressed-message,
|
||||||
|
useless-suppression,
|
||||||
|
deprecated-pragma,
|
||||||
|
use-implicit-booleaness-not-comparison-to-string,
|
||||||
|
use-implicit-booleaness-not-comparison-to-zero,
|
||||||
|
use-symbolic-message-instead,
|
||||||
|
missing-module-docstring,
|
||||||
|
missing-class-docstring,
|
||||||
|
missing-function-docstring,
|
||||||
|
redefined-builtin
|
||||||
|
|
||||||
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
|
# either give multiple identifier separated by comma (,) or put this option
|
||||||
|
# multiple time (only on the command line, not in the configuration file where
|
||||||
|
# it should appear only once). See also the "--disable" option for examples.
|
||||||
|
enable=
|
||||||
|
|
||||||
|
|
||||||
|
[METHOD_ARGS]
|
||||||
|
|
||||||
|
# List of qualified names (i.e., library.method) which require a timeout
|
||||||
|
# parameter e.g. 'requests.api.get,requests.api.post'
|
||||||
|
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
|
||||||
|
|
||||||
|
|
||||||
|
[MISCELLANEOUS]
|
||||||
|
|
||||||
|
# List of note tags to take in consideration, separated by a comma.
|
||||||
|
notes=FIXME,
|
||||||
|
XXX,
|
||||||
|
TODO
|
||||||
|
|
||||||
|
# Regular expression of note tags to take in consideration.
|
||||||
|
notes-rgx=
|
||||||
|
|
||||||
|
|
||||||
|
[REFACTORING]
|
||||||
|
|
||||||
|
# Maximum number of nested blocks for function / method body
|
||||||
|
max-nested-blocks=5
|
||||||
|
|
||||||
|
# Complete name of functions that never returns. When checking for
|
||||||
|
# inconsistent-return-statements if a never returning function is called then
|
||||||
|
# it will be considered as an explicit return statement and no message will be
|
||||||
|
# printed.
|
||||||
|
never-returning-functions=sys.exit,argparse.parse_error
|
||||||
|
|
||||||
|
# Let 'consider-using-join' be raised when the separator to join on would be
|
||||||
|
# non-empty (resulting in expected fixes of the type: ``"- " + " -
|
||||||
|
# ".join(items)``)
|
||||||
|
suggest-join-with-non-empty-separator=yes
|
||||||
|
|
||||||
|
|
||||||
|
[REPORTS]
|
||||||
|
|
||||||
|
# Python expression which should return a score less than or equal to 10. You
|
||||||
|
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
|
||||||
|
# 'convention', and 'info' which contain the number of messages in each
|
||||||
|
# category, as well as 'statement' which is the total number of statements
|
||||||
|
# analyzed. This score is used by the global evaluation report (RP0004).
|
||||||
|
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||||
|
|
||||||
|
# Template used to display messages. This is a python new-style format string
|
||||||
|
# used to format the message information. See doc for all details.
|
||||||
|
msg-template=
|
||||||
|
|
||||||
|
# Set the output format. Available formats are: 'text', 'parseable',
|
||||||
|
# 'colorized', 'json2' (improved json format), 'json' (old json format), msvs
|
||||||
|
# (visual studio) and 'github' (GitHub actions). You can also give a reporter
|
||||||
|
# class, e.g. mypackage.mymodule.MyReporterClass.
|
||||||
|
#output-format=
|
||||||
|
|
||||||
|
# Tells whether to display a full report or only the messages.
|
||||||
|
reports=no
|
||||||
|
|
||||||
|
# Activate the evaluation score.
|
||||||
|
score=yes
|
||||||
|
|
||||||
|
|
||||||
|
[SIMILARITIES]
|
||||||
|
|
||||||
|
# Comments are removed from the similarity computation
|
||||||
|
ignore-comments=yes
|
||||||
|
|
||||||
|
# Docstrings are removed from the similarity computation
|
||||||
|
ignore-docstrings=yes
|
||||||
|
|
||||||
|
# Imports are removed from the similarity computation
|
||||||
|
ignore-imports=yes
|
||||||
|
|
||||||
|
# Signatures are removed from the similarity computation
|
||||||
|
ignore-signatures=yes
|
||||||
|
|
||||||
|
# Minimum lines number of a similarity.
|
||||||
|
min-similarity-lines=4
|
||||||
|
|
||||||
|
|
||||||
|
[SPELLING]
|
||||||
|
|
||||||
|
# Limits count of emitted suggestions for spelling mistakes.
|
||||||
|
max-spelling-suggestions=4
|
||||||
|
|
||||||
|
# Spelling dictionary name. No available dictionaries : You need to install
|
||||||
|
# both the python package and the system dependency for enchant to work.
|
||||||
|
spelling-dict=
|
||||||
|
|
||||||
|
# List of comma separated words that should be considered directives if they
|
||||||
|
# appear at the beginning of a comment and should not be checked.
|
||||||
|
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||||
|
|
||||||
|
# List of comma separated words that should not be checked.
|
||||||
|
spelling-ignore-words=
|
||||||
|
|
||||||
|
# A path to a file that contains the private dictionary; one word per line.
|
||||||
|
spelling-private-dict-file=
|
||||||
|
|
||||||
|
# Tells whether to store unknown words to the private dictionary (see the
|
||||||
|
# --spelling-private-dict-file option) instead of raising a message.
|
||||||
|
spelling-store-unknown-words=no
|
||||||
|
|
||||||
|
|
||||||
|
[STRING]
|
||||||
|
|
||||||
|
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||||
|
# character used as a quote delimiter is used inconsistently within a module.
|
||||||
|
check-quote-consistency=no
|
||||||
|
|
||||||
|
# This flag controls whether the implicit-str-concat should generate a warning
|
||||||
|
# on implicit string concatenation in sequences defined over several lines.
|
||||||
|
check-str-concat-over-line-jumps=no
|
||||||
|
|
||||||
|
|
||||||
|
[TYPECHECK]
|
||||||
|
|
||||||
|
# List of decorators that produce context managers, such as
|
||||||
|
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||||
|
# produce valid context managers.
|
||||||
|
contextmanager-decorators=contextlib.contextmanager
|
||||||
|
|
||||||
|
# List of members which are set dynamically and missed by pylint inference
|
||||||
|
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||||
|
# expressions are accepted.
|
||||||
|
generated-members=
|
||||||
|
|
||||||
|
# Tells whether to warn about missing members when the owner of the attribute
|
||||||
|
# is inferred to be None.
|
||||||
|
ignore-none=yes
|
||||||
|
|
||||||
|
# This flag controls whether pylint should warn about no-member and similar
|
||||||
|
# checks whenever an opaque object is returned when inferring. The inference
|
||||||
|
# can return multiple potential results while evaluating a Python object, but
|
||||||
|
# some branches might not be evaluated, which results in partial inference. In
|
||||||
|
# that case, it might be useful to still emit no-member and other checks for
|
||||||
|
# the rest of the inferred objects.
|
||||||
|
ignore-on-opaque-inference=yes
|
||||||
|
|
||||||
|
# List of symbolic message names to ignore for Mixin members.
|
||||||
|
ignored-checks-for-mixins=no-member,
|
||||||
|
not-async-context-manager,
|
||||||
|
not-context-manager,
|
||||||
|
attribute-defined-outside-init
|
||||||
|
|
||||||
|
# List of class names for which member attributes should not be checked (useful
|
||||||
|
# for classes with dynamically set attributes). This supports the use of
|
||||||
|
# qualified names.
|
||||||
|
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
||||||
|
|
||||||
|
# Show a hint with possible names when a member name was not found. The aspect
|
||||||
|
# of finding the hint is based on edit distance.
|
||||||
|
missing-member-hint=yes
|
||||||
|
|
||||||
|
# The minimum edit distance a name should have in order to be considered a
|
||||||
|
# similar match for a missing member name.
|
||||||
|
missing-member-hint-distance=1
|
||||||
|
|
||||||
|
# The total number of similar names that should be taken in consideration when
|
||||||
|
# showing a hint for a missing member.
|
||||||
|
missing-member-max-choices=1
|
||||||
|
|
||||||
|
# Regex pattern to define which classes are considered mixins.
|
||||||
|
mixin-class-rgx=.*[Mm]ixin
|
||||||
|
|
||||||
|
# List of decorators that change the signature of a decorated function.
|
||||||
|
signature-mutators=
|
||||||
|
|
||||||
|
|
||||||
|
[VARIABLES]
|
||||||
|
|
||||||
|
# List of additional names supposed to be defined in builtins. Remember that
|
||||||
|
# you should avoid defining new builtins when possible.
|
||||||
|
additional-builtins=
|
||||||
|
|
||||||
|
# Tells whether unused global variables should be treated as a violation.
|
||||||
|
allow-global-unused-variables=yes
|
||||||
|
|
||||||
|
# List of names allowed to shadow builtins
|
||||||
|
allowed-redefined-builtins=
|
||||||
|
|
||||||
|
# List of strings which can identify a callback function by name. A callback
|
||||||
|
# name must start or end with one of those strings.
|
||||||
|
callbacks=cb_,
|
||||||
|
_cb
|
||||||
|
|
||||||
|
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||||
|
# not be used).
|
||||||
|
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||||
|
|
||||||
|
# Argument names that match this expression will be ignored.
|
||||||
|
ignored-argument-names=_.*|^ignored_|^unused_
|
||||||
|
|
||||||
|
# Tells whether we should check for unused import in __init__ files.
|
||||||
|
init-import=no
|
||||||
|
|
||||||
|
# List of qualified module names which can have objects that can redefine
|
||||||
|
# builtins.
|
||||||
|
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
Homepage
|
Homepage
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
<a href="https://pyrofork.mayuri.my.id">
|
<a href="https://pyrofork.wulan17.dev">
|
||||||
Documentation
|
Documentation
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
|
|
@ -44,7 +44,7 @@ async def hello(client, message):
|
||||||
app.run()
|
app.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pyrofork** is a modern, elegant and asynchronous [MTProto API](https://pyrofork.mayuri.my.id/topics/mtproto-vs-botapi)
|
**Pyrofork** is a modern, elegant and asynchronous [MTProto API](https://pyrofork.wulan17.dev/main/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
|
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.
|
identity (bot API alternative) using Python.
|
||||||
|
|
||||||
|
|
@ -72,6 +72,6 @@ pip3 install pyrofork
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
- Check out the docs at https://pyrofork.mayuri.my.id to learn more about Pyrofork, get started right
|
- Check out the docs at https://pyrofork.wulan17.dev to learn more about Pyrofork, get started right
|
||||||
away and discover more in-depth material for building your client applications.
|
away and discover more in-depth material for building your client applications.
|
||||||
- Join the official group at https://t.me/MayuriChan_Chat and stay tuned for news, updates and announcements.
|
- Join the official group at https://t.me/MayuriChan_Chat and stay tuned for news, updates and announcements.
|
||||||
|
|
|
||||||
115
build-docs.sh
115
build-docs.sh
|
|
@ -1,42 +1,87 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
export DOCS_KEY
|
|
||||||
VENV="$(pwd)"/venv
|
|
||||||
export VENV
|
|
||||||
|
|
||||||
if [[ "$(echo "$GITHUB_REF" | cut -d '/' -f "1 2")" == "refs/tags" ]]; then
|
# Check if config.sh exists
|
||||||
branch="main"
|
if [ -f config.sh ]; then
|
||||||
elif [[ "$GITHUB_REF" == "refs/heads/staging" ]]; then
|
source config.sh
|
||||||
branch="staging"
|
fi
|
||||||
else
|
|
||||||
b="$(echo "$GITHUB_REF" | cut -d '/' -f '3 4')"
|
function parse_parameters() {
|
||||||
if [[ $(echo "$b" | cut -d '/' -f 1 ) == "dev" ]]; then
|
while (($#)); do
|
||||||
b="$(echo "$b" | cut -d '/' -f 2)"
|
case $1 in
|
||||||
if [[ "$b" =~ ^[0-9]\.[0-9]\.x ]]; then
|
all | configure | cleanup | virtualenv | build | clone | push ) action=$1 ;;
|
||||||
branch="$b"
|
*) exit 33 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_configure() {
|
||||||
|
echo "#!/bin/bash" > config.sh
|
||||||
|
echo "export VENV=\"$(pwd)/venv\"" >> config.sh
|
||||||
|
|
||||||
|
if [[ "$(echo "$GITHUB_REF" | cut -d '/' -f "1 2")" == "refs/tags" ]]; then
|
||||||
|
echo "export BRANCH=\"main\"" >> config.sh
|
||||||
|
elif [[ "$GITHUB_REF" == "refs/heads/staging" ]]; then
|
||||||
|
echo "export BRANCH=\"staging\"" >> config.sh
|
||||||
|
else
|
||||||
|
b="$(echo "$GITHUB_REF" | cut -d '/' -f '3 4')"
|
||||||
|
if [[ $(echo "$b" | cut -d '/' -f 1 ) == "dev" ]]; then
|
||||||
|
b="$(echo "$b" | cut -d '/' -f 2)"
|
||||||
|
if [[ "$b" =~ ^[0-9]\.[0-9]\.x ]]; then
|
||||||
|
echo "export BRANCH=\"$b\"" >> config.sh
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
fi
|
chmod +x config.sh
|
||||||
|
}
|
||||||
|
|
||||||
make clean
|
function do_cleanup() {
|
||||||
make clean-docs
|
make clean
|
||||||
make venv
|
make clean-docs
|
||||||
make api
|
}
|
||||||
"$VENV"/bin/pip install -e '.[docs]'
|
|
||||||
cd compiler/docs || exit 1 && "$VENV"/bin/python compiler.py
|
function do_virtualenv() {
|
||||||
cd ../.. || exit 1
|
make venv
|
||||||
"$VENV"/bin/sphinx-build -b html "docs/source" "docs/build/html" -j auto
|
make api
|
||||||
git clone https://wulan17:"$DOCS_KEY"@github.com/Mayuri-Chan/pyrofork-docs.git
|
"$VENV"/bin/pip install -e '.[docs]'
|
||||||
cd pyrofork-docs || exit 1
|
}
|
||||||
mkdir -p "$branch"
|
|
||||||
cd "$branch" || exit 1
|
function do_build() {
|
||||||
rm -rf _includes api genindex.html intro py-modindex.html sitemap.xml support.html topics _static faq index.html objects.inv searchindex.js start telegram
|
cd compiler/docs || exit 1 && "$VENV"/bin/python compiler.py
|
||||||
cp -r ../../docs/build/html/* .
|
cd ../.. || exit 1
|
||||||
git config --local user.name "Mayuri-Chan"
|
"$VENV"/bin/sphinx-build -b html "docs/source" "docs/build/html" -j auto
|
||||||
git config --local user.email "mayuri@mayuri.my.id"
|
}
|
||||||
git add --all
|
|
||||||
git commit -a -m "docs: $branch: Update docs $(date '+%Y-%m-%d | %H:%m:%S %p %Z')" --signoff
|
function do_clone() {
|
||||||
git push -u origin --all
|
git clone https://wulan17:"$DOCS_KEY"@github.com/Mayuri-Chan/pyrofork-docs.git
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_push() {
|
||||||
|
cd pyrofork-docs || exit 1
|
||||||
|
mkdir -p "$BRANCH"
|
||||||
|
cd "$BRANCH" || exit 1
|
||||||
|
rm -rf _includes api genindex.html intro py-modindex.html sitemap.xml support.html topics _static faq index.html objects.inv searchindex.js start telegram
|
||||||
|
cp -r ../../docs/build/html/* .
|
||||||
|
git config --local user.name "Mayuri-Chan"
|
||||||
|
git config --local user.email "mayuri@mayuri.my.id"
|
||||||
|
git add --all
|
||||||
|
git commit -a -m "docs: $BRANCH: Update docs $(date '+%Y-%m-%d | %H:%m:%S %p %Z')" --signoff
|
||||||
|
git push -u origin --all
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_all() {
|
||||||
|
do_configure
|
||||||
|
source config.sh
|
||||||
|
do_cleanup
|
||||||
|
do_virtualenv
|
||||||
|
do_build
|
||||||
|
do_clone
|
||||||
|
do_push
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_parameters "$@"
|
||||||
|
do_"${action:=all}"
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ def get_type_hint(type: str) -> str:
|
||||||
return f"Optional[{type}] = None" if is_flag else type
|
return f"Optional[{type}] = None" if is_flag else type
|
||||||
else:
|
else:
|
||||||
ns, name = type.split(".") if "." in type else ("", type)
|
ns, name = type.split(".") if "." in type else ("", type)
|
||||||
type = f'"raw.base.' + ".".join([ns, name]).strip(".") + '"'
|
type = '"raw.base.' + ".".join([ns, name]).strip(".") + '"'
|
||||||
|
|
||||||
return f'{type}{" = None" if is_flag else ""}'
|
return f'{type}{" = None" if is_flag else ""}'
|
||||||
|
|
||||||
|
|
@ -430,11 +430,11 @@ def start(format: bool = False):
|
||||||
if function_docs:
|
if function_docs:
|
||||||
docstring += function_docs["desc"] + "\n"
|
docstring += function_docs["desc"] + "\n"
|
||||||
else:
|
else:
|
||||||
docstring += f"Telegram API function."
|
docstring += "Telegram API function."
|
||||||
|
|
||||||
docstring += f"\n\n Details:\n - Layer: ``{layer}``\n - ID: ``{c.id[2:].upper()}``\n\n"
|
docstring += f"\n\n Details:\n - Layer: ``{layer}``\n - ID: ``{c.id[2:].upper()}``\n\n"
|
||||||
docstring += f" Parameters:\n " + \
|
docstring += " Parameters:\n " + \
|
||||||
(f"\n ".join(docstring_args) if docstring_args else "No parameters required.\n")
|
("\n ".join(docstring_args) if docstring_args else "No parameters required.\n")
|
||||||
|
|
||||||
if c.section == "functions":
|
if c.section == "functions":
|
||||||
docstring += "\n Returns:\n " + get_docstring_arg_type(c.qualtype)
|
docstring += "\n Returns:\n " + get_docstring_arg_type(c.qualtype)
|
||||||
|
|
@ -442,12 +442,12 @@ def start(format: bool = False):
|
||||||
references, count = get_references(c.qualname, "constructors")
|
references, count = get_references(c.qualname, "constructors")
|
||||||
|
|
||||||
if references:
|
if references:
|
||||||
docstring += f"\n Functions:\n This object can be returned by " \
|
docstring += "\n Functions:\n This object can be returned by " \
|
||||||
f"{count} function{'s' if count > 1 else ''}.\n\n" \
|
f"{count} function{'s' if count > 1 else ''}.\n\n" \
|
||||||
f" .. currentmodule:: pyrogram.raw.functions\n\n" \
|
" .. currentmodule:: pyrogram.raw.functions\n\n" \
|
||||||
f" .. autosummary::\n" \
|
" .. autosummary::\n" \
|
||||||
f" :nosignatures:\n\n" \
|
" :nosignatures:\n\n" \
|
||||||
f" " + references
|
" " + references
|
||||||
|
|
||||||
write_types = read_types = "" if c.has_flags else "# No flags\n "
|
write_types = read_types = "" if c.has_flags else "# No flags\n "
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,4 +20,4 @@ class {name}: # type: ignore
|
||||||
raise TypeError("Base types can only be used for type checking purposes: "
|
raise TypeError("Base types can only be used for type checking purposes: "
|
||||||
"you tried to use a base type instance as argument, "
|
"you tried to use a base type instance as argument, "
|
||||||
"but you need to instantiate one of its constructors instead. "
|
"but you need to instantiate one of its constructors instead. "
|
||||||
"More info: https://pyrofork.mayuri.my.id/telegram/base/{doc_name}")
|
"More info: https://pyrofork.wulan17.dev/telegram/base/{doc_name}")
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ def pyrogram_api():
|
||||||
stop_transmission
|
stop_transmission
|
||||||
export_session_string
|
export_session_string
|
||||||
set_parse_mode
|
set_parse_mode
|
||||||
|
ping
|
||||||
""",
|
""",
|
||||||
conversation="""
|
conversation="""
|
||||||
Conversation
|
Conversation
|
||||||
|
|
@ -164,7 +165,9 @@ def pyrogram_api():
|
||||||
""",
|
""",
|
||||||
messages="""
|
messages="""
|
||||||
Messages
|
Messages
|
||||||
|
add_task_to_todo
|
||||||
send_message
|
send_message
|
||||||
|
forward_media_group
|
||||||
forward_messages
|
forward_messages
|
||||||
copy_message
|
copy_message
|
||||||
copy_media_group
|
copy_media_group
|
||||||
|
|
@ -172,6 +175,7 @@ def pyrogram_api():
|
||||||
send_audio
|
send_audio
|
||||||
send_document
|
send_document
|
||||||
send_sticker
|
send_sticker
|
||||||
|
send_todo
|
||||||
send_video
|
send_video
|
||||||
send_animation
|
send_animation
|
||||||
send_voice
|
send_voice
|
||||||
|
|
@ -183,6 +187,7 @@ def pyrogram_api():
|
||||||
send_contact
|
send_contact
|
||||||
send_cached_media
|
send_cached_media
|
||||||
send_reaction
|
send_reaction
|
||||||
|
set_todo_tasks_completion
|
||||||
edit_message_text
|
edit_message_text
|
||||||
edit_message_caption
|
edit_message_caption
|
||||||
edit_message_media
|
edit_message_media
|
||||||
|
|
@ -193,8 +198,11 @@ def pyrogram_api():
|
||||||
edit_inline_reply_markup
|
edit_inline_reply_markup
|
||||||
send_chat_action
|
send_chat_action
|
||||||
delete_messages
|
delete_messages
|
||||||
|
delete_scheduled_messages
|
||||||
get_available_effects
|
get_available_effects
|
||||||
get_messages
|
get_messages
|
||||||
|
get_message_read_participants
|
||||||
|
get_scheduled_messages
|
||||||
get_media_group
|
get_media_group
|
||||||
get_chat_history
|
get_chat_history
|
||||||
get_chat_history_count
|
get_chat_history_count
|
||||||
|
|
@ -208,12 +216,18 @@ def pyrogram_api():
|
||||||
search_messages_count
|
search_messages_count
|
||||||
search_global
|
search_global
|
||||||
search_global_count
|
search_global_count
|
||||||
|
search_global_hashtag_messages
|
||||||
|
search_global_hashtag_messages_count
|
||||||
download_media
|
download_media
|
||||||
stream_media
|
stream_media
|
||||||
get_discussion_message
|
get_discussion_message
|
||||||
get_discussion_replies
|
get_discussion_replies
|
||||||
get_discussion_replies_count
|
get_discussion_replies_count
|
||||||
get_custom_emoji_stickers
|
get_custom_emoji_stickers
|
||||||
|
transcribe_audio
|
||||||
|
translate_message_text
|
||||||
|
start_bot
|
||||||
|
delete_chat_history
|
||||||
""",
|
""",
|
||||||
chats="""
|
chats="""
|
||||||
Chats
|
Chats
|
||||||
|
|
@ -226,6 +240,9 @@ def pyrogram_api():
|
||||||
set_administrator_title
|
set_administrator_title
|
||||||
set_chat_photo
|
set_chat_photo
|
||||||
delete_chat_photo
|
delete_chat_photo
|
||||||
|
delete_folder
|
||||||
|
export_folder_link
|
||||||
|
update_folder
|
||||||
set_chat_title
|
set_chat_title
|
||||||
set_chat_description
|
set_chat_description
|
||||||
set_chat_permissions
|
set_chat_permissions
|
||||||
|
|
@ -238,10 +255,11 @@ def pyrogram_api():
|
||||||
get_chat_members_count
|
get_chat_members_count
|
||||||
get_dialogs
|
get_dialogs
|
||||||
get_dialogs_count
|
get_dialogs_count
|
||||||
|
get_folders
|
||||||
get_forum_topics
|
get_forum_topics
|
||||||
get_forum_topics_by_id
|
get_forum_topics_by_id
|
||||||
|
get_forum_topics_count
|
||||||
set_chat_username
|
set_chat_username
|
||||||
get_nearby_chats
|
|
||||||
archive_chats
|
archive_chats
|
||||||
unarchive_chats
|
unarchive_chats
|
||||||
add_chat_members
|
add_chat_members
|
||||||
|
|
@ -267,7 +285,10 @@ def pyrogram_api():
|
||||||
hide_general_topic
|
hide_general_topic
|
||||||
reopen_forum_topic
|
reopen_forum_topic
|
||||||
reopen_general_topic
|
reopen_general_topic
|
||||||
|
transfer_chat_ownership
|
||||||
unhide_general_topic
|
unhide_general_topic
|
||||||
|
update_color
|
||||||
|
update_folder
|
||||||
""",
|
""",
|
||||||
users="""
|
users="""
|
||||||
Users
|
Users
|
||||||
|
|
@ -333,6 +354,39 @@ def pyrogram_api():
|
||||||
get_contacts
|
get_contacts
|
||||||
get_contacts_count
|
get_contacts_count
|
||||||
""",
|
""",
|
||||||
|
payments="""
|
||||||
|
Payments
|
||||||
|
apply_gift_code
|
||||||
|
check_gift_code
|
||||||
|
convert_gift
|
||||||
|
create_invoice_link
|
||||||
|
get_payment_form
|
||||||
|
get_stars_transactions
|
||||||
|
get_stars_transactions_by_id
|
||||||
|
get_available_gifts
|
||||||
|
get_upgraded_gift
|
||||||
|
get_chat_gifts_count
|
||||||
|
get_chat_gifts
|
||||||
|
hide_gift
|
||||||
|
refund_star_payment
|
||||||
|
search_gifts_for_resale
|
||||||
|
send_invoice
|
||||||
|
send_paid_media
|
||||||
|
send_paid_reaction
|
||||||
|
send_payment_form
|
||||||
|
send_gift
|
||||||
|
send_resold_gift
|
||||||
|
set_gift_resale_price
|
||||||
|
set_pinned_gifts
|
||||||
|
show_gift
|
||||||
|
transfer_gift
|
||||||
|
upgrade_gift
|
||||||
|
get_stars_balance
|
||||||
|
""",
|
||||||
|
phone="""
|
||||||
|
Phone
|
||||||
|
get_call_members
|
||||||
|
""",
|
||||||
password="""
|
password="""
|
||||||
Password
|
Password
|
||||||
enable_cloud_password
|
enable_cloud_password
|
||||||
|
|
@ -357,10 +411,21 @@ def pyrogram_api():
|
||||||
set_chat_menu_button
|
set_chat_menu_button
|
||||||
get_chat_menu_button
|
get_chat_menu_button
|
||||||
answer_web_app_query
|
answer_web_app_query
|
||||||
answer_pre_checkout_query
|
|
||||||
get_bot_info
|
get_bot_info
|
||||||
set_bot_info
|
set_bot_info
|
||||||
get_collectible_item_info
|
get_collectible_item_info
|
||||||
|
get_owned_bots
|
||||||
|
get_similar_bots
|
||||||
|
""",
|
||||||
|
business="""
|
||||||
|
Telegram Business
|
||||||
|
answer_pre_checkout_query
|
||||||
|
answer_shipping_query
|
||||||
|
delete_business_messages
|
||||||
|
get_business_connection
|
||||||
|
get_business_account_gifts
|
||||||
|
get_business_account_star_balance
|
||||||
|
transfer_business_account_stars
|
||||||
""",
|
""",
|
||||||
authorization="""
|
authorization="""
|
||||||
Authorization
|
Authorization
|
||||||
|
|
@ -372,13 +437,13 @@ def pyrogram_api():
|
||||||
resend_code
|
resend_code
|
||||||
sign_in
|
sign_in
|
||||||
sign_in_bot
|
sign_in_bot
|
||||||
sign_up
|
sign_in_qrcode
|
||||||
get_password_hint
|
get_password_hint
|
||||||
check_password
|
check_password
|
||||||
send_recovery_code
|
send_recovery_code
|
||||||
recover_password
|
recover_password
|
||||||
accept_terms_of_service
|
|
||||||
log_out
|
log_out
|
||||||
|
get_active_sessions
|
||||||
""",
|
""",
|
||||||
advanced="""
|
advanced="""
|
||||||
Advanced
|
Advanced
|
||||||
|
|
@ -400,7 +465,7 @@ def pyrogram_api():
|
||||||
fmt_keys = {}
|
fmt_keys = {}
|
||||||
|
|
||||||
for k, v in categories.items():
|
for k, v in categories.items():
|
||||||
name, *methods = get_title_list(v)
|
_, *methods = get_title_list(v)
|
||||||
fmt_keys.update({k: "\n ".join("{0} <{0}>".format(m) for m in methods)})
|
fmt_keys.update({k: "\n ".join("{0} <{0}>".format(m) for m in methods)})
|
||||||
|
|
||||||
for method in methods:
|
for method in methods:
|
||||||
|
|
@ -434,6 +499,7 @@ def pyrogram_api():
|
||||||
BusinessWeeklyOpen
|
BusinessWeeklyOpen
|
||||||
BusinessWorkingHours
|
BusinessWorkingHours
|
||||||
User
|
User
|
||||||
|
Username
|
||||||
Chat
|
Chat
|
||||||
ChatPreview
|
ChatPreview
|
||||||
ChatPhoto
|
ChatPhoto
|
||||||
|
|
@ -449,24 +515,41 @@ def pyrogram_api():
|
||||||
ChatJoinedByRequest
|
ChatJoinedByRequest
|
||||||
ChatJoiner
|
ChatJoiner
|
||||||
Dialog
|
Dialog
|
||||||
|
Folder
|
||||||
Restriction
|
Restriction
|
||||||
EmojiStatus
|
EmojiStatus
|
||||||
|
ExportedFolderLink
|
||||||
ForumTopic
|
ForumTopic
|
||||||
PeerUser
|
PeerUser
|
||||||
PeerChannel
|
PeerChannel
|
||||||
BotInfo
|
BotInfo
|
||||||
|
GroupCallMember
|
||||||
ChatColor
|
ChatColor
|
||||||
CollectibleItemInfo
|
CollectibleItemInfo
|
||||||
|
BotVerification
|
||||||
""",
|
""",
|
||||||
messages_media="""
|
messages_media="""
|
||||||
Messages & Media
|
Messages & Media
|
||||||
Message
|
Message
|
||||||
MessageEntity
|
MessageEntity
|
||||||
|
MessageOriginChannel
|
||||||
|
MessageOriginChat
|
||||||
|
MessageOriginHiddenUser
|
||||||
|
MessageOriginImport
|
||||||
|
MessageOriginUser
|
||||||
|
MessageOrigin
|
||||||
Photo
|
Photo
|
||||||
Thumbnail
|
Thumbnail
|
||||||
|
TodoList
|
||||||
|
TodoTask
|
||||||
|
TodoTasksAdded
|
||||||
|
TodoTasksCompleted
|
||||||
|
TodoTasksIncompleted
|
||||||
Audio
|
Audio
|
||||||
AvailableEffect
|
AvailableEffect
|
||||||
Document
|
Document
|
||||||
|
ExternalReplyInfo
|
||||||
|
AlternativeVideo
|
||||||
Animation
|
Animation
|
||||||
Video
|
Video
|
||||||
Voice
|
Voice
|
||||||
|
|
@ -477,15 +560,18 @@ def pyrogram_api():
|
||||||
Sticker
|
Sticker
|
||||||
StickerSet
|
StickerSet
|
||||||
Game
|
Game
|
||||||
GiftedPremium
|
Gift
|
||||||
|
GiftAttribute
|
||||||
Giveaway
|
Giveaway
|
||||||
GiveawayLaunched
|
GiveawayLaunched
|
||||||
GiveawayResult
|
GiveawayResult
|
||||||
MessageInvoice
|
|
||||||
MessageStory
|
MessageStory
|
||||||
WebPage
|
WebPage
|
||||||
WebPageEmpty
|
WebPageEmpty
|
||||||
WebPagePreview
|
WebPagePreview
|
||||||
|
TranscribedAudio
|
||||||
|
TranslatedText
|
||||||
|
TextQuote
|
||||||
Poll
|
Poll
|
||||||
PollOption
|
PollOption
|
||||||
Dice
|
Dice
|
||||||
|
|
@ -496,19 +582,26 @@ def pyrogram_api():
|
||||||
VideoChatMembersInvited
|
VideoChatMembersInvited
|
||||||
WebAppData
|
WebAppData
|
||||||
MessageReactions
|
MessageReactions
|
||||||
|
MessageReactor
|
||||||
ChatReactions
|
ChatReactions
|
||||||
ForumTopicCreated
|
ForumTopicCreated
|
||||||
ForumTopicEdited
|
ForumTopicEdited
|
||||||
ForumTopicClosed
|
ForumTopicClosed
|
||||||
|
ForumTopicDeleted
|
||||||
ForumTopicReopened
|
ForumTopicReopened
|
||||||
GeneralTopicHidden
|
GeneralTopicHidden
|
||||||
GeneralTopicUnhidden
|
GeneralTopicUnhidden
|
||||||
Reaction
|
Reaction
|
||||||
ReactionCount
|
|
||||||
ReactionType
|
|
||||||
MessageReactionUpdated
|
MessageReactionUpdated
|
||||||
MessageReactionCountUpdated
|
MessageReactionCountUpdated
|
||||||
SuccessfulPayment
|
ExportedStoryLink
|
||||||
|
ChatTheme
|
||||||
|
ChatWallpaper
|
||||||
|
ContactRegistered
|
||||||
|
ReadParticipant
|
||||||
|
ScreenshotTaken
|
||||||
|
Wallpaper
|
||||||
|
WallpaperSettings
|
||||||
""",
|
""",
|
||||||
stories="""
|
stories="""
|
||||||
Stories
|
Stories
|
||||||
|
|
@ -524,14 +617,38 @@ def pyrogram_api():
|
||||||
InputMediaArea
|
InputMediaArea
|
||||||
InputMediaAreaChannelPost
|
InputMediaAreaChannelPost
|
||||||
""",
|
""",
|
||||||
|
payment="""
|
||||||
|
Payment
|
||||||
|
CheckedGiftCode
|
||||||
|
ExtendedMediaPreview
|
||||||
|
GiftCode
|
||||||
|
GiftedPremium
|
||||||
|
InputStarsTransaction
|
||||||
|
Invoice
|
||||||
|
LabeledPrice
|
||||||
|
PaidMedia
|
||||||
|
PaidMessagePriceChanged
|
||||||
|
PaymentForm
|
||||||
|
PaymentInfo
|
||||||
|
PaymentRefunded
|
||||||
|
PurchasedPaidMedia
|
||||||
|
StarsStatus
|
||||||
|
StarsTransaction
|
||||||
|
SuccessfulPayment
|
||||||
|
""",
|
||||||
pyromod="""
|
pyromod="""
|
||||||
Pyromod
|
Pyromod
|
||||||
Identifier
|
Identifier
|
||||||
Listener
|
Listener
|
||||||
""",
|
""",
|
||||||
|
bot="""
|
||||||
|
Bot
|
||||||
|
BotAllowed
|
||||||
|
BotApp
|
||||||
|
BotBusinessConnection
|
||||||
|
""",
|
||||||
bot_keyboards="""
|
bot_keyboards="""
|
||||||
Bot keyboards
|
Bot keyboards
|
||||||
BotBusinessConnection
|
|
||||||
ReplyKeyboardMarkup
|
ReplyKeyboardMarkup
|
||||||
KeyboardButton
|
KeyboardButton
|
||||||
ReplyKeyboardRemove
|
ReplyKeyboardRemove
|
||||||
|
|
@ -541,6 +658,9 @@ def pyrogram_api():
|
||||||
RequestPeerTypeChannel
|
RequestPeerTypeChannel
|
||||||
RequestPeerTypeChat
|
RequestPeerTypeChat
|
||||||
RequestPeerTypeUser
|
RequestPeerTypeUser
|
||||||
|
RequestedChats
|
||||||
|
RequestedChat
|
||||||
|
RequestedUser
|
||||||
LoginUrl
|
LoginUrl
|
||||||
ForceReply
|
ForceReply
|
||||||
CallbackQuery
|
CallbackQuery
|
||||||
|
|
@ -552,9 +672,6 @@ def pyrogram_api():
|
||||||
MenuButtonWebApp
|
MenuButtonWebApp
|
||||||
MenuButtonDefault
|
MenuButtonDefault
|
||||||
SentWebAppMessage
|
SentWebAppMessage
|
||||||
PaymentInfo
|
|
||||||
PreCheckoutQuery
|
|
||||||
ShippingAddress
|
|
||||||
""",
|
""",
|
||||||
bot_commands="""
|
bot_commands="""
|
||||||
Bot commands
|
Bot commands
|
||||||
|
|
@ -568,6 +685,13 @@ def pyrogram_api():
|
||||||
BotCommandScopeChatAdministrators
|
BotCommandScopeChatAdministrators
|
||||||
BotCommandScopeChatMember
|
BotCommandScopeChatMember
|
||||||
""",
|
""",
|
||||||
|
business="""
|
||||||
|
Telegram Business
|
||||||
|
PreCheckoutQuery
|
||||||
|
ShippingAddress
|
||||||
|
ShippingOption
|
||||||
|
ShippingQuery
|
||||||
|
""",
|
||||||
input_media="""
|
input_media="""
|
||||||
Input Media
|
Input Media
|
||||||
InputMedia
|
InputMedia
|
||||||
|
|
@ -605,15 +729,28 @@ def pyrogram_api():
|
||||||
PreCheckoutQuery
|
PreCheckoutQuery
|
||||||
PreCheckoutQuery.answer
|
PreCheckoutQuery.answer
|
||||||
""",
|
""",
|
||||||
|
shipping_query="""
|
||||||
|
ShippingQuery
|
||||||
|
ShippingQuery.answer
|
||||||
|
""",
|
||||||
input_message_content="""
|
input_message_content="""
|
||||||
InputMessageContent
|
InputMessageContent
|
||||||
InputMessageContent
|
InputMessageContent
|
||||||
InputReplyToMessage
|
InputReplyToMessage
|
||||||
|
InputReplyToMonoforum
|
||||||
InputReplyToStory
|
InputReplyToStory
|
||||||
InputTextMessageContent
|
InputTextMessageContent
|
||||||
|
InputLocationMessageContent
|
||||||
|
InputVenueMessageContent
|
||||||
|
InputContactMessageContent
|
||||||
|
InputInvoiceMessageContent
|
||||||
|
InputTodoTask
|
||||||
""",
|
""",
|
||||||
authorization="""
|
authorization="""
|
||||||
Authorization
|
Authorization
|
||||||
|
ActiveSession
|
||||||
|
ActiveSessions
|
||||||
|
LoginToken
|
||||||
SentCode
|
SentCode
|
||||||
TermsOfService
|
TermsOfService
|
||||||
"""
|
"""
|
||||||
|
|
@ -631,7 +768,7 @@ def pyrogram_api():
|
||||||
fmt_keys = {}
|
fmt_keys = {}
|
||||||
|
|
||||||
for k, v in categories.items():
|
for k, v in categories.items():
|
||||||
name, *types = get_title_list(v)
|
_, *types = get_title_list(v)
|
||||||
|
|
||||||
fmt_keys.update({k: "\n ".join(types)})
|
fmt_keys.update({k: "\n ".join(types)})
|
||||||
|
|
||||||
|
|
@ -685,6 +822,8 @@ def pyrogram_api():
|
||||||
Message.reply_web_page
|
Message.reply_web_page
|
||||||
Message.get_media_group
|
Message.get_media_group
|
||||||
Message.react
|
Message.react
|
||||||
|
Message.transcribe
|
||||||
|
Message.translate
|
||||||
Message.wait_for_click
|
Message.wait_for_click
|
||||||
""",
|
""",
|
||||||
chat="""
|
chat="""
|
||||||
|
|
@ -743,6 +882,26 @@ def pyrogram_api():
|
||||||
Story.reply_video_note
|
Story.reply_video_note
|
||||||
Story.reply_voice
|
Story.reply_voice
|
||||||
""",
|
""",
|
||||||
|
folder="""
|
||||||
|
Folder
|
||||||
|
Folder.delete
|
||||||
|
Folder.update
|
||||||
|
Folder.include_chat
|
||||||
|
Folder.exclude_chat
|
||||||
|
Folder.update_color
|
||||||
|
Folder.pin_chat
|
||||||
|
Folder.remove_chat
|
||||||
|
Folder.export_link
|
||||||
|
""",
|
||||||
|
gift="""
|
||||||
|
Gift
|
||||||
|
Gift.show
|
||||||
|
Gift.hide
|
||||||
|
Gift.convert
|
||||||
|
Gift.upgrade
|
||||||
|
Gift.transfer
|
||||||
|
Gift.wear
|
||||||
|
""",
|
||||||
callback_query="""
|
callback_query="""
|
||||||
Callback Query
|
Callback Query
|
||||||
CallbackQuery.answer
|
CallbackQuery.answer
|
||||||
|
|
@ -759,6 +918,10 @@ def pyrogram_api():
|
||||||
PreCheckoutQuery
|
PreCheckoutQuery
|
||||||
PreCheckoutQuery.answer
|
PreCheckoutQuery.answer
|
||||||
""",
|
""",
|
||||||
|
shipping_query="""
|
||||||
|
ShippingQuery
|
||||||
|
ShippingQuery.answer
|
||||||
|
""",
|
||||||
chat_join_request="""
|
chat_join_request="""
|
||||||
ChatJoinRequest
|
ChatJoinRequest
|
||||||
ChatJoinRequest.approve
|
ChatJoinRequest.approve
|
||||||
|
|
|
||||||
40
compiler/docs/template/bound-methods.rst
vendored
40
compiler/docs/template/bound-methods.rst
vendored
|
|
@ -102,7 +102,7 @@ InlineQuery
|
||||||
{inline_query_toctree}
|
{inline_query_toctree}
|
||||||
|
|
||||||
PreCheckoutQuery
|
PreCheckoutQuery
|
||||||
-----------
|
----------------
|
||||||
|
|
||||||
.. hlist::
|
.. hlist::
|
||||||
:columns: 2
|
:columns: 2
|
||||||
|
|
@ -114,6 +114,19 @@ PreCheckoutQuery
|
||||||
|
|
||||||
{pre_checkout_query_toctree}
|
{pre_checkout_query_toctree}
|
||||||
|
|
||||||
|
ShippingQuery
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. hlist::
|
||||||
|
:columns: 2
|
||||||
|
|
||||||
|
{shipping_query_hlist}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{shipping_query_toctree}
|
||||||
|
|
||||||
ChatJoinRequest
|
ChatJoinRequest
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
@ -127,3 +140,28 @@ ChatJoinRequest
|
||||||
|
|
||||||
{chat_join_request_toctree}
|
{chat_join_request_toctree}
|
||||||
|
|
||||||
|
Folder
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. hlist::
|
||||||
|
:columns: 2
|
||||||
|
|
||||||
|
{folder_hlist}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{folder_toctree}
|
||||||
|
|
||||||
|
Gift
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. hlist::
|
||||||
|
:columns: 2
|
||||||
|
|
||||||
|
{gift_hlist}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{gift_toctree}
|
||||||
|
|
|
||||||
28
compiler/docs/template/methods.rst
vendored
28
compiler/docs/template/methods.rst
vendored
|
|
@ -112,6 +112,19 @@ Stickers
|
||||||
|
|
||||||
{stickers}
|
{stickers}
|
||||||
|
|
||||||
|
Telegram Business
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{business}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{business}
|
||||||
|
|
||||||
Users
|
Users
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
@ -177,6 +190,19 @@ Bots
|
||||||
|
|
||||||
{bots}
|
{bots}
|
||||||
|
|
||||||
|
Payments
|
||||||
|
----
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{payments}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{payments}
|
||||||
|
|
||||||
Authorization
|
Authorization
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
@ -204,4 +230,4 @@ Learn more about how to use the raw API at :doc:`Advanced Usage <../../topics/ad
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:hidden:
|
:hidden:
|
||||||
|
|
||||||
{advanced}
|
{advanced}
|
||||||
|
|
|
||||||
67
compiler/docs/template/types.rst
vendored
67
compiler/docs/template/types.rst
vendored
|
|
@ -73,6 +73,19 @@ Pyromod
|
||||||
|
|
||||||
{pyromod}
|
{pyromod}
|
||||||
|
|
||||||
|
Bot
|
||||||
|
---
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{bot}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{bot}
|
||||||
|
|
||||||
Bot keyboards
|
Bot keyboards
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
@ -99,6 +112,19 @@ Bot commands
|
||||||
|
|
||||||
{bot_commands}
|
{bot_commands}
|
||||||
|
|
||||||
|
Telegram Business
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{business}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{business}
|
||||||
|
|
||||||
Input Media
|
Input Media
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
@ -138,6 +164,45 @@ InputMessageContent
|
||||||
|
|
||||||
{input_message_content}
|
{input_message_content}
|
||||||
|
|
||||||
|
ShippingQuery
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{shipping_query}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{shipping_query}
|
||||||
|
|
||||||
|
PreCheckoutQuery
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{pre_checkout_query}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{pre_checkout_query}
|
||||||
|
|
||||||
|
Payment
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
{payment}
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
{payment}
|
||||||
|
|
||||||
Authorization
|
Authorization
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
@ -149,4 +214,4 @@ Authorization
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:hidden:
|
:hidden:
|
||||||
|
|
||||||
{authorization}
|
{authorization}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import ast
|
||||||
import csv
|
import csv
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
@ -37,6 +38,13 @@ def caml(s):
|
||||||
s = snek(s).split("_")
|
s = snek(s).split("_")
|
||||||
return "".join([str(i.title()) for i in s])
|
return "".join([str(i.title()) for i in s])
|
||||||
|
|
||||||
|
def get_classes_from_file(file_path):
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
tree = ast.parse(f.read())
|
||||||
|
|
||||||
|
classes = [node.name for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
|
||||||
|
return classes
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
shutil.rmtree(DEST, ignore_errors=True)
|
shutil.rmtree(DEST, ignore_errors=True)
|
||||||
|
|
@ -127,6 +135,20 @@ def start():
|
||||||
f_all.write(" },\n")
|
f_all.write(" },\n")
|
||||||
|
|
||||||
f_all.write("}\n")
|
f_all.write("}\n")
|
||||||
|
with open(init, "a", encoding="utf-8") as f_init:
|
||||||
|
f_init.write("\n")
|
||||||
|
all_classes = []
|
||||||
|
for i in files:
|
||||||
|
code, name = re.search(r"(\d+)_([A-Z_]+)", i).groups()
|
||||||
|
classes = get_classes_from_file("{}/{}_{}.py".format(DEST, name.lower(), code))
|
||||||
|
for j in classes:
|
||||||
|
if j not in ["BaseException", "Exception", "PyrogramException"]:
|
||||||
|
all_classes.append(j)
|
||||||
|
f_init.write("__all__ = [\n")
|
||||||
|
all_classes = sorted(set(all_classes))
|
||||||
|
for i in all_classes:
|
||||||
|
f_init.write(" \"{}\",\n".format(i))
|
||||||
|
f_init.write("]\n")
|
||||||
|
|
||||||
with open("{}/all.py".format(DEST), encoding="utf-8") as f:
|
with open("{}/all.py".format(DEST), encoding="utf-8") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@ id message
|
||||||
ABOUT_TOO_LONG The provided about/bio text is too long
|
ABOUT_TOO_LONG The provided about/bio text is too long
|
||||||
ACCESS_TOKEN_EXPIRED The bot token has expired
|
ACCESS_TOKEN_EXPIRED The bot token has expired
|
||||||
ACCESS_TOKEN_INVALID The bot access token is invalid
|
ACCESS_TOKEN_INVALID The bot access token is invalid
|
||||||
|
ADDRESS_INVALID The specified geopoint address is invalid.
|
||||||
ADMINS_TOO_MUCH The chat has too many administrators
|
ADMINS_TOO_MUCH The chat has too many administrators
|
||||||
ADMIN_ID_INVALID The specified admin ID is invalid
|
ADMIN_ID_INVALID The specified admin ID is invalid
|
||||||
ADMIN_RANK_EMOJI_NOT_ALLOWED Emoji are not allowed in custom administrator titles
|
ADMIN_RANK_EMOJI_NOT_ALLOWED Emoji are not allowed in custom administrator titles
|
||||||
ADMIN_RANK_INVALID The custom administrator title is invalid or too long
|
ADMIN_RANK_INVALID The custom administrator title is invalid or too long
|
||||||
|
ADMIN_RIGHTS_EMPTY The chatAdminRights constructor passed in keyboardButtonRequestPeer.peer_type.user_admin_rights has no rights set (i.e. flags is 0).
|
||||||
ALBUM_PHOTOS_TOO_MANY Too many photos were included in the album
|
ALBUM_PHOTOS_TOO_MANY Too many photos were included in the album
|
||||||
API_ID_INVALID The api_id/api_hash combination is invalid
|
API_ID_INVALID The api_id/api_hash combination is invalid
|
||||||
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side because it was published somewhere
|
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side because it was published somewhere
|
||||||
|
|
@ -23,6 +25,7 @@ AUTOARCHIVE_NOT_AVAILABLE This feature is not yet enabled for your account due t
|
||||||
BANK_CARD_NUMBER_INVALID The credit card number is invalid
|
BANK_CARD_NUMBER_INVALID The credit card number is invalid
|
||||||
BANNED_RIGHTS_INVALID You provided a set of restrictions that is invalid
|
BANNED_RIGHTS_INVALID You provided a set of restrictions that is invalid
|
||||||
BASE_PORT_LOC_INVALID The base port location is invalid
|
BASE_PORT_LOC_INVALID The base port location is invalid
|
||||||
|
BIRTHDAY_INVALID The age should be less than 150 year old in Telegram
|
||||||
BOTS_TOO_MUCH The chat has too many bots
|
BOTS_TOO_MUCH The chat has too many bots
|
||||||
BOT_CHANNELS_NA Bots can't edit admin privileges
|
BOT_CHANNELS_NA Bots can't edit admin privileges
|
||||||
BOT_COMMAND_DESCRIPTION_INVALID The command description was empty, too long or had invalid characters
|
BOT_COMMAND_DESCRIPTION_INVALID The command description was empty, too long or had invalid characters
|
||||||
|
|
@ -32,6 +35,7 @@ BOT_GAMES_DISABLED Bot games cannot be used in this type of chat
|
||||||
BOT_GROUPS_BLOCKED This bot can't be added to groups
|
BOT_GROUPS_BLOCKED This bot can't be added to groups
|
||||||
BOT_INLINE_DISABLED The inline feature of the bot is disabled
|
BOT_INLINE_DISABLED The inline feature of the bot is disabled
|
||||||
BOT_INVALID This is not a valid bot
|
BOT_INVALID This is not a valid bot
|
||||||
|
BOT_INVOICE_INVALID The provided invoice is invalid
|
||||||
BOT_METHOD_INVALID The method can't be used by bots
|
BOT_METHOD_INVALID The method can't be used by bots
|
||||||
BOT_MISSING This method can only be run by a bot
|
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_ONESIDE_NOT_AVAIL Bots can't pin messages for one side only in private chats
|
||||||
|
|
@ -43,7 +47,9 @@ BROADCAST_CALLS_DISABLED Broadcast calls disabled
|
||||||
BROADCAST_ID_INVALID The channel is invalid
|
BROADCAST_ID_INVALID The channel is invalid
|
||||||
BROADCAST_PUBLIC_VOTERS_FORBIDDEN Polls with public voters cannot be sent in channels
|
BROADCAST_PUBLIC_VOTERS_FORBIDDEN Polls with public voters cannot be sent in channels
|
||||||
BROADCAST_REQUIRED The request can only be used with a channel
|
BROADCAST_REQUIRED The request can only be used with a channel
|
||||||
|
BUSINESS_BOT_MISSING Business bot missing
|
||||||
BUTTON_DATA_INVALID The button callback data is invalid or too large
|
BUTTON_DATA_INVALID The button callback data is invalid or too large
|
||||||
|
BUTTON_ID_INVALID The button_id parameter is invalid
|
||||||
BUTTON_TEXT_INVALID The specified button text is invalid
|
BUTTON_TEXT_INVALID The specified button text is invalid
|
||||||
BUTTON_TYPE_INVALID The type of one of the buttons you provided is invalid
|
BUTTON_TYPE_INVALID The type of one of the buttons you provided is invalid
|
||||||
BUTTON_URL_INVALID The button url is invalid
|
BUTTON_URL_INVALID The button url is invalid
|
||||||
|
|
@ -58,11 +64,15 @@ CHANNELS_ADMIN_PUBLIC_TOO_MUCH You are an administrator of too many public chann
|
||||||
CHANNELS_TOO_MUCH You have joined too many channels or supergroups, leave some and try again
|
CHANNELS_TOO_MUCH You have joined too many channels or supergroups, leave some and try again
|
||||||
CHANNEL_ADD_INVALID Internal error.
|
CHANNEL_ADD_INVALID Internal error.
|
||||||
CHANNEL_BANNED The channel is banned
|
CHANNEL_BANNED The channel is banned
|
||||||
|
CHANNEL_ID_INVALID The specified supergroup ID is invalid.
|
||||||
CHANNEL_INVALID The channel parameter is invalid
|
CHANNEL_INVALID The channel parameter is invalid
|
||||||
CHANNEL_PARICIPANT_MISSING The current user is not in the channel
|
CHANNEL_PARICIPANT_MISSING The current user is not in the channel
|
||||||
CHANNEL_PRIVATE The channel/supergroup is not accessible
|
CHANNEL_PRIVATE The channel/supergroup is not accessible
|
||||||
CHANNEL_TOO_BIG The channel too big
|
CHANNEL_TOO_BIG The channel too big
|
||||||
CHANNEL_TOO_LARGE The channel is too large
|
CHANNEL_TOO_LARGE "Channel is too large to be deleted; this error is issued when trying to delete channels with more than 1000 members (subject to change)."
|
||||||
|
CHARGE_ALREADY_REFUNDED The charge id was already used for a refund.
|
||||||
|
CHARGE_NOT_FOUND The charge id was not found.
|
||||||
|
CHATLIST_EXCLUDE_INVALID The specified `exclude_peers` are invalid.
|
||||||
CHAT_ABOUT_NOT_MODIFIED The chat about text was not modified because you tried to edit it using the same content
|
CHAT_ABOUT_NOT_MODIFIED The chat about text was not modified because you tried to edit it using the same content
|
||||||
CHAT_ABOUT_TOO_LONG The chat about text is too long
|
CHAT_ABOUT_TOO_LONG The chat about text is too long
|
||||||
CHAT_ADMIN_REQUIRED The method requires chat admin privileges
|
CHAT_ADMIN_REQUIRED The method requires chat admin privileges
|
||||||
|
|
@ -93,6 +103,7 @@ CONNECTION_SYSTEM_EMPTY The connection to the system is empty
|
||||||
CONNECTION_SYSTEM_LANG_CODE_EMPTY The system language code is empty
|
CONNECTION_SYSTEM_LANG_CODE_EMPTY The system language code is empty
|
||||||
CONTACT_ADD_MISSING Contact to add is missing
|
CONTACT_ADD_MISSING Contact to add is missing
|
||||||
CONTACT_ID_INVALID The provided contact id is invalid
|
CONTACT_ID_INVALID The provided contact id is invalid
|
||||||
|
CONTACT_MISSING The specified user is not a contact.
|
||||||
CONTACT_NAME_EMPTY The provided contact name is empty
|
CONTACT_NAME_EMPTY The provided contact name is empty
|
||||||
CONTACT_REQ_MISSING Missing contact request
|
CONTACT_REQ_MISSING Missing contact request
|
||||||
CREATE_CALL_FAILED An error occurred while creating the call
|
CREATE_CALL_FAILED An error occurred while creating the call
|
||||||
|
|
@ -107,10 +118,12 @@ DOCUMENT_INVALID The document is invalid
|
||||||
EMAIL_HASH_EXPIRED The email hash expired and cannot be used to verify it
|
EMAIL_HASH_EXPIRED The email hash expired and cannot be used to verify it
|
||||||
EMAIL_INVALID The email provided is invalid
|
EMAIL_INVALID The email provided is invalid
|
||||||
EMAIL_NOT_ALLOWED This email is not allowed
|
EMAIL_NOT_ALLOWED This email is not allowed
|
||||||
|
EMAIL_NOT_SETUP In order to change the login email with emailVerifyPurposeLoginChange, an existing login email must already be set using emailVerifyPurposeLoginSetup.
|
||||||
EMAIL_UNCONFIRMED Email unconfirmed
|
EMAIL_UNCONFIRMED Email unconfirmed
|
||||||
EMAIL_UNCONFIRMED_X The provided email isn't confirmed, {value} is the length of the verification code that was just sent to the email
|
EMAIL_UNCONFIRMED_X The provided email isn't confirmed, {value} is the length of the verification code that was just sent to the email
|
||||||
EMAIL_VERIFY_EXPIRED The verification email has expired
|
EMAIL_VERIFY_EXPIRED The verification email has expired
|
||||||
EMOJI_INVALID The specified theme emoji is valid
|
EMOJI_INVALID The specified theme emoji is valid
|
||||||
|
EMOJI_MARKUP_INVALID The specified `video_emoji_markup` was invalid.
|
||||||
EMOJI_NOT_MODIFIED The theme wasn't changed
|
EMOJI_NOT_MODIFIED The theme wasn't changed
|
||||||
EMOTICON_EMPTY The emoticon parameter is empty
|
EMOTICON_EMPTY The emoticon parameter is empty
|
||||||
EMOTICON_INVALID The emoticon parameter is invalid
|
EMOTICON_INVALID The emoticon parameter is invalid
|
||||||
|
|
@ -127,6 +140,9 @@ ERROR_TEXT_EMPTY The provided error message is empty
|
||||||
EXPIRE_DATE_INVALID The expiration date is invalid
|
EXPIRE_DATE_INVALID The expiration date is invalid
|
||||||
EXPIRE_FORBIDDEN Expire forbidden
|
EXPIRE_FORBIDDEN Expire forbidden
|
||||||
EXPORT_CARD_INVALID The provided card is invalid
|
EXPORT_CARD_INVALID The provided card is invalid
|
||||||
|
EXTENDED_MEDIA_AMOUNT_INVALID The maximum amount of `star_count` should be less than the `stars_paid_post_amount_max`
|
||||||
|
EXTENDED_MEDIA_PEER_INVALID The specified chat type is invalid.
|
||||||
|
EXTENDED_MEDIA_TYPE_INVALID The specified extended media type is unsupported.
|
||||||
EXTERNAL_URL_INVALID The external media URL is invalid
|
EXTERNAL_URL_INVALID The external media URL is invalid
|
||||||
FIELD_NAME_EMPTY The field with the name FIELD_NAME is missing
|
FIELD_NAME_EMPTY The field with the name FIELD_NAME is missing
|
||||||
FIELD_NAME_INVALID The field with the name FIELD_NAME is invalid
|
FIELD_NAME_INVALID The field with the name FIELD_NAME is invalid
|
||||||
|
|
@ -154,13 +170,17 @@ FILTER_TITLE_EMPTY The title field of the filter is empty
|
||||||
FIRSTNAME_INVALID The first name is invalid
|
FIRSTNAME_INVALID The first name is invalid
|
||||||
FOLDER_ID_EMPTY The folder you tried to delete was already empty
|
FOLDER_ID_EMPTY The folder you tried to delete was already empty
|
||||||
FOLDER_ID_INVALID The folder id is invalid
|
FOLDER_ID_INVALID The folder id is invalid
|
||||||
|
FORM_ID_EXPIRED The specified id has expired.
|
||||||
|
FORUM_ENABLED You can't execute the specified action because the group is a [forum](https://core.telegram.org/api/forum), disable forum functionality to continue.
|
||||||
FRESH_CHANGE_ADMINS_FORBIDDEN You can't change administrator settings in this chat because your session was logged-in recently
|
FRESH_CHANGE_ADMINS_FORBIDDEN You can't change administrator settings in this chat because your session was logged-in recently
|
||||||
FROM_MESSAGE_BOT_DISABLED Bots can't use fromMessage min constructors
|
FROM_MESSAGE_BOT_DISABLED Bots can't use fromMessage min constructors
|
||||||
FROM_PEER_INVALID The from peer value is invalid
|
FROM_PEER_INVALID The from peer value is invalid
|
||||||
GAME_BOT_INVALID You cannot send that game with the current bot
|
GAME_BOT_INVALID You cannot send that game with the current bot
|
||||||
|
GENERAL_MODIFY_ICON_FORBIDDEN You can't modify the icon of the General topic.
|
||||||
GEO_POINT_INVALID Invalid geo point provided
|
GEO_POINT_INVALID Invalid geo point provided
|
||||||
GIF_CONTENT_TYPE_INVALID GIF content-type invalid
|
GIF_CONTENT_TYPE_INVALID GIF content-type invalid
|
||||||
GIF_ID_INVALID The provided gif/animation id is invalid
|
GIF_ID_INVALID The provided gif/animation id is invalid
|
||||||
|
GIFT_SLUG_INVALID The specified slug is invalid.
|
||||||
GIFT_SLUG_EXPIRED The gift slug is expired
|
GIFT_SLUG_EXPIRED The gift slug is expired
|
||||||
GRAPH_EXPIRED_RELOAD This graph has expired, please obtain a new graph token
|
GRAPH_EXPIRED_RELOAD This graph has expired, please obtain a new graph token
|
||||||
GRAPH_INVALID_RELOAD Invalid graph token provided, please reload the stats and provide the updated token
|
GRAPH_INVALID_RELOAD Invalid graph token provided, please reload the stats and provide the updated token
|
||||||
|
|
@ -187,7 +207,9 @@ INPUT_LAYER_INVALID The provided layer is invalid
|
||||||
INPUT_METHOD_INVALID The method invoked is invalid in the current schema
|
INPUT_METHOD_INVALID The method invoked is invalid in the current schema
|
||||||
INPUT_REQUEST_TOO_LONG The input request is too long
|
INPUT_REQUEST_TOO_LONG The input request is too long
|
||||||
INPUT_TEXT_EMPTY The specified text is empty
|
INPUT_TEXT_EMPTY The specified text is empty
|
||||||
|
INPUT_TEXT_TOO_LONG The specified text is too long.
|
||||||
INPUT_USER_DEACTIVATED The target user has been deleted/deactivated
|
INPUT_USER_DEACTIVATED The target user has been deleted/deactivated
|
||||||
|
INVITES_TOO_MUCH The maximum number of per-folder invites specified by the `chatlist_invites_limit_default`/`chatlist_invites_limit_premium` was reached.
|
||||||
INVITE_FORBIDDEN_WITH_JOINAS If the user has anonymously joined a group call as a channel, they can't invite other users to the group call because that would cause deanonymization, because the invite would be sent using the original user ID, not the anonymized channel ID
|
INVITE_FORBIDDEN_WITH_JOINAS If the user has anonymously joined a group call as a channel, they can't invite other users to the group call because that would cause deanonymization, because the invite would be sent using the original user ID, not the anonymized channel ID
|
||||||
INVITE_HASH_EMPTY The invite hash is empty
|
INVITE_HASH_EMPTY The invite hash is empty
|
||||||
INVITE_HASH_EXPIRED The chat invite link is no longer valid
|
INVITE_HASH_EXPIRED The chat invite link is no longer valid
|
||||||
|
|
@ -238,6 +260,7 @@ MULTI_MEDIA_TOO_LONG The album/media group contains too many items
|
||||||
NEW_SALT_INVALID The new salt is invalid
|
NEW_SALT_INVALID The new salt is invalid
|
||||||
NEW_SETTINGS_EMPTY No password is set on the current account, and no new password was specified in `new_settings`
|
NEW_SETTINGS_EMPTY No password is set on the current account, and no new password was specified in `new_settings`
|
||||||
NEW_SETTINGS_INVALID The new settings are invalid
|
NEW_SETTINGS_INVALID The new settings are invalid
|
||||||
|
NOGENERAL_HIDE_FORBIDDEN The hidden parameter is only valid for the General topic message_thread_id=1
|
||||||
NEXT_OFFSET_INVALID The next offset value is invalid
|
NEXT_OFFSET_INVALID The next offset value is invalid
|
||||||
OFFSET_INVALID The offset parameter is invalid
|
OFFSET_INVALID The offset parameter is invalid
|
||||||
OFFSET_PEER_ID_INVALID The provided offset peer is invalid
|
OFFSET_PEER_ID_INVALID The provided offset peer is invalid
|
||||||
|
|
@ -289,6 +312,7 @@ PHOTO_SAVE_FILE_INVALID The photo you tried to send cannot be saved by Telegram
|
||||||
PHOTO_THUMB_URL_EMPTY The photo thumb URL is empty
|
PHOTO_THUMB_URL_EMPTY The photo thumb URL is empty
|
||||||
PHOTO_THUMB_URL_INVALID The photo thumb URL is invalid
|
PHOTO_THUMB_URL_INVALID The photo thumb URL is invalid
|
||||||
PINNED_DIALOGS_TOO_MUCH Too many pinned dialogs
|
PINNED_DIALOGS_TOO_MUCH Too many pinned dialogs
|
||||||
|
PINNED_TOPIC_NOT_MODIFIED The pinned topic was not modified.
|
||||||
PIN_RESTRICTED You can't pin messages in private chats with other people
|
PIN_RESTRICTED You can't pin messages in private chats with other people
|
||||||
POLL_ANSWERS_INVALID The poll answers are invalid
|
POLL_ANSWERS_INVALID The poll answers are invalid
|
||||||
POLL_ANSWER_INVALID One of the poll answers is not acceptable
|
POLL_ANSWER_INVALID One of the poll answers is not acceptable
|
||||||
|
|
@ -298,6 +322,8 @@ POLL_QUESTION_INVALID The poll question is invalid
|
||||||
POLL_UNSUPPORTED This layer does not support polls in the invoked method
|
POLL_UNSUPPORTED This layer does not support polls in the invoked method
|
||||||
POLL_VOTE_REQUIRED Cast a vote in the poll before calling this method
|
POLL_VOTE_REQUIRED Cast a vote in the poll before calling this method
|
||||||
PREMIUM_ACCOUNT_REQUIRED The method requires a premium user account
|
PREMIUM_ACCOUNT_REQUIRED The method requires a premium user account
|
||||||
|
PREMIUM_GIFTCODE_WAS_REFUNDED This gift code can't be redeemed because the giveaway organizer requested a refund
|
||||||
|
PRICING_CHAT_INVALID This chat chat doesn't support subscription link.
|
||||||
PRIVACY_KEY_INVALID The privacy key is invalid
|
PRIVACY_KEY_INVALID The privacy key is invalid
|
||||||
PRIVACY_TOO_LONG Your privacy exception list has exceeded the maximum capacity
|
PRIVACY_TOO_LONG Your privacy exception list has exceeded the maximum capacity
|
||||||
PRIVACY_VALUE_INVALID The privacy value is invalid
|
PRIVACY_VALUE_INVALID The privacy value is invalid
|
||||||
|
|
@ -354,6 +380,9 @@ SLOWMODE_MULTI_MSGS_DISABLED Slowmode is enabled, you cannot forward multiple me
|
||||||
SMS_CODE_CREATE_FAILED An error occurred while creating the SMS code
|
SMS_CODE_CREATE_FAILED An error occurred while creating the SMS code
|
||||||
SRP_ID_INVALID Invalid SRP ID provided
|
SRP_ID_INVALID Invalid SRP ID provided
|
||||||
SRP_PASSWORD_CHANGED The password has changed
|
SRP_PASSWORD_CHANGED The password has changed
|
||||||
|
STARGIFT_ALREADY_CONVERTED The provided star gift already converted to stars
|
||||||
|
STARGIFT_ALREADY_UPGRADED This star gift was already upgraded before
|
||||||
|
STARGIFT_USAGE_LIMITED The star gift usage is limited
|
||||||
START_PARAM_EMPTY The start parameter is empty
|
START_PARAM_EMPTY The start parameter is empty
|
||||||
START_PARAM_INVALID The start parameter is invalid
|
START_PARAM_INVALID The start parameter is invalid
|
||||||
START_PARAM_TOO_LONG The start parameter is too long
|
START_PARAM_TOO_LONG The start parameter is too long
|
||||||
|
|
@ -377,8 +406,15 @@ STICKER_THUMB_PNG_NOPNG A png sticker thumbnail file was expected, but something
|
||||||
STICKER_VIDEO_BIG The specified video sticker is too big
|
STICKER_VIDEO_BIG The specified video sticker is too big
|
||||||
STICKER_VIDEO_NODOC You must send the video sticker as a document
|
STICKER_VIDEO_NODOC You must send the video sticker as a document
|
||||||
STICKER_VIDEO_NOWEBM A webm video file was expected, but something else was provided
|
STICKER_VIDEO_NOWEBM A webm video file was expected, but something else was provided
|
||||||
|
STORY_ID_EMPTY You specified no story IDs.
|
||||||
|
STORY_ID_INVALID The specified story ID is invalid.
|
||||||
|
STORY_NOT_MODIFIED The new story information you passed is equal to the previous story information, thus it wasn't modified.
|
||||||
|
STORY_PERIOD_INVALID The specified story period is invalid for this account.
|
||||||
STORIES_TOO_MUCH Too many stories in the current account
|
STORIES_TOO_MUCH Too many stories in the current account
|
||||||
|
STORY_SEND_FLOOD_WEEKLY_X You've hit the weekly story limit, wait for the specified number of seconds before posting a new story.
|
||||||
|
STORY_SEND_FLOOD_MONTHLY_X You've hit the monthly story limit, wait for the specified number of seconds before posting a new story.
|
||||||
STORY_PERIOD_INVALID The story period is invalid
|
STORY_PERIOD_INVALID The story period is invalid
|
||||||
|
SUBSCRIPTION_PERIOD_INVALID The subscription period is invalid.
|
||||||
SWITCH_PM_TEXT_EMPTY The switch_pm.text field was empty
|
SWITCH_PM_TEXT_EMPTY The switch_pm.text field was empty
|
||||||
TAKEOUT_INVALID The takeout id is invalid
|
TAKEOUT_INVALID The takeout id is invalid
|
||||||
TAKEOUT_REQUIRED The method must be invoked inside a takeout session
|
TAKEOUT_REQUIRED The method must be invoked inside a takeout session
|
||||||
|
|
@ -395,8 +431,11 @@ TMP_PASSWORD_INVALID The temporary password is invalid
|
||||||
TOKEN_INVALID The provided token is invalid
|
TOKEN_INVALID The provided token is invalid
|
||||||
TOPIC_CLOSED The topic was closed
|
TOPIC_CLOSED The topic was closed
|
||||||
TOPIC_DELETED The topic was deleted
|
TOPIC_DELETED The topic was deleted
|
||||||
|
TOPIC_CLOSE_SEPARATELY The close flag cannot be provided together with any of the other flags.
|
||||||
|
TOPIC_HIDE_SEPARATELY The hide flag cannot be provided together with any of the other flags.
|
||||||
TOPIC_ID_INVALID The provided topic ID is invalid
|
TOPIC_ID_INVALID The provided topic ID is invalid
|
||||||
TOPIC_NOT_MODIFIED The topic was not modified
|
TOPIC_NOT_MODIFIED The topic was not modified
|
||||||
|
TOPIC_TITLE_EMPTY The specified topic title is empty.
|
||||||
TO_LANG_INVALID The specified destination language is invalid
|
TO_LANG_INVALID The specified destination language is invalid
|
||||||
TRANSCRIPTION_FAILED Telegram is having internal problems. Please try again later to transcribe the audio.
|
TRANSCRIPTION_FAILED Telegram is having internal problems. Please try again later to transcribe the audio.
|
||||||
TTL_DAYS_INVALID The provided TTL days is invalid
|
TTL_DAYS_INVALID The provided TTL days is invalid
|
||||||
|
|
@ -437,11 +476,12 @@ USER_VOLUME_INVALID The specified user volume is invalid
|
||||||
VIDEO_CONTENT_TYPE_INVALID The video content type is invalid (i.e.: not streamable)
|
VIDEO_CONTENT_TYPE_INVALID The video content type is invalid (i.e.: not streamable)
|
||||||
VIDEO_FILE_INVALID The video file is invalid
|
VIDEO_FILE_INVALID The video file is invalid
|
||||||
VIDEO_TITLE_EMPTY The specified video title is empty
|
VIDEO_TITLE_EMPTY The specified video title is empty
|
||||||
VOICE_MESSAGES_FORBIDDEN Voice messages are restricted
|
VOICE_MESSAGES_FORBIDDEN This user's privacy settings forbid you from sending voice messages
|
||||||
VOLUME_LOC_NOT_FOUND The volume location can't be found
|
VOLUME_LOC_NOT_FOUND The volume location can't be found
|
||||||
WALLPAPER_FILE_INVALID The provided file cannot be used as a wallpaper
|
WALLPAPER_FILE_INVALID The provided file cannot be used as a wallpaper
|
||||||
WALLPAPER_INVALID The input wallpaper was not valid
|
WALLPAPER_INVALID The input wallpaper was not valid
|
||||||
WALLPAPER_MIME_INVALID The wallpaper mime type is invalid
|
WALLPAPER_MIME_INVALID The wallpaper mime type is invalid
|
||||||
|
WALLPAPER_NOT_FOUND The specified wallpaper could not be found.
|
||||||
WC_CONVERT_URL_INVALID WC convert URL invalid
|
WC_CONVERT_URL_INVALID WC convert URL invalid
|
||||||
WEBDOCUMENT_INVALID The web document is invalid
|
WEBDOCUMENT_INVALID The web document is invalid
|
||||||
WEBDOCUMENT_MIME_INVALID The web document mime type is invalid
|
WEBDOCUMENT_MIME_INVALID The web document mime type is invalid
|
||||||
|
|
@ -460,5 +500,9 @@ STORIES_NEVER_CREATED You have never created any stories
|
||||||
MEDIA_FILE_INVALID The provided media file is invalid
|
MEDIA_FILE_INVALID The provided media file is invalid
|
||||||
CHANNEL_FORUM_MISSING The channel forum is missing
|
CHANNEL_FORUM_MISSING The channel forum is missing
|
||||||
TTL_PERIOD_INVALID The provided TTL period is invalid
|
TTL_PERIOD_INVALID The provided TTL period is invalid
|
||||||
BOOSTS_REQUIRED Channel required more boost to upload a story
|
BOOSTS_REQUIRED The specified channel must first be boosted by its users in order to perform this action
|
||||||
BOOSTS_EMPTY Boosts empty
|
BOOSTS_EMPTY You can't modify the icon of the General topic.
|
||||||
|
BOOST_NOT_MODIFIED You're already boosting the specified channel.
|
||||||
|
PAYMENT_REQUIRED The payment is required
|
||||||
|
BOOST_PEER_INVALID The specified `boost_peer` is invalid.
|
||||||
|
STARS_AMOUNT_INVALID The specified `amount` is invalid.
|
||||||
|
|
|
@ -44,3 +44,4 @@ GROUPCALL_ALREADY_STARTED The groupcall has already started, you can join direct
|
||||||
GROUPCALL_FORBIDDEN The group call has already ended
|
GROUPCALL_FORBIDDEN The group call has already ended
|
||||||
LIVE_DISABLED Story is disabled server-side
|
LIVE_DISABLED Story is disabled server-side
|
||||||
CHAT_GUEST_SEND_FORBIDDEN You need to join the discussion group before commenting
|
CHAT_GUEST_SEND_FORBIDDEN You need to join the discussion group before commenting
|
||||||
|
ALLOW_PAYMENT_REQUIRED_X Payment of {value} stars is required to perform this action
|
||||||
|
|
|
@ -14,9 +14,10 @@ PHONE_PASSWORD_FLOOD You have tried to log-in too many times
|
||||||
PREMIUM_CURRENTLY_UNAVAILABLE Premium currently unavailable
|
PREMIUM_CURRENTLY_UNAVAILABLE Premium currently unavailable
|
||||||
PREVIOUS_CHAT_IMPORT_ACTIVE_WAIT_XMIN Similar to a flood wait, must wait {value} minutes
|
PREVIOUS_CHAT_IMPORT_ACTIVE_WAIT_XMIN Similar to a flood wait, must wait {value} minutes
|
||||||
SEND_CODE_UNAVAILABLE Returned when all available options for this type of number were already used (e.g. flash-call, then SMS, then this error might be returned to trigger a second resend)
|
SEND_CODE_UNAVAILABLE Returned when all available options for this type of number were already used (e.g. flash-call, then SMS, then this error might be returned to trigger a second resend)
|
||||||
|
PREMIUM_GIFTCODE_WAS_REFUNDED This gift code can't be redeemed because the giveaway organizer requested a refund
|
||||||
STICKERSET_INVALID The sticker set is invalid
|
STICKERSET_INVALID The sticker set is invalid
|
||||||
STICKERSET_OWNER_ANONYMOUS This sticker set can't be used as the group's sticker set because it was created by one of its anonymous admins
|
STICKERSET_OWNER_ANONYMOUS This sticker set can't be used as the group's sticker set because it was created by one of its anonymous admins
|
||||||
UPDATE_APP_TO_LOGIN Update app to login
|
UPDATE_APP_TO_LOGIN Update app to login
|
||||||
USERPIC_PRIVACY_REQUIRED You need to disable privacy settings for your profile picture in order to make your geolocation public
|
USERPIC_PRIVACY_REQUIRED You need to disable privacy settings for your profile picture in order to make your geolocation public
|
||||||
USERPIC_UPLOAD_REQUIRED You must have a profile picture to publish your geolocation
|
USERPIC_UPLOAD_REQUIRED You must have a profile picture to publish your geolocation
|
||||||
USER_RESTRICTED You are limited/restricted. You can't perform this action
|
USER_RESTRICTED You are limited/restricted. You can't perform this action
|
||||||
|
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<strong>Usable by</strong>
|
<blockquote>
|
||||||
<span class="usable-by"><i class="fa-solid fa-xmark" style="color: var(--color-red)"></i> Users</span>
|
<strong>Usable by</strong>
|
||||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Bots</span>
|
<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>
|
||||||
|
</blockquote>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<strong>Usable by</strong>
|
<blockquote>
|
||||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Users</span>
|
<strong>Usable by</strong>
|
||||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Bots</span>
|
<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>
|
||||||
|
</blockquote>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<strong>Usable by</strong>
|
<blockquote>
|
||||||
<span class="usable-by"><i class="fa-solid fa-check" style="color: var(--color-green)"></i> Users</span>
|
<strong>Usable by</strong>
|
||||||
<span class="usable-by"><i class="fa-solid fa-xmark" style="color: var(--color-red)"></i> Bots</span>
|
<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>
|
||||||
|
</blockquote>
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ Index
|
||||||
- :meth:`~Client.on_edited_message`
|
- :meth:`~Client.on_edited_message`
|
||||||
- :meth:`~Client.on_edited_bot_business_message`
|
- :meth:`~Client.on_edited_bot_business_message`
|
||||||
- :meth:`~Client.on_callback_query`
|
- :meth:`~Client.on_callback_query`
|
||||||
|
- :meth:`~Client.on_shipping_query`
|
||||||
|
- :meth:`~Client.on_pre_checkout_query`
|
||||||
- :meth:`~Client.on_message_reaction_updated`
|
- :meth:`~Client.on_message_reaction_updated`
|
||||||
- :meth:`~Client.on_message_reaction_count_updated`
|
- :meth:`~Client.on_message_reaction_count_updated`
|
||||||
- :meth:`~Client.on_inline_query`
|
- :meth:`~Client.on_inline_query`
|
||||||
|
|
@ -48,12 +50,13 @@ Index
|
||||||
- :meth:`~Client.on_chat_member_updated`
|
- :meth:`~Client.on_chat_member_updated`
|
||||||
- :meth:`~Client.on_chat_join_request`
|
- :meth:`~Client.on_chat_join_request`
|
||||||
- :meth:`~Client.on_deleted_messages`
|
- :meth:`~Client.on_deleted_messages`
|
||||||
- :meth:`~Client.on_edited_bot_business_message`
|
- :meth:`~Client.on_deleted_bot_business_message`
|
||||||
- :meth:`~Client.on_user_status`
|
- :meth:`~Client.on_user_status`
|
||||||
- :meth:`~Client.on_story`
|
- :meth:`~Client.on_story`
|
||||||
- :meth:`~Client.on_poll`
|
- :meth:`~Client.on_poll`
|
||||||
- :meth:`~Client.on_disconnect`
|
- :meth:`~Client.on_disconnect`
|
||||||
- :meth:`~Client.on_raw_update`
|
- :meth:`~Client.on_raw_update`
|
||||||
|
- :meth:`~Client.on_error`
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
@ -67,6 +70,8 @@ Details
|
||||||
.. autodecorator:: pyrogram.Client.on_edited_message()
|
.. autodecorator:: pyrogram.Client.on_edited_message()
|
||||||
.. autodecorator:: pyrogram.Client.on_edited_bot_business_message()
|
.. autodecorator:: pyrogram.Client.on_edited_bot_business_message()
|
||||||
.. autodecorator:: pyrogram.Client.on_callback_query()
|
.. autodecorator:: pyrogram.Client.on_callback_query()
|
||||||
|
.. autodecorator:: pyrogram.Client.on_shipping_query()
|
||||||
|
.. autodecorator:: pyrogram.Client.on_pre_checkout_query()
|
||||||
.. autodecorator:: pyrogram.Client.on_message_reaction_updated()
|
.. autodecorator:: pyrogram.Client.on_message_reaction_updated()
|
||||||
.. autodecorator:: pyrogram.Client.on_message_reaction_count_updated()
|
.. autodecorator:: pyrogram.Client.on_message_reaction_count_updated()
|
||||||
.. autodecorator:: pyrogram.Client.on_inline_query()
|
.. autodecorator:: pyrogram.Client.on_inline_query()
|
||||||
|
|
@ -74,9 +79,10 @@ Details
|
||||||
.. autodecorator:: pyrogram.Client.on_chat_member_updated()
|
.. autodecorator:: pyrogram.Client.on_chat_member_updated()
|
||||||
.. autodecorator:: pyrogram.Client.on_chat_join_request()
|
.. autodecorator:: pyrogram.Client.on_chat_join_request()
|
||||||
.. autodecorator:: pyrogram.Client.on_deleted_messages()
|
.. autodecorator:: pyrogram.Client.on_deleted_messages()
|
||||||
.. autodecorator:: pyrogram.Client.on_edited_bot_business_message()
|
.. autodecorator:: pyrogram.Client.on_deleted_bot_business_message()
|
||||||
.. autodecorator:: pyrogram.Client.on_user_status()
|
.. autodecorator:: pyrogram.Client.on_user_status()
|
||||||
.. autodecorator:: pyrogram.Client.on_story()
|
.. autodecorator:: pyrogram.Client.on_story()
|
||||||
.. autodecorator:: pyrogram.Client.on_poll()
|
.. autodecorator:: pyrogram.Client.on_poll()
|
||||||
.. autodecorator:: pyrogram.Client.on_disconnect()
|
.. autodecorator:: pyrogram.Client.on_disconnect()
|
||||||
.. autodecorator:: pyrogram.Client.on_raw_update()
|
.. autodecorator:: pyrogram.Client.on_raw_update()
|
||||||
|
.. autodecorator:: pyrogram.Client.on_error()
|
||||||
|
|
|
||||||
8
docs/source/api/enums/BusinessSchedule.rst
Normal file
8
docs/source/api/enums/BusinessSchedule.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
BusinessSchedule
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.BusinessSchedule()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/ChatJoinType.rst
Normal file
8
docs/source/api/enums/ChatJoinType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
ChatJoinType
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.ChatJoinType()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/ClientPlatform.rst
Normal file
8
docs/source/api/enums/ClientPlatform.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
ClientPlatform
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.ClientPlatform()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/FolderColor.rst
Normal file
8
docs/source/api/enums/FolderColor.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
FolderColor
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.FolderColor()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/GiftAttributeType.rst
Normal file
8
docs/source/api/enums/GiftAttributeType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
GiftAttributeType
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.GiftAttributeType()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/GiftForResaleOrder.rst
Normal file
8
docs/source/api/enums/GiftForResaleOrder.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
GiftAttributeType
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.GiftForResaleOrder()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/MessageOriginType.rst
Normal file
8
docs/source/api/enums/MessageOriginType.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
MessageOriginType
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.MessageOriginType()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/ProfileColor.rst
Normal file
8
docs/source/api/enums/ProfileColor.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
ProfileColor
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.ProfileColor()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
8
docs/source/api/enums/ReplyColor.rst
Normal file
8
docs/source/api/enums/ReplyColor.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
ReplyColor
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. autoclass:: pyrogram.enums.ReplyColor()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ./cleanup.html
|
||||||
|
|
@ -16,9 +16,13 @@ to apply only a valid value among the expected ones.
|
||||||
BusinessSchedule
|
BusinessSchedule
|
||||||
ChatAction
|
ChatAction
|
||||||
ChatEventAction
|
ChatEventAction
|
||||||
|
ChatJoinType
|
||||||
ChatMemberStatus
|
ChatMemberStatus
|
||||||
ChatMembersFilter
|
ChatMembersFilter
|
||||||
ChatType
|
ChatType
|
||||||
|
ClientPlatform
|
||||||
|
FolderColor
|
||||||
|
GiftAttributeType
|
||||||
ListenerTypes
|
ListenerTypes
|
||||||
MessageEntityType
|
MessageEntityType
|
||||||
MessageMediaType
|
MessageMediaType
|
||||||
|
|
@ -26,21 +30,28 @@ to apply only a valid value among the expected ones.
|
||||||
MessagesFilter
|
MessagesFilter
|
||||||
ParseMode
|
ParseMode
|
||||||
PollType
|
PollType
|
||||||
|
ProfileColor
|
||||||
SentCodeType
|
SentCodeType
|
||||||
NextCodeType
|
NextCodeType
|
||||||
UserStatus
|
UserStatus
|
||||||
ReactionType
|
ReactionType
|
||||||
|
ReplyColor
|
||||||
StoriesPrivacyRules
|
StoriesPrivacyRules
|
||||||
StoryPrivacy
|
StoryPrivacy
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:hidden:
|
:hidden:
|
||||||
|
|
||||||
|
BusinessSchedule
|
||||||
ChatAction
|
ChatAction
|
||||||
ChatEventAction
|
ChatEventAction
|
||||||
|
ChatJoinType
|
||||||
ChatMemberStatus
|
ChatMemberStatus
|
||||||
ChatMembersFilter
|
ChatMembersFilter
|
||||||
ChatType
|
ChatType
|
||||||
|
ClientPlatform
|
||||||
|
FolderColor
|
||||||
|
GiftAttributeType
|
||||||
ListenerTypes
|
ListenerTypes
|
||||||
MessageEntityType
|
MessageEntityType
|
||||||
MessageMediaType
|
MessageMediaType
|
||||||
|
|
@ -48,9 +59,11 @@ to apply only a valid value among the expected ones.
|
||||||
MessagesFilter
|
MessagesFilter
|
||||||
ParseMode
|
ParseMode
|
||||||
PollType
|
PollType
|
||||||
|
ProfileColor
|
||||||
SentCodeType
|
SentCodeType
|
||||||
NextCodeType
|
NextCodeType
|
||||||
UserStatus
|
UserStatus
|
||||||
ReactionType
|
ReactionType
|
||||||
|
ReplyColor
|
||||||
StoriesPrivacyRules
|
StoriesPrivacyRules
|
||||||
StoryPrivacy
|
StoryPrivacy
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ Index
|
||||||
- :class:`DeletedMessagesHandler`
|
- :class:`DeletedMessagesHandler`
|
||||||
- :class:`DeletedBotBusinessMessagesHandler`
|
- :class:`DeletedBotBusinessMessagesHandler`
|
||||||
- :class:`CallbackQueryHandler`
|
- :class:`CallbackQueryHandler`
|
||||||
|
- :class:`PreCheckoutQueryHandler`
|
||||||
|
- :class:`ShippingQueryHandler`
|
||||||
- :class:`MessageReactionUpdatedHandler`
|
- :class:`MessageReactionUpdatedHandler`
|
||||||
- :class:`MessageReactionCountUpdatedHandler`
|
- :class:`MessageReactionCountUpdatedHandler`
|
||||||
- :class:`InlineQueryHandler`
|
- :class:`InlineQueryHandler`
|
||||||
|
|
@ -53,6 +55,7 @@ Index
|
||||||
- :class:`PollHandler`
|
- :class:`PollHandler`
|
||||||
- :class:`DisconnectHandler`
|
- :class:`DisconnectHandler`
|
||||||
- :class:`RawUpdateHandler`
|
- :class:`RawUpdateHandler`
|
||||||
|
- :class:`ErrorHandler`
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
@ -68,6 +71,8 @@ Details
|
||||||
.. autoclass:: DeletedMessagesHandler()
|
.. autoclass:: DeletedMessagesHandler()
|
||||||
.. autoclass:: DeletedBotBusinessMessagesHandler()
|
.. autoclass:: DeletedBotBusinessMessagesHandler()
|
||||||
.. autoclass:: CallbackQueryHandler()
|
.. autoclass:: CallbackQueryHandler()
|
||||||
|
.. autoclass:: ShippingQueryHandler()
|
||||||
|
.. autoclass:: PreCheckoutQueryHandler()
|
||||||
.. autoclass:: MessageReactionUpdatedHandler()
|
.. autoclass:: MessageReactionUpdatedHandler()
|
||||||
.. autoclass:: MessageReactionCountUpdatedHandler()
|
.. autoclass:: MessageReactionCountUpdatedHandler()
|
||||||
.. autoclass:: InlineQueryHandler()
|
.. autoclass:: InlineQueryHandler()
|
||||||
|
|
@ -78,3 +83,4 @@ Details
|
||||||
.. autoclass:: PollHandler()
|
.. autoclass:: PollHandler()
|
||||||
.. autoclass:: DisconnectHandler()
|
.. autoclass:: DisconnectHandler()
|
||||||
.. autoclass:: RawUpdateHandler()
|
.. autoclass:: RawUpdateHandler()
|
||||||
|
.. autoclass:: ErrorHandler()
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ from pygments.styles.friendly import FriendlyStyle
|
||||||
FriendlyStyle.background_color = "#f3f2f1"
|
FriendlyStyle.background_color = "#f3f2f1"
|
||||||
|
|
||||||
project = "Pyrofork"
|
project = "Pyrofork"
|
||||||
copyright = f"2022-present, Mayuri-Chan"
|
copyright = "2022-present, Mayuri-Chan"
|
||||||
author = "Mayuri-Chan"
|
author = "Mayuri-Chan"
|
||||||
|
|
||||||
version = ".".join(__version__.split(".")[:-1])
|
version = ".".join(__version__.split(".")[:-1])
|
||||||
|
|
@ -73,7 +73,7 @@ html_theme_options = {
|
||||||
"repo": "fontawesome/brands/github",
|
"repo": "fontawesome/brands/github",
|
||||||
"edit": "material/file-edit-outline",
|
"edit": "material/file-edit-outline",
|
||||||
},
|
},
|
||||||
"site_url": "https://pyrofork.mayuri.my.id/",
|
"site_url": "https://pyrofork.wulan17.dev/",
|
||||||
"repo_url": "https://github.com/Mayuri-Chan/pyrofork/",
|
"repo_url": "https://github.com/Mayuri-Chan/pyrofork/",
|
||||||
"repo_name": "pyrofork",
|
"repo_name": "pyrofork",
|
||||||
"globaltoc_collapse": True,
|
"globaltoc_collapse": True,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ like send_audio(), send_document(), send_location(), etc...
|
||||||
),
|
),
|
||||||
InlineKeyboardButton( # Opens a web URL
|
InlineKeyboardButton( # Opens a web URL
|
||||||
"URL",
|
"URL",
|
||||||
url="https://pyrofork.mayuri.my.id"
|
url="https://pyrofork.wulan17.dev"
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[ # Second row
|
[ # Second row
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,13 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
"Here's how to install **Pyrofork**"
|
"Here's how to install **Pyrofork**"
|
||||||
),
|
),
|
||||||
url="https://pyrofork.mayuri.my.id/intro/install",
|
url="https://pyrofork.wulan17.dev/intro/install",
|
||||||
description="How to install Pyrofork",
|
description="How to install Pyrofork",
|
||||||
reply_markup=InlineKeyboardMarkup(
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[InlineKeyboardButton(
|
[InlineKeyboardButton(
|
||||||
"Open website",
|
"Open website",
|
||||||
url="https://pyrofork.mayuri.my.id/intro/install"
|
url="https://pyrofork.wulan17.dev/intro/install"
|
||||||
)]
|
)]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
@ -40,13 +40,13 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
"Here's how to use **Pyrofork**"
|
"Here's how to use **Pyrofork**"
|
||||||
),
|
),
|
||||||
url="https://pyrofork.mayuri.my.id/start/invoking",
|
url="https://pyrofork.wulan17.dev/start/invoking",
|
||||||
description="How to use Pyrofork",
|
description="How to use Pyrofork",
|
||||||
reply_markup=InlineKeyboardMarkup(
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[InlineKeyboardButton(
|
[InlineKeyboardButton(
|
||||||
"Open website",
|
"Open website",
|
||||||
url="https://pyrofork.mayuri.my.id/start/invoking"
|
url="https://pyrofork.wulan17.dev/start/invoking"
|
||||||
)]
|
)]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ to make it only work for specific messages in a specific chat.
|
||||||
# Target chat. Can also be a list of multiple chat ids/usernames
|
# Target chat. Can also be a list of multiple chat ids/usernames
|
||||||
TARGET = -100123456789
|
TARGET = -100123456789
|
||||||
# Welcome message template
|
# Welcome message template
|
||||||
MESSAGE = "{} Welcome to [Pyrofork](https://pyrofork.mayuri.my.id/)'s group chat {}!"
|
MESSAGE = "{} Welcome to [Pyrofork](https://pyrofork.wulan17.dev/)'s group chat {}!"
|
||||||
|
|
||||||
app = Client("my_account")
|
app = Client("my_account")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,20 @@ Using async_pymongo (Recommended for python3.9+):
|
||||||
print(await app.get_me())
|
print(await app.get_me())
|
||||||
|
|
||||||
|
|
||||||
Using motor:
|
Using official mongodb driver:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from pymongo import AsyncMongoClient
|
||||||
|
from pyrogram import Client
|
||||||
|
|
||||||
|
conn = AsyncMongoClient("mongodb://...")
|
||||||
|
|
||||||
|
async with Client("my_account", mongodb=dict(connection=conn, remove_peers=False)) as app:
|
||||||
|
print(await app.get_me())
|
||||||
|
|
||||||
|
|
||||||
|
Using motor (Deprecated, but still works):
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,68 +37,16 @@ list of the basic styles currently supported by Pyrofork.
|
||||||
- spoiler
|
- spoiler
|
||||||
- `text URL <https://pyrogram.org>`_
|
- `text URL <https://pyrogram.org>`_
|
||||||
- `user text mention <tg://user?id=123456789>`_
|
- `user text mention <tg://user?id=123456789>`_
|
||||||
|
- :emoji:`🔥`
|
||||||
- ``inline fixed-width code``
|
- ``inline fixed-width code``
|
||||||
- .. code-block:: text
|
- .. code-block:: text
|
||||||
|
|
||||||
pre-formatted
|
pre-formatted
|
||||||
fixed-width
|
fixed-width
|
||||||
code block
|
code block
|
||||||
|
- > Quoted text
|
||||||
|
|
||||||
Markdown Style
|
- > Quoted text with collapse/expand button
|
||||||
--------------
|
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
> Quoted text
|
|
||||||
|
|
||||||
**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
|
HTML Style
|
||||||
----------
|
----------
|
||||||
|
|
@ -122,10 +70,10 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<a href="tg://user?id=123456789">inline mention</a>
|
<a href="tg://user?id=123456789">inline mention</a>
|
||||||
|
|
||||||
<code>inline fixed-width code</code>
|
|
||||||
|
|
||||||
<emoji id="12345678901234567890">🔥</emoji>
|
<emoji id="12345678901234567890">🔥</emoji>
|
||||||
|
|
||||||
|
<code>inline fixed-width code</code>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
pre-formatted
|
pre-formatted
|
||||||
fixed-width
|
fixed-width
|
||||||
|
|
@ -134,6 +82,8 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<blockquote>Quoted text</blockquote>
|
<blockquote>Quoted text</blockquote>
|
||||||
|
|
||||||
|
<blockquote expandable>Quoted text with collapse/expand button</blockquote>
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
@ -178,6 +128,72 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<my text>
|
<my text>
|
||||||
|
|
||||||
|
Markdown Style
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The Markdown style is not recommended for complex text formatting.
|
||||||
|
If you want to use complex text formatting such as nested entities, overlapping entities use the HTML style instead.
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
> Quoted text
|
||||||
|
|
||||||
|
**> Quoted text with collapse/expand button
|
||||||
|
|
||||||
|
**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
|
||||||
|
)
|
||||||
|
|
||||||
Different Styles
|
Different Styles
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
@ -230,18 +246,18 @@ strike` styles, and you can still combine both Markdown and HTML together.
|
||||||
|
|
||||||
Here there are some example texts you can try sending:
|
Here there are some example texts you can try sending:
|
||||||
|
|
||||||
**Markdown**:
|
|
||||||
|
|
||||||
- ``**bold, --underline--**``
|
|
||||||
- ``**bold __italic --underline ~~strike~~--__**``
|
|
||||||
- ``**bold __and** italic__``
|
|
||||||
|
|
||||||
**HTML**:
|
**HTML**:
|
||||||
|
|
||||||
- ``<b>bold, <u>underline</u></b>``
|
- ``<b>bold, <u>underline</u></b>``
|
||||||
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
||||||
- ``<b>bold <i>and</b> italic</i>``
|
- ``<b>bold <i>and</b> italic</i>``
|
||||||
|
|
||||||
|
**Markdown (Not Recommended)**:
|
||||||
|
|
||||||
|
- ``**bold, --underline--**``
|
||||||
|
- ``**bold __italic --underline ~~strike~~--__**``
|
||||||
|
- ``**bold __and** italic__``
|
||||||
|
|
||||||
**Combined**:
|
**Combined**:
|
||||||
|
|
||||||
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ authors = [{ name = "wulan17", email = "mayuri@mayuri.my.id" }]
|
||||||
dependencies = ["pyaes==1.6.1", "pysocks==1.7.1", "pymediainfo-pyrofork>=6.0.1,<7.0.0"]
|
dependencies = ["pyaes==1.6.1", "pysocks==1.7.1", "pymediainfo-pyrofork>=6.0.1,<7.0.0"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "LGPL-3.0-or-later"
|
license = "LGPL-3.0-or-later"
|
||||||
requires-python = "~=3.8"
|
requires-python = "~=3.10"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
|
|
@ -15,11 +15,11 @@ classifiers = [
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
"Programming Language :: Python :: Implementation",
|
"Programming Language :: Python :: Implementation",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
|
|
@ -43,7 +43,7 @@ Homepage = "https://github.com/Mayuri-Chan"
|
||||||
Tracker = "https://github.com/Mayuri-Chan/pyrofork/issues"
|
Tracker = "https://github.com/Mayuri-Chan/pyrofork/issues"
|
||||||
Community = "https://t.me/MayuriChan_Chat"
|
Community = "https://t.me/MayuriChan_Chat"
|
||||||
Source = "https://github.com/Mayuri-Chan/pyrofork"
|
Source = "https://github.com/Mayuri-Chan/pyrofork"
|
||||||
Documentation = "https://pyrofork.mayuri.my.id"
|
Documentation = "https://pyrofork.wulan17.dev"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
|
|
@ -60,7 +60,7 @@ dev = [
|
||||||
|
|
||||||
docs = [
|
docs = [
|
||||||
"sphinx",
|
"sphinx",
|
||||||
"sphinx-immaterial==0.11.11",
|
"sphinx-immaterial==0.12.5",
|
||||||
"sphinx_copybutton",
|
"sphinx_copybutton",
|
||||||
"sphinx-autobuild",
|
"sphinx-autobuild",
|
||||||
"tornado>=6.3.3"
|
"tornado>=6.3.3"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
__fork_name__ = "PyroFork"
|
__fork_name__ = "PyroFork"
|
||||||
__version__ = "2.3.22"
|
__version__ = "2.3.69"
|
||||||
__license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)"
|
__license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)"
|
||||||
__copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>"
|
__copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>"
|
||||||
|
|
||||||
|
|
@ -37,8 +37,24 @@ class ContinuePropagation(StopAsyncIteration):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
from . import raw, types, filters, handlers, emoji, enums
|
from . import raw, types, filters, handlers, emoji, enums # pylint: disable=wrong-import-position
|
||||||
from .client import Client
|
from .client import Client # pylint: disable=wrong-import-position
|
||||||
from .sync import idle, compose
|
from .sync import idle, compose # pylint: disable=wrong-import-position
|
||||||
|
|
||||||
crypto_executor = ThreadPoolExecutor(1, thread_name_prefix="CryptoWorker")
|
crypto_executor = ThreadPoolExecutor(1, thread_name_prefix="CryptoWorker")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Client",
|
||||||
|
"idle",
|
||||||
|
"compose",
|
||||||
|
"crypto_executor",
|
||||||
|
"StopTransmission",
|
||||||
|
"StopPropagation",
|
||||||
|
"ContinuePropagation",
|
||||||
|
"raw",
|
||||||
|
"types",
|
||||||
|
"filters",
|
||||||
|
"handlers",
|
||||||
|
"emoji",
|
||||||
|
"enums",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -33,40 +33,45 @@ from importlib import import_module
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO, BytesIO
|
||||||
from mimetypes import MimeTypes
|
from mimetypes import MimeTypes
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union, List, Optional, Callable, AsyncGenerator
|
from typing import Union, List, Optional, Callable, AsyncGenerator, Tuple
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import __version__, __license__
|
from pyrogram import __version__, __license__
|
||||||
from pyrogram import enums
|
from pyrogram import enums
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from pyrogram import utils
|
from pyrogram import utils
|
||||||
from pyrogram.crypto import aes
|
from pyrogram.crypto import aes
|
||||||
from pyrogram.errors import CDNFileHashMismatch
|
from pyrogram.errors import CDNFileHashMismatch
|
||||||
from pyrogram.errors import (
|
from pyrogram.errors import (
|
||||||
SessionPasswordNeeded,
|
SessionPasswordNeeded,
|
||||||
VolumeLocNotFound, ChannelPrivate,
|
VolumeLocNotFound, ChannelPrivate,
|
||||||
BadRequest
|
BadRequest, ChannelInvalid, PersistentTimestampInvalid, PersistentTimestampOutdated
|
||||||
)
|
)
|
||||||
from pyrogram.handlers.handler import Handler
|
from pyrogram.handlers.handler import Handler
|
||||||
from pyrogram.methods import Methods
|
from pyrogram.methods import Methods
|
||||||
from pyrogram.session import Auth, Session
|
from pyrogram.session import Auth, Session
|
||||||
from pyrogram.storage import FileStorage, MemoryStorage, Storage
|
from pyrogram.storage import FileStorage, MemoryStorage, Storage
|
||||||
|
from pyrogram.types import User
|
||||||
|
from pyrogram.utils import ainput
|
||||||
|
from .connection import Connection
|
||||||
|
from .connection.transport import TCPAbridged
|
||||||
|
from .dispatcher import Dispatcher
|
||||||
|
from .file_id import FileId, FileType, ThumbnailSource
|
||||||
|
from .mime_types import mime_types
|
||||||
|
from .parser import Parser
|
||||||
|
from .session.internals import MsgId
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
MONGO_AVAIL = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pymongo
|
import pymongo
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
from pyrogram.storage import MongoStorage
|
from pyrogram.storage import MongoStorage
|
||||||
from pyrogram.types import User, TermsOfService
|
MONGO_AVAIL = True
|
||||||
from pyrogram.utils import ainput
|
|
||||||
from .dispatcher import Dispatcher
|
|
||||||
from .file_id import FileId, FileType, ThumbnailSource
|
|
||||||
from .filters import Filter
|
|
||||||
from .mime_types import mime_types
|
|
||||||
from .parser import Parser
|
|
||||||
from .session.internals import MsgId
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Client(Methods):
|
class Client(Methods):
|
||||||
|
|
@ -126,6 +131,9 @@ class Client(Methods):
|
||||||
Pass a session string to load the session in-memory.
|
Pass a session string to load the session in-memory.
|
||||||
Implies ``in_memory=True``.
|
Implies ``in_memory=True``.
|
||||||
|
|
||||||
|
use_qrcode (``bool``, *optional*):
|
||||||
|
Pass True to login using a QR code.
|
||||||
|
|
||||||
in_memory (``bool``, *optional*):
|
in_memory (``bool``, *optional*):
|
||||||
Pass True to start an in-memory session that will be discarded as soon as the client stops.
|
Pass True to start an in-memory session that will be discarded as soon as the client stops.
|
||||||
In order to reconnect again using an in-memory session without having to login again, you can use
|
In order to reconnect again using an in-memory session without having to login again, you can use
|
||||||
|
|
@ -201,6 +209,14 @@ class Client(Methods):
|
||||||
A value that is too high may result in network related issues.
|
A value that is too high may result in network related issues.
|
||||||
Defaults to 1.
|
Defaults to 1.
|
||||||
|
|
||||||
|
max_message_cache_size (``int``, *optional*):
|
||||||
|
Set the maximum size of the message cache.
|
||||||
|
Defaults to 10000.
|
||||||
|
|
||||||
|
max_business_user_connection_cache_size (``int``, *optional*):
|
||||||
|
Set the maximum size of the message cache.
|
||||||
|
Defaults to 10000.
|
||||||
|
|
||||||
client_platform (:obj:`~pyrogram.enums.ClientPlatform`, *optional*):
|
client_platform (:obj:`~pyrogram.enums.ClientPlatform`, *optional*):
|
||||||
The platform where this client is running.
|
The platform where this client is running.
|
||||||
Defaults to 'other'
|
Defaults to 'other'
|
||||||
|
|
@ -211,10 +227,13 @@ class Client(Methods):
|
||||||
SYSTEM_VERSION = f"{platform.system()} {platform.release()}"
|
SYSTEM_VERSION = f"{platform.system()} {platform.release()}"
|
||||||
|
|
||||||
LANG_CODE = "en"
|
LANG_CODE = "en"
|
||||||
|
LANG_PACK = ""
|
||||||
|
SYSTEM_LANG_CODE = "en-US"
|
||||||
|
|
||||||
PARENT_DIR = Path(sys.argv[0]).parent
|
PARENT_DIR = Path(sys.argv[0]).parent
|
||||||
|
|
||||||
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:joinchat/|\+))([\w-]+)$")
|
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:joinchat/|\+))([\w-]+)$")
|
||||||
|
UPGRADED_GIFT_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:nft/|\+))([\w-]+)$")
|
||||||
WORKERS = min(32, (os.cpu_count() or 0) + 4) # os.cpu_count() can be None
|
WORKERS = min(32, (os.cpu_count() or 0) + 4) # os.cpu_count() can be None
|
||||||
WORKDIR = PARENT_DIR
|
WORKDIR = PARENT_DIR
|
||||||
|
|
||||||
|
|
@ -222,6 +241,7 @@ class Client(Methods):
|
||||||
UPDATES_WATCHDOG_INTERVAL = 15 * 60
|
UPDATES_WATCHDOG_INTERVAL = 15 * 60
|
||||||
|
|
||||||
MAX_CONCURRENT_TRANSMISSIONS = 1
|
MAX_CONCURRENT_TRANSMISSIONS = 1
|
||||||
|
MAX_CACHE_SIZE = 10000
|
||||||
|
|
||||||
mimetypes = MimeTypes()
|
mimetypes = MimeTypes()
|
||||||
mimetypes.readfp(StringIO(mime_types))
|
mimetypes.readfp(StringIO(mime_types))
|
||||||
|
|
@ -234,13 +254,16 @@ class Client(Methods):
|
||||||
app_version: str = APP_VERSION,
|
app_version: str = APP_VERSION,
|
||||||
device_model: str = DEVICE_MODEL,
|
device_model: str = DEVICE_MODEL,
|
||||||
system_version: str = SYSTEM_VERSION,
|
system_version: str = SYSTEM_VERSION,
|
||||||
|
system_lang_code: str = SYSTEM_LANG_CODE,
|
||||||
lang_code: str = LANG_CODE,
|
lang_code: str = LANG_CODE,
|
||||||
|
lang_pack: str = LANG_PACK,
|
||||||
ipv6: Optional[bool] = False,
|
ipv6: Optional[bool] = False,
|
||||||
alt_port: Optional[bool] = False,
|
alt_port: Optional[bool] = False,
|
||||||
proxy: Optional[dict] = None,
|
proxy: Optional[dict] = None,
|
||||||
test_mode: Optional[bool] = False,
|
test_mode: Optional[bool] = False,
|
||||||
bot_token: Optional[str] = None,
|
bot_token: Optional[str] = None,
|
||||||
session_string: Optional[str] = None,
|
session_string: Optional[str] = None,
|
||||||
|
use_qrcode: Optional[bool] = False,
|
||||||
in_memory: Optional[bool] = None,
|
in_memory: Optional[bool] = None,
|
||||||
mongodb: Optional[dict] = None,
|
mongodb: Optional[dict] = None,
|
||||||
storage: Optional[Storage] = None,
|
storage: Optional[Storage] = None,
|
||||||
|
|
@ -255,9 +278,11 @@ class Client(Methods):
|
||||||
skip_updates: bool = True,
|
skip_updates: bool = True,
|
||||||
takeout: bool = None,
|
takeout: bool = None,
|
||||||
sleep_threshold: int = Session.SLEEP_THRESHOLD,
|
sleep_threshold: int = Session.SLEEP_THRESHOLD,
|
||||||
hide_password: Optional[bool] = False,
|
hide_password: Optional[bool] = True,
|
||||||
max_concurrent_transmissions: int = MAX_CONCURRENT_TRANSMISSIONS,
|
max_concurrent_transmissions: int = MAX_CONCURRENT_TRANSMISSIONS,
|
||||||
client_platform: "enums.ClientPlatform" = enums.ClientPlatform.OTHER
|
client_platform: "enums.ClientPlatform" = enums.ClientPlatform.OTHER,
|
||||||
|
max_message_cache_size: int = MAX_CACHE_SIZE,
|
||||||
|
max_business_user_connection_cache_size: int = MAX_CACHE_SIZE
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
|
@ -267,13 +292,16 @@ class Client(Methods):
|
||||||
self.app_version = app_version
|
self.app_version = app_version
|
||||||
self.device_model = device_model
|
self.device_model = device_model
|
||||||
self.system_version = system_version
|
self.system_version = system_version
|
||||||
|
self.system_lang_code = system_lang_code.lower()
|
||||||
self.lang_code = lang_code.lower()
|
self.lang_code = lang_code.lower()
|
||||||
|
self.lang_pack = lang_pack.lower()
|
||||||
self.ipv6 = ipv6
|
self.ipv6 = ipv6
|
||||||
self.alt_port = alt_port
|
self.alt_port = alt_port
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
self.test_mode = test_mode
|
self.test_mode = test_mode
|
||||||
self.bot_token = bot_token
|
self.bot_token = bot_token
|
||||||
self.session_string = session_string
|
self.session_string = session_string
|
||||||
|
self.use_qrcode = use_qrcode
|
||||||
self.in_memory = in_memory
|
self.in_memory = in_memory
|
||||||
self.mongodb = mongodb
|
self.mongodb = mongodb
|
||||||
self.phone_number = phone_number
|
self.phone_number = phone_number
|
||||||
|
|
@ -290,6 +318,9 @@ class Client(Methods):
|
||||||
self.hide_password = hide_password
|
self.hide_password = hide_password
|
||||||
self.max_concurrent_transmissions = max_concurrent_transmissions
|
self.max_concurrent_transmissions = max_concurrent_transmissions
|
||||||
self.client_platform = client_platform
|
self.client_platform = client_platform
|
||||||
|
self.max_message_cache_size = max_message_cache_size
|
||||||
|
self.max_message_cache_size = max_message_cache_size
|
||||||
|
self.max_business_user_connection_cache_size = max_business_user_connection_cache_size
|
||||||
|
|
||||||
self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler")
|
self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler")
|
||||||
|
|
||||||
|
|
@ -300,9 +331,7 @@ class Client(Methods):
|
||||||
elif self.in_memory:
|
elif self.in_memory:
|
||||||
self.storage = MemoryStorage(self.name)
|
self.storage = MemoryStorage(self.name)
|
||||||
elif self.mongodb:
|
elif self.mongodb:
|
||||||
try:
|
if not MONGO_AVAIL:
|
||||||
import pymongo
|
|
||||||
except Exception:
|
|
||||||
log.warning(
|
log.warning(
|
||||||
"pymongo is missing! "
|
"pymongo is missing! "
|
||||||
"Using MemoryStorage as session storage"
|
"Using MemoryStorage as session storage"
|
||||||
|
|
@ -313,6 +342,9 @@ class Client(Methods):
|
||||||
else:
|
else:
|
||||||
self.storage = FileStorage(self.name, self.workdir)
|
self.storage = FileStorage(self.name, self.workdir)
|
||||||
|
|
||||||
|
self.connection_factory = Connection
|
||||||
|
self.protocol_factory = TCPAbridged
|
||||||
|
|
||||||
self.dispatcher = Dispatcher(self)
|
self.dispatcher = Dispatcher(self)
|
||||||
|
|
||||||
self.rnd_id = MsgId
|
self.rnd_id = MsgId
|
||||||
|
|
@ -336,7 +368,8 @@ class Client(Methods):
|
||||||
|
|
||||||
self.me: Optional[User] = None
|
self.me: Optional[User] = None
|
||||||
|
|
||||||
self.message_cache = Cache(10000)
|
self.message_cache = Cache(self.max_message_cache_size)
|
||||||
|
self.business_user_connection_cache = Cache(self.max_business_user_connection_cache_size)
|
||||||
|
|
||||||
# Sometimes, for some reason, the server will stop sending updates and will only respond to pings.
|
# Sometimes, for some reason, the server will stop sending updates and will only respond to pings.
|
||||||
# This watchdog will invoke updates.GetState in order to wake up the server and enable it sending updates again
|
# This watchdog will invoke updates.GetState in order to wake up the server and enable it sending updates again
|
||||||
|
|
@ -377,6 +410,15 @@ class Client(Methods):
|
||||||
if datetime.now() - self.last_update_time > timedelta(seconds=self.UPDATES_WATCHDOG_INTERVAL):
|
if datetime.now() - self.last_update_time > timedelta(seconds=self.UPDATES_WATCHDOG_INTERVAL):
|
||||||
await self.invoke(raw.functions.updates.GetState())
|
await self.invoke(raw.functions.updates.GetState())
|
||||||
|
|
||||||
|
async def _wait_for_update_login_token(self):
|
||||||
|
"""
|
||||||
|
Wait for an UpdateLoginToken update from Telegram.
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
update, _, _ = await self.dispatcher.updates_queue.get()
|
||||||
|
if isinstance(update, raw.types.UpdateLoginToken):
|
||||||
|
break
|
||||||
|
|
||||||
async def authorize(self) -> User:
|
async def authorize(self) -> User:
|
||||||
if self.bot_token:
|
if self.bot_token:
|
||||||
return await self.sign_in_bot(self.bot_token)
|
return await self.sign_in_bot(self.bot_token)
|
||||||
|
|
@ -384,52 +426,60 @@ class Client(Methods):
|
||||||
print(f"Welcome to Pyrogram (version {__version__})")
|
print(f"Welcome to Pyrogram (version {__version__})")
|
||||||
print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n"
|
print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n"
|
||||||
f"under the terms of the {__license__}.\n")
|
f"under the terms of the {__license__}.\n")
|
||||||
|
if not self.use_qrcode:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if not self.phone_number:
|
||||||
|
while True:
|
||||||
|
print("Enter 'qrcode' if you want to login with qrcode.")
|
||||||
|
value = await ainput("Enter phone number or bot token: ")
|
||||||
|
|
||||||
|
if not value:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if value.lower() == "qrcode":
|
||||||
|
self.use_qrcode = True
|
||||||
|
break
|
||||||
|
|
||||||
|
confirm = (await ainput(f'Is "{value}" correct? (y/N): ')).lower()
|
||||||
|
|
||||||
|
if confirm == "y":
|
||||||
|
break
|
||||||
|
|
||||||
|
if ":" in value:
|
||||||
|
self.bot_token = value
|
||||||
|
return await self.sign_in_bot(value)
|
||||||
|
else:
|
||||||
|
self.phone_number = value
|
||||||
|
if not self.use_qrcode:
|
||||||
|
sent_code = await self.send_code(self.phone_number)
|
||||||
|
except BadRequest as e:
|
||||||
|
print(e.MESSAGE)
|
||||||
|
self.phone_number = None
|
||||||
|
self.bot_token = None
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if not self.use_qrcode:
|
||||||
|
sent_code_descriptions = {
|
||||||
|
enums.SentCodeType.APP: "Telegram app",
|
||||||
|
enums.SentCodeType.SMS: "SMS",
|
||||||
|
enums.SentCodeType.CALL: "phone call",
|
||||||
|
enums.SentCodeType.FLASH_CALL: "phone flash call",
|
||||||
|
enums.SentCodeType.FRAGMENT_SMS: "Fragment SMS",
|
||||||
|
enums.SentCodeType.EMAIL_CODE: "email code"
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"The confirmation code has been sent via {sent_code_descriptions[sent_code.type]}")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
if not self.use_qrcode and not self.phone_code:
|
||||||
if not self.phone_number:
|
|
||||||
while True:
|
|
||||||
value = await ainput("Enter phone number or bot token: ")
|
|
||||||
|
|
||||||
if not value:
|
|
||||||
continue
|
|
||||||
|
|
||||||
confirm = (await ainput(f'Is "{value}" correct? (y/N): ')).lower()
|
|
||||||
|
|
||||||
if confirm == "y":
|
|
||||||
break
|
|
||||||
|
|
||||||
if ":" in value:
|
|
||||||
self.bot_token = value
|
|
||||||
return await self.sign_in_bot(value)
|
|
||||||
else:
|
|
||||||
self.phone_number = value
|
|
||||||
|
|
||||||
sent_code = await self.send_code(self.phone_number)
|
|
||||||
except BadRequest as e:
|
|
||||||
print(e.MESSAGE)
|
|
||||||
self.phone_number = None
|
|
||||||
self.bot_token = None
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
sent_code_descriptions = {
|
|
||||||
enums.SentCodeType.APP: "Telegram app",
|
|
||||||
enums.SentCodeType.SMS: "SMS",
|
|
||||||
enums.SentCodeType.CALL: "phone call",
|
|
||||||
enums.SentCodeType.FLASH_CALL: "phone flash call",
|
|
||||||
enums.SentCodeType.FRAGMENT_SMS: "Fragment SMS",
|
|
||||||
enums.SentCodeType.EMAIL_CODE: "email code"
|
|
||||||
}
|
|
||||||
|
|
||||||
print(f"The confirmation code has been sent via {sent_code_descriptions[sent_code.type]}")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if not self.phone_code:
|
|
||||||
self.phone_code = await ainput("Enter confirmation code: ")
|
self.phone_code = await ainput("Enter confirmation code: ")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
signed_in = await self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code)
|
if self.use_qrcode:
|
||||||
|
signed_in = await self.sign_in_qrcode()
|
||||||
|
else:
|
||||||
|
signed_in = await self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code)
|
||||||
except BadRequest as e:
|
except BadRequest as e:
|
||||||
print(e.MESSAGE)
|
print(e.MESSAGE)
|
||||||
self.phone_code = None
|
self.phone_code = None
|
||||||
|
|
@ -468,33 +518,18 @@ class Client(Methods):
|
||||||
print(e.MESSAGE)
|
print(e.MESSAGE)
|
||||||
self.password = None
|
self.password = None
|
||||||
else:
|
else:
|
||||||
|
if self.use_qrcode and isinstance(signed_in, types.LoginToken):
|
||||||
|
time_out = signed_in.expires - datetime.timestamp(datetime.now())
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(self._wait_for_update_login_token(), timeout=time_out)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
print("QR code expired, Requesting new Qr code...")
|
||||||
|
continue
|
||||||
break
|
break
|
||||||
|
|
||||||
if isinstance(signed_in, User):
|
if isinstance(signed_in, User):
|
||||||
return signed_in
|
return signed_in
|
||||||
|
|
||||||
while True:
|
|
||||||
first_name = await ainput("Enter first name: ")
|
|
||||||
last_name = await ainput("Enter last name (empty to skip): ")
|
|
||||||
|
|
||||||
try:
|
|
||||||
signed_up = await self.sign_up(
|
|
||||||
self.phone_number,
|
|
||||||
sent_code.phone_code_hash,
|
|
||||||
first_name,
|
|
||||||
last_name
|
|
||||||
)
|
|
||||||
except BadRequest as e:
|
|
||||||
print(e.MESSAGE)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
if isinstance(signed_in, TermsOfService):
|
|
||||||
print("\n" + signed_in.text + "\n")
|
|
||||||
await self.accept_terms_of_service(signed_in.id)
|
|
||||||
|
|
||||||
return signed_up
|
|
||||||
|
|
||||||
def set_parse_mode(self, parse_mode: Optional["enums.ParseMode"]):
|
def set_parse_mode(self, parse_mode: Optional["enums.ParseMode"]):
|
||||||
"""Set the parse mode to be used globally by the client.
|
"""Set the parse mode to be used globally by the client.
|
||||||
|
|
||||||
|
|
@ -556,7 +591,7 @@ class Client(Methods):
|
||||||
)
|
)
|
||||||
if peer.usernames is not None and len(peer.usernames) > 1:
|
if peer.usernames is not None and len(peer.usernames) > 1:
|
||||||
for uname in peer.usernames:
|
for uname in peer.usernames:
|
||||||
usernames.append((peer.id, uname.username.lower()))
|
usernames.append((peer_id, uname.username.lower()))
|
||||||
phone_number = peer.phone
|
phone_number = peer.phone
|
||||||
peer_type = "bot" if peer.bot else "user"
|
peer_type = "bot" if peer.bot else "user"
|
||||||
elif isinstance(peer, (raw.types.Chat, raw.types.ChatForbidden)):
|
elif isinstance(peer, (raw.types.Chat, raw.types.ChatForbidden)):
|
||||||
|
|
@ -573,7 +608,7 @@ class Client(Methods):
|
||||||
)
|
)
|
||||||
if peer.usernames is not None and len(peer.usernames) > 1:
|
if peer.usernames is not None and len(peer.usernames) > 1:
|
||||||
for uname in peer.usernames:
|
for uname in peer.usernames:
|
||||||
usernames.append((peer.id, uname.username.lower()))
|
usernames.append((peer_id, uname.username.lower()))
|
||||||
peer_type = "channel" if peer.broadcast else "supergroup"
|
peer_type = "channel" if peer.broadcast else "supergroup"
|
||||||
elif isinstance(peer, raw.types.ChannelForbidden):
|
elif isinstance(peer, raw.types.ChannelForbidden):
|
||||||
peer_id = utils.get_channel_id(peer.id)
|
peer_id = utils.get_channel_id(peer.id)
|
||||||
|
|
@ -642,10 +677,11 @@ class Client(Methods):
|
||||||
)]
|
)]
|
||||||
),
|
),
|
||||||
pts=pts - pts_count,
|
pts=pts - pts_count,
|
||||||
limit=pts
|
limit=pts,
|
||||||
|
force=False
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except ChannelPrivate:
|
except (ChannelPrivate, PersistentTimestampOutdated, PersistentTimestampInvalid):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if not isinstance(diff, raw.types.updates.ChannelDifferenceEmpty):
|
if not isinstance(diff, raw.types.updates.ChannelDifferenceEmpty):
|
||||||
|
|
@ -690,6 +726,92 @@ class Client(Methods):
|
||||||
elif isinstance(updates, raw.types.UpdatesTooLong):
|
elif isinstance(updates, raw.types.UpdatesTooLong):
|
||||||
log.info(updates)
|
log.info(updates)
|
||||||
|
|
||||||
|
async def recover_gaps(self) -> Tuple[int, int]:
|
||||||
|
states = await self.storage.update_state()
|
||||||
|
|
||||||
|
message_updates_counter = 0
|
||||||
|
other_updates_counter = 0
|
||||||
|
|
||||||
|
if not states:
|
||||||
|
log.info("No states found, skipping recovery.")
|
||||||
|
return (message_updates_counter, other_updates_counter)
|
||||||
|
|
||||||
|
for state in states:
|
||||||
|
id, local_pts, _, local_date, _ = state
|
||||||
|
|
||||||
|
prev_pts = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
diff = await self.invoke(
|
||||||
|
raw.functions.updates.GetChannelDifference(
|
||||||
|
channel=await self.resolve_peer(id),
|
||||||
|
filter=raw.types.ChannelMessagesFilterEmpty(),
|
||||||
|
pts=local_pts,
|
||||||
|
limit=10000,
|
||||||
|
force=False
|
||||||
|
) if id < 0 else
|
||||||
|
raw.functions.updates.GetDifference(
|
||||||
|
pts=local_pts,
|
||||||
|
date=local_date,
|
||||||
|
qts=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except (ChannelPrivate, ChannelInvalid, PersistentTimestampOutdated, PersistentTimestampInvalid):
|
||||||
|
break
|
||||||
|
|
||||||
|
if isinstance(diff, raw.types.updates.DifferenceEmpty):
|
||||||
|
break
|
||||||
|
elif isinstance(diff, raw.types.updates.DifferenceTooLong):
|
||||||
|
break
|
||||||
|
elif isinstance(diff, raw.types.updates.Difference):
|
||||||
|
local_pts = diff.state.pts
|
||||||
|
elif isinstance(diff, raw.types.updates.DifferenceSlice):
|
||||||
|
local_pts = diff.intermediate_state.pts
|
||||||
|
local_date = diff.intermediate_state.date
|
||||||
|
|
||||||
|
if prev_pts == local_pts:
|
||||||
|
break
|
||||||
|
|
||||||
|
prev_pts = local_pts
|
||||||
|
elif isinstance(diff, raw.types.updates.ChannelDifferenceEmpty):
|
||||||
|
break
|
||||||
|
elif isinstance(diff, raw.types.updates.ChannelDifferenceTooLong):
|
||||||
|
break
|
||||||
|
elif isinstance(diff, raw.types.updates.ChannelDifference):
|
||||||
|
local_pts = diff.pts
|
||||||
|
|
||||||
|
users = {i.id: i for i in diff.users}
|
||||||
|
chats = {i.id: i for i in diff.chats}
|
||||||
|
|
||||||
|
for message in diff.new_messages:
|
||||||
|
message_updates_counter += 1
|
||||||
|
self.dispatcher.updates_queue.put_nowait(
|
||||||
|
(
|
||||||
|
raw.types.UpdateNewMessage(
|
||||||
|
message=message,
|
||||||
|
pts=local_pts,
|
||||||
|
pts_count=-1
|
||||||
|
),
|
||||||
|
users,
|
||||||
|
chats
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for update in diff.other_updates:
|
||||||
|
other_updates_counter += 1
|
||||||
|
self.dispatcher.updates_queue.put_nowait(
|
||||||
|
(update, users, chats)
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(diff, (raw.types.updates.Difference, raw.types.updates.ChannelDifference)):
|
||||||
|
break
|
||||||
|
|
||||||
|
await self.storage.update_state(id)
|
||||||
|
|
||||||
|
log.info("Recovered %s messages and %s updates.", message_updates_counter, other_updates_counter)
|
||||||
|
return (message_updates_counter, other_updates_counter)
|
||||||
|
|
||||||
async def load_session(self):
|
async def load_session(self):
|
||||||
await self.storage.open()
|
await self.storage.open()
|
||||||
|
|
||||||
|
|
@ -703,7 +825,7 @@ class Client(Methods):
|
||||||
if session_empty:
|
if session_empty:
|
||||||
if not self.api_id or not self.api_hash:
|
if not self.api_id or not self.api_hash:
|
||||||
raise AttributeError("The API key is required for new authorizations. "
|
raise AttributeError("The API key is required for new authorizations. "
|
||||||
"More info: https://pyrofork.mayuri.my.id/start/auth")
|
"More info: https://pyrofork.wulan17.dev/main/start/auth")
|
||||||
|
|
||||||
await self.storage.api_id(self.api_id)
|
await self.storage.api_id(self.api_id)
|
||||||
|
|
||||||
|
|
@ -741,6 +863,12 @@ class Client(Methods):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
|
def is_excluded(self, exclude, module):
|
||||||
|
for e in exclude:
|
||||||
|
if module == e or module.startswith(e + '.'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def load_plugins(self):
|
def load_plugins(self):
|
||||||
if self.plugins:
|
if self.plugins:
|
||||||
plugins = self.plugins.copy()
|
plugins = self.plugins.copy()
|
||||||
|
|
@ -759,40 +887,178 @@ class Client(Methods):
|
||||||
include = plugins.get("include", [])
|
include = plugins.get("include", [])
|
||||||
exclude = plugins.get("exclude", [])
|
exclude = plugins.get("exclude", [])
|
||||||
|
|
||||||
|
exclude_plugins = []
|
||||||
|
exclude_handlers = {}
|
||||||
|
|
||||||
|
if exclude:
|
||||||
|
for path, handler in exclude:
|
||||||
|
module_path = os.path.join(
|
||||||
|
root.replace(".", "/"), path.replace(".", "/")
|
||||||
|
)
|
||||||
|
if handler is None:
|
||||||
|
exclude_plugins.append(module_path.replace("/", ".").replace("\\", "."))
|
||||||
|
else:
|
||||||
|
exclude_handlers[module_path.replace("/", ".").replace("\\", ".")] = handler
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
if not include:
|
if not include:
|
||||||
for path in sorted(Path(root.replace(".", "/")).rglob("*.py")):
|
for current_root, _, filenames in os.walk(root.replace(".", "/")):
|
||||||
module_path = '.'.join(path.parent.parts + (path.stem,))
|
namespace = current_root.replace("/", ".").replace("\\", ".")
|
||||||
module = import_module(module_path)
|
if "__pycache__" in namespace:
|
||||||
|
continue
|
||||||
|
if namespace in exclude_plugins:
|
||||||
|
log.warning(
|
||||||
|
'[%s] [LOAD] Ignoring namespace "%s"', self.name, namespace
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
for filename in filenames:
|
||||||
|
if filename.endswith(".py"):
|
||||||
|
module_path = namespace + "." + filename[:-3]
|
||||||
|
if module_path in exclude_plugins:
|
||||||
|
log.warning(
|
||||||
|
'[%s] [LOAD] Ignoring namespace "%s"',
|
||||||
|
self.name,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
module = import_module(module_path)
|
||||||
|
|
||||||
for name in vars(module).keys():
|
for name in vars(module).keys():
|
||||||
# noinspection PyBroadException
|
|
||||||
try:
|
|
||||||
for handler, group in getattr(module, name).handlers:
|
|
||||||
if isinstance(handler, Handler) and isinstance(group, int):
|
|
||||||
self.add_handler(handler, group)
|
|
||||||
|
|
||||||
log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
|
# noinspection PyBroadException
|
||||||
self.name, type(handler).__name__, name, group, module_path))
|
try:
|
||||||
|
for handler, group in getattr(
|
||||||
|
module, name
|
||||||
|
).handlers:
|
||||||
|
if isinstance(
|
||||||
|
handler, Handler
|
||||||
|
) and isinstance(group, int):
|
||||||
|
|
||||||
count += 1
|
if (
|
||||||
except Exception:
|
module_path in exclude_handlers
|
||||||
pass
|
and name
|
||||||
|
in exclude_handlers[module_path]
|
||||||
|
):
|
||||||
|
exclude_handlers[
|
||||||
|
module_path
|
||||||
|
].remove(name)
|
||||||
|
log.warning(
|
||||||
|
'[{}] [LOAD] Ignoring function "{}" from group {} in "{}"'.format(
|
||||||
|
self.name,
|
||||||
|
name,
|
||||||
|
group,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.add_handler(handler, group)
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
'[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
|
||||||
|
self.name,
|
||||||
|
type(handler).__name__,
|
||||||
|
name,
|
||||||
|
group,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
for path, handlers in include:
|
for path, handlers in include:
|
||||||
module_path = root + "." + path
|
module_path = root.replace("/", ".").replace("\\", ".") + "." + path
|
||||||
|
if self.is_excluded(exclude_plugins, module_path):
|
||||||
|
log.warning(
|
||||||
|
'[%s] [LOAD] Ignoring namespace "%s"', self.name, module_path
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
warn_non_existent_functions = True
|
warn_non_existent_functions = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
module = import_module(module_path)
|
module = import_module(module_path)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
log.warning('[%s] [LOAD] Ignoring non-existent module "%s"', self.name, module_path)
|
log.warning(
|
||||||
|
'[%s] [LOAD] Ignoring non-existent module "%s"',
|
||||||
|
self.name,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if "__path__" in dir(module):
|
if "__path__" in dir(module):
|
||||||
log.warning('[%s] [LOAD] Ignoring namespace "%s"', self.name, module_path)
|
for current_root, _, filenames in os.walk(module_path.replace(".", "/")):
|
||||||
continue
|
namespace = current_root.replace("/", ".").replace("\\", ".")
|
||||||
|
if "__pycache__" in namespace:
|
||||||
|
continue
|
||||||
|
if namespace in exclude_plugins:
|
||||||
|
log.warning(
|
||||||
|
'[%s] [LOAD] Ignoring namespace "%s"', self.name, namespace
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
for filename in filenames:
|
||||||
|
if filename.endswith(".py"):
|
||||||
|
module_path = namespace + "." + filename[:-3]
|
||||||
|
if module_path in exclude_plugins:
|
||||||
|
log.warning(
|
||||||
|
'[%s] [LOAD] Ignoring namespace "%s"',
|
||||||
|
self.name,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
module = import_module(module_path)
|
||||||
|
|
||||||
|
for name in vars(module).keys():
|
||||||
|
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
for handler, group in getattr(
|
||||||
|
module, name
|
||||||
|
).handlers:
|
||||||
|
if isinstance(
|
||||||
|
handler, Handler
|
||||||
|
) and isinstance(group, int):
|
||||||
|
|
||||||
|
if (
|
||||||
|
module_path in exclude_handlers
|
||||||
|
and name
|
||||||
|
in exclude_handlers[module_path]
|
||||||
|
):
|
||||||
|
exclude_handlers[
|
||||||
|
module_path
|
||||||
|
].remove(name)
|
||||||
|
log.warning(
|
||||||
|
'[{}] [LOAD] Ignoring function "{}" from group {} in "{}"'.format(
|
||||||
|
self.name,
|
||||||
|
name,
|
||||||
|
group,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.add_handler(handler, group)
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
'[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
|
||||||
|
self.name,
|
||||||
|
type(handler).__name__,
|
||||||
|
name,
|
||||||
|
group,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
if handlers is None:
|
if handlers is None:
|
||||||
handlers = vars(module).keys()
|
handlers = vars(module).keys()
|
||||||
|
|
@ -803,62 +1069,59 @@ class Client(Methods):
|
||||||
try:
|
try:
|
||||||
for handler, group in getattr(module, name).handlers:
|
for handler, group in getattr(module, name).handlers:
|
||||||
if isinstance(handler, Handler) and isinstance(group, int):
|
if isinstance(handler, Handler) and isinstance(group, int):
|
||||||
|
if (
|
||||||
|
module_path in exclude_handlers
|
||||||
|
and name in exclude_handlers[module_path]
|
||||||
|
):
|
||||||
|
exclude_handlers[module_path].remove(name)
|
||||||
|
log.warning(
|
||||||
|
'[{}] [LOAD] Ignoring function "{}" from group {} in "{}"'.format(
|
||||||
|
self.name, name, group, module_path
|
||||||
|
)
|
||||||
|
)
|
||||||
|
continue
|
||||||
self.add_handler(handler, group)
|
self.add_handler(handler, group)
|
||||||
|
|
||||||
log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
|
log.info(
|
||||||
self.name, type(handler).__name__, name, group, module_path))
|
'[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
|
||||||
|
self.name,
|
||||||
|
type(handler).__name__,
|
||||||
|
name,
|
||||||
|
group,
|
||||||
|
module_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
except Exception:
|
except Exception:
|
||||||
if warn_non_existent_functions:
|
if warn_non_existent_functions:
|
||||||
log.warning('[{}] [LOAD] Ignoring non-existent function "{}" from "{}"'.format(
|
log.warning(
|
||||||
self.name, name, module_path))
|
'[{}] [LOAD] Ignoring non-existent function "{}" from "{}"'.format(
|
||||||
|
self.name, name, module_path
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if exclude:
|
for module in exclude_handlers:
|
||||||
for path, handlers in exclude:
|
for handler in exclude_handlers[module]:
|
||||||
module_path = root + "." + path
|
log.warning(
|
||||||
warn_non_existent_functions = True
|
'[{}] [LOAD] Ignoring non-existent function "{}" from "{}"'.format(
|
||||||
|
self.name, handler, module
|
||||||
try:
|
)
|
||||||
module = import_module(module_path)
|
)
|
||||||
except ImportError:
|
|
||||||
log.warning('[%s] [UNLOAD] Ignoring non-existent module "%s"', self.name, module_path)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if "__path__" in dir(module):
|
|
||||||
log.warning('[%s] [UNLOAD] Ignoring namespace "%s"', self.name, module_path)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if handlers is None:
|
|
||||||
handlers = vars(module).keys()
|
|
||||||
warn_non_existent_functions = False
|
|
||||||
|
|
||||||
for name in handlers:
|
|
||||||
# noinspection PyBroadException
|
|
||||||
try:
|
|
||||||
for handler, group in getattr(module, name).handlers:
|
|
||||||
if isinstance(handler, Handler) and isinstance(group, int):
|
|
||||||
self.remove_handler(handler, group)
|
|
||||||
|
|
||||||
log.info('[{}] [UNLOAD] {}("{}") from group {} in "{}"'.format(
|
|
||||||
self.name, type(handler).__name__, name, group, module_path))
|
|
||||||
|
|
||||||
count -= 1
|
|
||||||
except Exception:
|
|
||||||
if warn_non_existent_functions:
|
|
||||||
log.warning('[{}] [UNLOAD] Ignoring non-existent function "{}" from "{}"'.format(
|
|
||||||
self.name, name, module_path))
|
|
||||||
|
|
||||||
if count > 0:
|
if count > 0:
|
||||||
log.info('[{}] Successfully loaded {} plugin{} from "{}"'.format(
|
log.info(
|
||||||
self.name, count, "s" if count > 1 else "", root))
|
'[{}] Successfully loaded {} plugin{} from "{}"'.format(
|
||||||
|
self.name, count, "s" if count > 1 else "", root
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
log.warning('[%s] No plugin loaded from "%s"', self.name, root)
|
log.warning('[%s] No plugin loaded from "%s"', self.name, root)
|
||||||
|
|
||||||
async def handle_download(self, packet):
|
async def handle_download(self, packet):
|
||||||
file_id, directory, file_name, in_memory, file_size, progress, progress_args = packet
|
file_id, directory, file_name, in_memory, file_size, progress, progress_args = packet
|
||||||
|
|
||||||
os.makedirs(directory, exist_ok=True) if not in_memory else None
|
_ = os.makedirs(directory, exist_ok=True) if not in_memory else None
|
||||||
temp_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + ".temp"
|
temp_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + ".temp"
|
||||||
file = BytesIO() if in_memory else open(temp_file_path, "wb")
|
file = BytesIO() if in_memory else open(temp_file_path, "wb")
|
||||||
|
|
||||||
|
|
@ -974,7 +1237,8 @@ class Client(Methods):
|
||||||
location=location,
|
location=location,
|
||||||
offset=offset_bytes,
|
offset=offset_bytes,
|
||||||
limit=chunk_size
|
limit=chunk_size
|
||||||
)
|
),
|
||||||
|
sleep_threshold=30
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(r, raw.types.upload.File):
|
if isinstance(r, raw.types.upload.File):
|
||||||
|
|
@ -1009,7 +1273,8 @@ class Client(Methods):
|
||||||
location=location,
|
location=location,
|
||||||
offset=offset_bytes,
|
offset=offset_bytes,
|
||||||
limit=chunk_size
|
limit=chunk_size
|
||||||
)
|
),
|
||||||
|
sleep_threshold=30
|
||||||
)
|
)
|
||||||
|
|
||||||
elif isinstance(r, raw.types.upload.FileCdnRedirect):
|
elif isinstance(r, raw.types.upload.FileCdnRedirect):
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,7 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .connection import Connection
|
from .connection import Connection
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Connection"
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional, Type
|
||||||
|
|
||||||
from .transport import TCP, TCPAbridged
|
from .transport import TCP, TCPAbridged
|
||||||
from ..session.internals import DataCenter
|
from ..session.internals import DataCenter
|
||||||
|
|
@ -30,20 +30,30 @@ log = logging.getLogger(__name__)
|
||||||
class Connection:
|
class Connection:
|
||||||
MAX_CONNECTION_ATTEMPTS = 3
|
MAX_CONNECTION_ATTEMPTS = 3
|
||||||
|
|
||||||
def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, alt_port: bool, proxy: dict, media: bool = False):
|
def __init__(
|
||||||
|
self,
|
||||||
|
dc_id: int,
|
||||||
|
test_mode: bool,
|
||||||
|
ipv6: bool,
|
||||||
|
alt_port: bool,
|
||||||
|
proxy: dict,
|
||||||
|
media: bool = False,
|
||||||
|
protocol_factory: Type[TCP] = TCPAbridged
|
||||||
|
) -> None:
|
||||||
self.dc_id = dc_id
|
self.dc_id = dc_id
|
||||||
self.test_mode = test_mode
|
self.test_mode = test_mode
|
||||||
self.ipv6 = ipv6
|
self.ipv6 = ipv6
|
||||||
self.alt_port = alt_port
|
self.alt_port = alt_port
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
self.media = media
|
self.media = media
|
||||||
|
self.protocol_factory = protocol_factory
|
||||||
|
|
||||||
self.address = DataCenter(dc_id, test_mode, ipv6, alt_port, media)
|
self.address = DataCenter(dc_id, test_mode, ipv6, alt_port, media)
|
||||||
self.protocol: TCP = None
|
self.protocol: Optional[TCP] = None
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self) -> None:
|
||||||
for i in range(Connection.MAX_CONNECTION_ATTEMPTS):
|
for _ in range(Connection.MAX_CONNECTION_ATTEMPTS):
|
||||||
self.protocol = TCPAbridged(self.ipv6, self.proxy)
|
self.protocol = self.protocol_factory(ipv6=self.ipv6, proxy=self.proxy)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
log.info("Connecting...")
|
log.info("Connecting...")
|
||||||
|
|
@ -63,11 +73,11 @@ class Connection:
|
||||||
log.warning("Connection failed! Trying again...")
|
log.warning("Connection failed! Trying again...")
|
||||||
raise ConnectionError
|
raise ConnectionError
|
||||||
|
|
||||||
async def close(self):
|
async def close(self) -> None:
|
||||||
await self.protocol.close()
|
await self.protocol.close()
|
||||||
log.info("Disconnected")
|
log.info("Disconnected")
|
||||||
|
|
||||||
async def send(self, data: bytes):
|
async def send(self, data: bytes) -> None:
|
||||||
await self.protocol.send(data)
|
await self.protocol.send(data)
|
||||||
|
|
||||||
async def recv(self) -> Optional[bytes]:
|
async def recv(self) -> Optional[bytes]:
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,6 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .tcp import *
|
from .tcp import *
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
__all__.extend(tcp.__all__)
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,19 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP, Proxy
|
||||||
from .tcp_abridged import TCPAbridged
|
from .tcp_abridged import TCPAbridged
|
||||||
from .tcp_abridged_o import TCPAbridgedO
|
from .tcp_abridged_o import TCPAbridgedO
|
||||||
from .tcp_full import TCPFull
|
from .tcp_full import TCPFull
|
||||||
from .tcp_intermediate import TCPIntermediate
|
from .tcp_intermediate import TCPIntermediate
|
||||||
from .tcp_intermediate_o import TCPIntermediateO
|
from .tcp_intermediate_o import TCPIntermediateO
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"TCP",
|
||||||
|
"Proxy",
|
||||||
|
"TCPAbridged",
|
||||||
|
"TCPAbridgedO",
|
||||||
|
"TCPFull",
|
||||||
|
"TCPIntermediate",
|
||||||
|
"TCPIntermediateO"
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -21,90 +21,134 @@ import asyncio
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from typing import Tuple, Dict, TypedDict, Optional
|
||||||
|
|
||||||
import socks
|
import socks
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
proxy_type_by_scheme: Dict[str, int] = {
|
||||||
|
"SOCKS4": socks.SOCKS4,
|
||||||
|
"SOCKS5": socks.SOCKS5,
|
||||||
|
"HTTP": socks.HTTP,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Proxy(TypedDict):
|
||||||
|
scheme: str
|
||||||
|
hostname: str
|
||||||
|
port: int
|
||||||
|
username: Optional[str]
|
||||||
|
password: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class TCP:
|
class TCP:
|
||||||
TIMEOUT = 10
|
TIMEOUT = 10
|
||||||
|
|
||||||
def __init__(self, ipv6: bool, proxy: dict):
|
def __init__(self, ipv6: bool, proxy: Proxy) -> None:
|
||||||
self.socket = None
|
self.ipv6 = ipv6
|
||||||
|
self.proxy = proxy
|
||||||
|
|
||||||
self.reader = None
|
self.reader: Optional[asyncio.StreamReader] = None
|
||||||
self.writer = None
|
self.writer: Optional[asyncio.StreamWriter] = None
|
||||||
|
|
||||||
self.lock = asyncio.Lock()
|
self.lock = asyncio.Lock()
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
self.proxy = proxy
|
async def _connect_via_proxy(
|
||||||
|
self,
|
||||||
|
destination: Tuple[str, int]
|
||||||
|
) -> None:
|
||||||
|
scheme = self.proxy.get("scheme")
|
||||||
|
if scheme is None:
|
||||||
|
raise ValueError("No scheme specified")
|
||||||
|
|
||||||
if proxy:
|
proxy_type = proxy_type_by_scheme.get(scheme.upper())
|
||||||
hostname = proxy.get("hostname")
|
if proxy_type is None:
|
||||||
|
raise ValueError(f"Unknown proxy type {scheme}")
|
||||||
|
|
||||||
try:
|
hostname = self.proxy.get("hostname")
|
||||||
ip_address = ipaddress.ip_address(hostname)
|
port = self.proxy.get("port")
|
||||||
except ValueError:
|
username = self.proxy.get("username")
|
||||||
self.socket = socks.socksocket(socket.AF_INET)
|
password = self.proxy.get("password")
|
||||||
else:
|
|
||||||
if isinstance(ip_address, ipaddress.IPv6Address):
|
|
||||||
self.socket = socks.socksocket(socket.AF_INET6)
|
|
||||||
else:
|
|
||||||
self.socket = socks.socksocket(socket.AF_INET)
|
|
||||||
|
|
||||||
self.socket.set_proxy(
|
|
||||||
proxy_type=getattr(socks, proxy.get("scheme").upper()),
|
|
||||||
addr=hostname,
|
|
||||||
port=proxy.get("port", None),
|
|
||||||
username=proxy.get("username", None),
|
|
||||||
password=proxy.get("password", None)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.socket.settimeout(TCP.TIMEOUT)
|
|
||||||
|
|
||||||
log.info("Using proxy %s", hostname)
|
|
||||||
else:
|
|
||||||
self.socket = socket.socket(
|
|
||||||
socket.AF_INET6 if ipv6
|
|
||||||
else socket.AF_INET
|
|
||||||
)
|
|
||||||
|
|
||||||
self.socket.setblocking(False)
|
|
||||||
|
|
||||||
async def connect(self, address: tuple):
|
|
||||||
if self.proxy:
|
|
||||||
with ThreadPoolExecutor(1) as executor:
|
|
||||||
await self.loop.run_in_executor(executor, self.socket.connect, address)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
await asyncio.wait_for(asyncio.get_event_loop().sock_connect(self.socket, address), TCP.TIMEOUT)
|
|
||||||
except asyncio.TimeoutError: # Re-raise as TimeoutError. asyncio.TimeoutError is deprecated in 3.11
|
|
||||||
raise TimeoutError("Connection timed out")
|
|
||||||
|
|
||||||
self.reader, self.writer = await asyncio.open_connection(sock=self.socket)
|
|
||||||
|
|
||||||
async def close(self):
|
|
||||||
try:
|
try:
|
||||||
if self.writer is not None:
|
ip_address = ipaddress.ip_address(hostname)
|
||||||
self.writer.close()
|
except ValueError:
|
||||||
await asyncio.wait_for(self.writer.wait_closed(), TCP.TIMEOUT)
|
is_proxy_ipv6 = False
|
||||||
|
else:
|
||||||
|
is_proxy_ipv6 = isinstance(ip_address, ipaddress.IPv6Address)
|
||||||
|
|
||||||
|
proxy_family = socket.AF_INET6 if is_proxy_ipv6 else socket.AF_INET
|
||||||
|
sock = socks.socksocket(proxy_family)
|
||||||
|
|
||||||
|
sock.set_proxy(
|
||||||
|
proxy_type=proxy_type,
|
||||||
|
addr=hostname,
|
||||||
|
port=port,
|
||||||
|
username=username,
|
||||||
|
password=password
|
||||||
|
)
|
||||||
|
sock.settimeout(TCP.TIMEOUT)
|
||||||
|
|
||||||
|
await self.loop.sock_connect(
|
||||||
|
sock=sock,
|
||||||
|
address=destination
|
||||||
|
)
|
||||||
|
|
||||||
|
sock.setblocking(False)
|
||||||
|
|
||||||
|
self.reader, self.writer = await asyncio.open_connection(
|
||||||
|
sock=sock
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _connect_via_direct(
|
||||||
|
self,
|
||||||
|
destination: Tuple[str, int]
|
||||||
|
) -> None:
|
||||||
|
host, port = destination
|
||||||
|
family = socket.AF_INET6 if self.ipv6 else socket.AF_INET
|
||||||
|
self.reader, self.writer = await asyncio.open_connection(
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
family=family
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _connect(self, destination: Tuple[str, int]) -> None:
|
||||||
|
if self.proxy:
|
||||||
|
await self._connect_via_proxy(destination)
|
||||||
|
else:
|
||||||
|
await self._connect_via_direct(destination)
|
||||||
|
|
||||||
|
async def connect(self, address: Tuple[str, int]) -> None:
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(self._connect(address), TCP.TIMEOUT)
|
||||||
|
except asyncio.TimeoutError: # Re-raise as TimeoutError. asyncio.TimeoutError is deprecated in 3.11
|
||||||
|
raise TimeoutError("Connection timed out")
|
||||||
|
|
||||||
|
async def close(self) -> None:
|
||||||
|
if self.writer is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.writer.close()
|
||||||
|
await asyncio.wait_for(self.writer.wait_closed(), TCP.TIMEOUT)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.info("Close exception: %s %s", type(e).__name__, e)
|
log.info("Close exception: %s %s", type(e).__name__, e)
|
||||||
|
|
||||||
async def send(self, data: bytes):
|
async def send(self, data: bytes) -> None:
|
||||||
|
if self.writer is None:
|
||||||
|
return None
|
||||||
|
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
try:
|
try:
|
||||||
if self.writer is not None:
|
self.writer.write(data)
|
||||||
self.writer.write(data)
|
await self.writer.drain()
|
||||||
await self.writer.drain()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.info("Send exception: %s %s", type(e).__name__, e)
|
log.info("Send exception: %s %s", type(e).__name__, e)
|
||||||
raise OSError(e)
|
raise OSError(e)
|
||||||
|
|
||||||
async def recv(self, length: int = 0):
|
async def recv(self, length: int = 0) -> Optional[bytes]:
|
||||||
data = b""
|
data = b""
|
||||||
|
|
||||||
while len(data) < length:
|
while len(data) < length:
|
||||||
|
|
|
||||||
|
|
@ -18,22 +18,22 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP, Proxy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TCPAbridged(TCP):
|
class TCPAbridged(TCP):
|
||||||
def __init__(self, ipv6: bool, proxy: dict):
|
def __init__(self, ipv6: bool, proxy: Proxy) -> None:
|
||||||
super().__init__(ipv6, proxy)
|
super().__init__(ipv6, proxy)
|
||||||
|
|
||||||
async def connect(self, address: tuple):
|
async def connect(self, address: Tuple[str, int]) -> None:
|
||||||
await super().connect(address)
|
await super().connect(address)
|
||||||
await super().send(b"\xef")
|
await super().send(b"\xef")
|
||||||
|
|
||||||
async def send(self, data: bytes, *args):
|
async def send(self, data: bytes, *args) -> None:
|
||||||
length = len(data) // 4
|
length = len(data) // 4
|
||||||
|
|
||||||
await super().send(
|
await super().send(
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from typing import Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram.crypto import aes
|
from pyrogram.crypto import aes
|
||||||
from .tcp import TCP
|
from .tcp import TCP, Proxy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -31,13 +31,13 @@ log = logging.getLogger(__name__)
|
||||||
class TCPAbridgedO(TCP):
|
class TCPAbridgedO(TCP):
|
||||||
RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
|
RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
|
||||||
|
|
||||||
def __init__(self, ipv6: bool, proxy: dict):
|
def __init__(self, ipv6: bool, proxy: Proxy) -> None:
|
||||||
super().__init__(ipv6, proxy)
|
super().__init__(ipv6, proxy)
|
||||||
|
|
||||||
self.encrypt = None
|
self.encrypt = None
|
||||||
self.decrypt = None
|
self.decrypt = None
|
||||||
|
|
||||||
async def connect(self, address: tuple):
|
async def connect(self, address: Tuple[str, int]) -> None:
|
||||||
await super().connect(address)
|
await super().connect(address)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -56,7 +56,7 @@ class TCPAbridgedO(TCP):
|
||||||
|
|
||||||
await super().send(nonce)
|
await super().send(nonce)
|
||||||
|
|
||||||
async def send(self, data: bytes, *args):
|
async def send(self, data: bytes, *args) -> None:
|
||||||
length = len(data) // 4
|
length = len(data) // 4
|
||||||
data = (bytes([length]) if length <= 126 else b"\x7f" + length.to_bytes(3, "little")) + data
|
data = (bytes([length]) if length <= 126 else b"\x7f" + length.to_bytes(3, "little")) + data
|
||||||
payload = await self.loop.run_in_executor(pyrogram.crypto_executor, aes.ctr256_encrypt, data, *self.encrypt)
|
payload = await self.loop.run_in_executor(pyrogram.crypto_executor, aes.ctr256_encrypt, data, *self.encrypt)
|
||||||
|
|
|
||||||
|
|
@ -20,24 +20,24 @@
|
||||||
import logging
|
import logging
|
||||||
from binascii import crc32
|
from binascii import crc32
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from typing import Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP, Proxy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TCPFull(TCP):
|
class TCPFull(TCP):
|
||||||
def __init__(self, ipv6: bool, proxy: dict):
|
def __init__(self, ipv6: bool, proxy: Proxy) -> None:
|
||||||
super().__init__(ipv6, proxy)
|
super().__init__(ipv6, proxy)
|
||||||
|
|
||||||
self.seq_no = None
|
self.seq_no: Optional[int] = None
|
||||||
|
|
||||||
async def connect(self, address: tuple):
|
async def connect(self, address: Tuple[str, int]) -> None:
|
||||||
await super().connect(address)
|
await super().connect(address)
|
||||||
self.seq_no = 0
|
self.seq_no = 0
|
||||||
|
|
||||||
async def send(self, data: bytes, *args):
|
async def send(self, data: bytes, *args) -> None:
|
||||||
data = pack("<II", len(data) + 12, self.seq_no) + data
|
data = pack("<II", len(data) + 12, self.seq_no) + data
|
||||||
data += pack("<I", crc32(data))
|
data += pack("<I", crc32(data))
|
||||||
self.seq_no += 1
|
self.seq_no += 1
|
||||||
|
|
|
||||||
|
|
@ -19,22 +19,22 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from typing import Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP, Proxy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TCPIntermediate(TCP):
|
class TCPIntermediate(TCP):
|
||||||
def __init__(self, ipv6: bool, proxy: dict):
|
def __init__(self, ipv6: bool, proxy: Proxy) -> None:
|
||||||
super().__init__(ipv6, proxy)
|
super().__init__(ipv6, proxy)
|
||||||
|
|
||||||
async def connect(self, address: tuple):
|
async def connect(self, address: Tuple[str, int]) -> None:
|
||||||
await super().connect(address)
|
await super().connect(address)
|
||||||
await super().send(b"\xee" * 4)
|
await super().send(b"\xee" * 4)
|
||||||
|
|
||||||
async def send(self, data: bytes, *args):
|
async def send(self, data: bytes, *args) -> None:
|
||||||
await super().send(pack("<i", len(data)) + data)
|
await super().send(pack("<i", len(data)) + data)
|
||||||
|
|
||||||
async def recv(self, length: int = 0) -> Optional[bytes]:
|
async def recv(self, length: int = 0) -> Optional[bytes]:
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from typing import Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
from pyrogram.crypto import aes
|
from pyrogram.crypto import aes
|
||||||
from .tcp import TCP
|
from .tcp import TCP, Proxy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -31,13 +31,13 @@ log = logging.getLogger(__name__)
|
||||||
class TCPIntermediateO(TCP):
|
class TCPIntermediateO(TCP):
|
||||||
RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
|
RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
|
||||||
|
|
||||||
def __init__(self, ipv6: bool, proxy: dict):
|
def __init__(self, ipv6: bool, proxy: Proxy) -> None:
|
||||||
super().__init__(ipv6, proxy)
|
super().__init__(ipv6, proxy)
|
||||||
|
|
||||||
self.encrypt = None
|
self.encrypt = None
|
||||||
self.decrypt = None
|
self.decrypt = None
|
||||||
|
|
||||||
async def connect(self, address: tuple):
|
async def connect(self, address: Tuple[str, int]) -> None:
|
||||||
await super().connect(address)
|
await super().connect(address)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -56,7 +56,7 @@ class TCPIntermediateO(TCP):
|
||||||
|
|
||||||
await super().send(nonce)
|
await super().send(nonce)
|
||||||
|
|
||||||
async def send(self, data: bytes, *args):
|
async def send(self, data: bytes, *args) -> None:
|
||||||
await super().send(
|
await super().send(
|
||||||
aes.ctr256_encrypt(
|
aes.ctr256_encrypt(
|
||||||
pack("<i", len(data)) + data,
|
pack("<i", len(data)) + data,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ except ImportError:
|
||||||
log.warning(
|
log.warning(
|
||||||
"TgCrypto is missing! "
|
"TgCrypto is missing! "
|
||||||
"Pyrogram will work the same, but at a much slower speed. "
|
"Pyrogram will work the same, but at a much slower speed. "
|
||||||
"More info: https://pyrofork.mayuri.my.id/topics/speedups"
|
"More info: https://pyrofork.wulan17.dev/main/topics/speedups"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ def unpack(
|
||||||
message = Message.read(data)
|
message = Message.read(data)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
if e.args[0] == 0:
|
if e.args[0] == 0:
|
||||||
raise ConnectionError(f"Received empty data. Check your internet connection.")
|
raise ConnectionError("Received empty data. Check your internet connection.")
|
||||||
|
|
||||||
left = data.read().hex()
|
left = data.read().hex()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ def decompose(pq: int) -> int:
|
||||||
while g == 1:
|
while g == 1:
|
||||||
x = y
|
x = y
|
||||||
|
|
||||||
for i in range(r):
|
for _ in range(r):
|
||||||
y = (pow(y, 2, pq) + c) % pq
|
y = (pow(y, 2, pq) + c) % pq
|
||||||
|
|
||||||
k = 0
|
k = 0
|
||||||
|
|
@ -63,7 +63,7 @@ def decompose(pq: int) -> int:
|
||||||
while k < r and g == 1:
|
while k < r and g == 1:
|
||||||
ys = y
|
ys = y
|
||||||
|
|
||||||
for i in range(min(m, r - k)):
|
for _ in range(min(m, r - k)):
|
||||||
y = (pow(y, 2, pq) + c) % pq
|
y = (pow(y, 2, pq) + c) % pq
|
||||||
q = q * (abs(x - y)) % pq
|
q = q * (abs(x - y)) % pq
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ import asyncio
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import errors
|
from pyrogram import raw, types, utils
|
||||||
from pyrogram import utils
|
from pyrogram.handlers.handler import Handler
|
||||||
from pyrogram import raw
|
|
||||||
from pyrogram.handlers import (
|
from pyrogram.handlers import (
|
||||||
BotBusinessConnectHandler,
|
BotBusinessConnectHandler,
|
||||||
BotBusinessMessageHandler,
|
BotBusinessMessageHandler,
|
||||||
|
|
@ -33,6 +33,7 @@ from pyrogram.handlers import (
|
||||||
MessageHandler,
|
MessageHandler,
|
||||||
EditedMessageHandler,
|
EditedMessageHandler,
|
||||||
EditedBotBusinessMessageHandler,
|
EditedBotBusinessMessageHandler,
|
||||||
|
ErrorHandler,
|
||||||
DeletedMessagesHandler,
|
DeletedMessagesHandler,
|
||||||
DeletedBotBusinessMessagesHandler,
|
DeletedBotBusinessMessagesHandler,
|
||||||
MessageReactionUpdatedHandler,
|
MessageReactionUpdatedHandler,
|
||||||
|
|
@ -41,12 +42,14 @@ from pyrogram.handlers import (
|
||||||
RawUpdateHandler,
|
RawUpdateHandler,
|
||||||
InlineQueryHandler,
|
InlineQueryHandler,
|
||||||
PollHandler,
|
PollHandler,
|
||||||
|
ShippingQueryHandler,
|
||||||
PreCheckoutQueryHandler,
|
PreCheckoutQueryHandler,
|
||||||
ConversationHandler,
|
ConversationHandler,
|
||||||
ChosenInlineResultHandler,
|
ChosenInlineResultHandler,
|
||||||
ChatMemberUpdatedHandler,
|
ChatMemberUpdatedHandler,
|
||||||
ChatJoinRequestHandler,
|
ChatJoinRequestHandler,
|
||||||
StoryHandler
|
StoryHandler,
|
||||||
|
PurchasedPaidMediaHandler
|
||||||
)
|
)
|
||||||
from pyrogram.raw.types import (
|
from pyrogram.raw.types import (
|
||||||
UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage,
|
UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage,
|
||||||
|
|
@ -59,7 +62,10 @@ from pyrogram.raw.types import (
|
||||||
UpdateBotInlineSend, UpdateChatParticipant, UpdateChannelParticipant, UpdateBotStopped,
|
UpdateBotInlineSend, UpdateChatParticipant, UpdateChannelParticipant, UpdateBotStopped,
|
||||||
UpdateBotChatInviteRequester, UpdateStory,
|
UpdateBotChatInviteRequester, UpdateStory,
|
||||||
UpdateBotMessageReaction,
|
UpdateBotMessageReaction,
|
||||||
UpdateBotMessageReactions
|
UpdateBotMessageReactions,
|
||||||
|
UpdateBotShippingQuery,
|
||||||
|
UpdateBusinessBotCallbackQuery,
|
||||||
|
UpdateBotPurchasedPaidMedia
|
||||||
)
|
)
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
@ -72,7 +78,7 @@ class Dispatcher:
|
||||||
EDIT_BOT_BUSINESS_MESSAGE_UPDATES = (UpdateBotEditBusinessMessage,)
|
EDIT_BOT_BUSINESS_MESSAGE_UPDATES = (UpdateBotEditBusinessMessage,)
|
||||||
DELETE_MESSAGES_UPDATES = (UpdateDeleteMessages, UpdateDeleteChannelMessages)
|
DELETE_MESSAGES_UPDATES = (UpdateDeleteMessages, UpdateDeleteChannelMessages)
|
||||||
DELETE_BOT_BUSINESS_MESSAGES_UPDATES = (UpdateBotDeleteBusinessMessage,)
|
DELETE_BOT_BUSINESS_MESSAGES_UPDATES = (UpdateBotDeleteBusinessMessage,)
|
||||||
CALLBACK_QUERY_UPDATES = (UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery)
|
CALLBACK_QUERY_UPDATES = (UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery, UpdateBusinessBotCallbackQuery)
|
||||||
CHAT_MEMBER_UPDATES = (UpdateChatParticipant, UpdateChannelParticipant, UpdateBotStopped,)
|
CHAT_MEMBER_UPDATES = (UpdateChatParticipant, UpdateChannelParticipant, UpdateBotStopped,)
|
||||||
USER_STATUS_UPDATES = (UpdateUserStatus,)
|
USER_STATUS_UPDATES = (UpdateUserStatus,)
|
||||||
BOT_INLINE_QUERY_UPDATES = (UpdateBotInlineQuery,)
|
BOT_INLINE_QUERY_UPDATES = (UpdateBotInlineQuery,)
|
||||||
|
|
@ -84,13 +90,21 @@ class Dispatcher:
|
||||||
MESSAGE_BOT_A_REACTION_UPDATES = (UpdateBotMessageReactions,)
|
MESSAGE_BOT_A_REACTION_UPDATES = (UpdateBotMessageReactions,)
|
||||||
BOT_BUSSINESS_CONNECT_UPDATES = (UpdateBotBusinessConnect,)
|
BOT_BUSSINESS_CONNECT_UPDATES = (UpdateBotBusinessConnect,)
|
||||||
PRE_CHECKOUT_QUERY_UPDATES = (UpdateBotPrecheckoutQuery,)
|
PRE_CHECKOUT_QUERY_UPDATES = (UpdateBotPrecheckoutQuery,)
|
||||||
|
SHIPPING_QUERY_UPDATES = (UpdateBotShippingQuery,)
|
||||||
|
PURCHASED_PAID_MEDIA_UPDATES = (UpdateBotPurchasedPaidMedia,)
|
||||||
|
|
||||||
def __init__(self, client: "pyrogram.Client"):
|
def __init__(self, client: "pyrogram.Client"):
|
||||||
self.client = client
|
self.client = client
|
||||||
self.loop = asyncio.get_event_loop()
|
try:
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
self.loop = loop
|
||||||
|
|
||||||
self.handler_worker_tasks = []
|
self.handler_worker_tasks = []
|
||||||
self.locks_list = []
|
self.locks_list = []
|
||||||
|
self.error_handlers = []
|
||||||
|
|
||||||
self.updates_queue = asyncio.Queue()
|
self.updates_queue = asyncio.Queue()
|
||||||
self.groups = OrderedDict()
|
self.groups = OrderedDict()
|
||||||
|
|
@ -167,7 +181,7 @@ class Dispatcher:
|
||||||
|
|
||||||
async def poll_parser(update, users, chats):
|
async def poll_parser(update, users, chats):
|
||||||
return (
|
return (
|
||||||
pyrogram.types.Poll._parse_update(self.client, update),
|
await pyrogram.types.Poll._parse_update(self.client, update, users),
|
||||||
PollHandler
|
PollHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -195,6 +209,12 @@ class Dispatcher:
|
||||||
StoryHandler
|
StoryHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def shipping_query_parser(update, users, chats):
|
||||||
|
return (
|
||||||
|
await pyrogram.types.ShippingQuery._parse(self.client, update, users),
|
||||||
|
ShippingQueryHandler
|
||||||
|
)
|
||||||
|
|
||||||
async def pre_checkout_query_parser(update, users, chats):
|
async def pre_checkout_query_parser(update, users, chats):
|
||||||
return (
|
return (
|
||||||
await pyrogram.types.PreCheckoutQuery._parse(self.client, update, users),
|
await pyrogram.types.PreCheckoutQuery._parse(self.client, update, users),
|
||||||
|
|
@ -219,6 +239,12 @@ class Dispatcher:
|
||||||
BotBusinessConnectHandler
|
BotBusinessConnectHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def purchased_paid_media_parser(update, users, chats):
|
||||||
|
return (
|
||||||
|
pyrogram.types.PurchasedPaidMedia._parse(self.client, update, users),
|
||||||
|
PurchasedPaidMediaHandler
|
||||||
|
)
|
||||||
|
|
||||||
self.update_parsers = {
|
self.update_parsers = {
|
||||||
Dispatcher.NEW_MESSAGE_UPDATES: message_parser,
|
Dispatcher.NEW_MESSAGE_UPDATES: message_parser,
|
||||||
Dispatcher.NEW_BOT_BUSINESS_MESSAGE_UPDATES: bot_business_message_parser,
|
Dispatcher.NEW_BOT_BUSINESS_MESSAGE_UPDATES: bot_business_message_parser,
|
||||||
|
|
@ -234,17 +260,19 @@ class Dispatcher:
|
||||||
Dispatcher.CHAT_MEMBER_UPDATES: chat_member_updated_parser,
|
Dispatcher.CHAT_MEMBER_UPDATES: chat_member_updated_parser,
|
||||||
Dispatcher.CHAT_JOIN_REQUEST_UPDATES: chat_join_request_parser,
|
Dispatcher.CHAT_JOIN_REQUEST_UPDATES: chat_join_request_parser,
|
||||||
Dispatcher.NEW_STORY_UPDATES: story_parser,
|
Dispatcher.NEW_STORY_UPDATES: story_parser,
|
||||||
|
Dispatcher.SHIPPING_QUERY_UPDATES: shipping_query_parser,
|
||||||
Dispatcher.PRE_CHECKOUT_QUERY_UPDATES: pre_checkout_query_parser,
|
Dispatcher.PRE_CHECKOUT_QUERY_UPDATES: pre_checkout_query_parser,
|
||||||
Dispatcher.MESSAGE_BOT_NA_REACTION_UPDATES: message_bot_na_reaction_parser,
|
Dispatcher.MESSAGE_BOT_NA_REACTION_UPDATES: message_bot_na_reaction_parser,
|
||||||
Dispatcher.MESSAGE_BOT_A_REACTION_UPDATES: message_bot_a_reaction_parser,
|
Dispatcher.MESSAGE_BOT_A_REACTION_UPDATES: message_bot_a_reaction_parser,
|
||||||
Dispatcher.BOT_BUSSINESS_CONNECT_UPDATES: bot_business_connect_parser
|
Dispatcher.BOT_BUSSINESS_CONNECT_UPDATES: bot_business_connect_parser,
|
||||||
|
Dispatcher.PURCHASED_PAID_MEDIA_UPDATES: purchased_paid_media_parser
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple}
|
self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple}
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
if not self.client.no_updates:
|
if not self.client.no_updates:
|
||||||
for i in range(self.client.workers):
|
for _ in range(self.client.workers):
|
||||||
self.locks_list.append(asyncio.Lock())
|
self.locks_list.append(asyncio.Lock())
|
||||||
|
|
||||||
self.handler_worker_tasks.append(
|
self.handler_worker_tasks.append(
|
||||||
|
|
@ -254,93 +282,7 @@ class Dispatcher:
|
||||||
log.info("Started %s HandlerTasks", self.client.workers)
|
log.info("Started %s HandlerTasks", self.client.workers)
|
||||||
|
|
||||||
if not self.client.skip_updates:
|
if not self.client.skip_updates:
|
||||||
states = await self.client.storage.update_state()
|
await self.client.recover_gaps()
|
||||||
|
|
||||||
if not states:
|
|
||||||
log.info("No states found, skipping recovery.")
|
|
||||||
return
|
|
||||||
|
|
||||||
message_updates_counter = 0
|
|
||||||
other_updates_counter = 0
|
|
||||||
|
|
||||||
for state in states:
|
|
||||||
id, local_pts, _, local_date, _ = state
|
|
||||||
|
|
||||||
prev_pts = 0
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
diff = await self.client.invoke(
|
|
||||||
raw.functions.updates.GetChannelDifference(
|
|
||||||
channel=await self.client.resolve_peer(id),
|
|
||||||
filter=raw.types.ChannelMessagesFilterEmpty(),
|
|
||||||
pts=local_pts,
|
|
||||||
limit=10000
|
|
||||||
) if id < 0 else
|
|
||||||
raw.functions.updates.GetDifference(
|
|
||||||
pts=local_pts,
|
|
||||||
date=local_date,
|
|
||||||
qts=0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except (errors.ChannelPrivate, errors.ChannelInvalid):
|
|
||||||
break
|
|
||||||
|
|
||||||
if isinstance(diff, raw.types.updates.DifferenceEmpty):
|
|
||||||
break
|
|
||||||
elif isinstance(diff, raw.types.updates.DifferenceTooLong):
|
|
||||||
break
|
|
||||||
elif isinstance(diff, raw.types.updates.Difference):
|
|
||||||
local_pts = diff.state.pts
|
|
||||||
elif isinstance(diff, raw.types.updates.DifferenceSlice):
|
|
||||||
local_pts = diff.intermediate_state.pts
|
|
||||||
local_date = diff.intermediate_state.date
|
|
||||||
|
|
||||||
if prev_pts == local_pts:
|
|
||||||
break
|
|
||||||
|
|
||||||
prev_pts = local_pts
|
|
||||||
elif isinstance(diff, raw.types.updates.ChannelDifferenceEmpty):
|
|
||||||
break
|
|
||||||
elif isinstance(diff, raw.types.updates.ChannelDifferenceTooLong):
|
|
||||||
break
|
|
||||||
elif isinstance(diff, raw.types.updates.ChannelDifference):
|
|
||||||
local_pts = diff.pts
|
|
||||||
|
|
||||||
users = {i.id: i for i in diff.users}
|
|
||||||
chats = {i.id: i for i in diff.chats}
|
|
||||||
|
|
||||||
for message in diff.new_messages:
|
|
||||||
message_updates_counter += 1
|
|
||||||
self.updates_queue.put_nowait(
|
|
||||||
(
|
|
||||||
raw.types.UpdateNewMessage(
|
|
||||||
message=message,
|
|
||||||
pts=local_pts,
|
|
||||||
pts_count=-1
|
|
||||||
) if id == self.client.me.id else
|
|
||||||
raw.types.UpdateNewChannelMessage(
|
|
||||||
message=message,
|
|
||||||
pts=local_pts,
|
|
||||||
pts_count=-1
|
|
||||||
),
|
|
||||||
users,
|
|
||||||
chats
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for update in diff.other_updates:
|
|
||||||
other_updates_counter += 1
|
|
||||||
self.updates_queue.put_nowait(
|
|
||||||
(update, users, chats)
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(diff, (raw.types.updates.Difference, raw.types.updates.ChannelDifference)):
|
|
||||||
break
|
|
||||||
|
|
||||||
await self.client.storage.update_state(id)
|
|
||||||
|
|
||||||
log.info("Recovered %s messages and %s updates.", message_updates_counter, other_updates_counter)
|
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
if not self.client.no_updates:
|
if not self.client.no_updates:
|
||||||
|
|
@ -352,6 +294,7 @@ class Dispatcher:
|
||||||
|
|
||||||
self.handler_worker_tasks.clear()
|
self.handler_worker_tasks.clear()
|
||||||
self.groups.clear()
|
self.groups.clear()
|
||||||
|
self.error_handlers.clear()
|
||||||
|
|
||||||
log.info("Stopped %s HandlerTasks", self.client.workers)
|
log.info("Stopped %s HandlerTasks", self.client.workers)
|
||||||
|
|
||||||
|
|
@ -361,11 +304,14 @@ class Dispatcher:
|
||||||
await lock.acquire()
|
await lock.acquire()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if group not in self.groups:
|
if isinstance(handler, ErrorHandler):
|
||||||
self.groups[group] = []
|
if handler not in self.error_handlers:
|
||||||
self.groups = OrderedDict(sorted(self.groups.items()))
|
self.error_handlers.append(handler)
|
||||||
|
else:
|
||||||
self.groups[group].append(handler)
|
if group not in self.groups:
|
||||||
|
self.groups[group] = []
|
||||||
|
self.groups = OrderedDict(sorted(self.groups.items()))
|
||||||
|
self.groups[group].append(handler)
|
||||||
finally:
|
finally:
|
||||||
for lock in self.locks_list:
|
for lock in self.locks_list:
|
||||||
lock.release()
|
lock.release()
|
||||||
|
|
@ -378,17 +324,23 @@ class Dispatcher:
|
||||||
await lock.acquire()
|
await lock.acquire()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if group not in self.groups:
|
if isinstance(handler, ErrorHandler):
|
||||||
raise ValueError(f"Group {group} does not exist. Handler was not removed.")
|
if handler not in self.error_handlers:
|
||||||
|
raise ValueError(
|
||||||
self.groups[group].remove(handler)
|
f"Error handler {handler} does not exist. Handler was not removed."
|
||||||
|
)
|
||||||
|
self.error_handlers.remove(handler)
|
||||||
|
else:
|
||||||
|
if group not in self.groups:
|
||||||
|
raise ValueError(f"Group {group} does not exist. Handler was not removed.")
|
||||||
|
self.groups[group].remove(handler)
|
||||||
finally:
|
finally:
|
||||||
for lock in self.locks_list:
|
for lock in self.locks_list:
|
||||||
lock.release()
|
lock.release()
|
||||||
|
|
||||||
self.loop.create_task(fn())
|
self.loop.create_task(fn())
|
||||||
|
|
||||||
async def handler_worker(self, lock):
|
async def handler_worker(self, lock: asyncio.Lock):
|
||||||
while True:
|
while True:
|
||||||
packet = await self.updates_queue.get()
|
packet = await self.updates_queue.get()
|
||||||
|
|
||||||
|
|
@ -396,53 +348,91 @@ class Dispatcher:
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
update, users, chats = packet
|
await self._handle_packet(packet, lock)
|
||||||
parser = self.update_parsers.get(type(update), None)
|
|
||||||
|
|
||||||
parsed_update, handler_type = (
|
|
||||||
await parser(update, users, chats)
|
|
||||||
if parser is not None
|
|
||||||
else (None, type(None))
|
|
||||||
)
|
|
||||||
|
|
||||||
async with lock:
|
|
||||||
for group in self.groups.values():
|
|
||||||
for handler in group:
|
|
||||||
args = None
|
|
||||||
|
|
||||||
if isinstance(handler, handler_type):
|
|
||||||
try:
|
|
||||||
if await handler.check(self.client, parsed_update):
|
|
||||||
args = (parsed_update,)
|
|
||||||
except Exception as e:
|
|
||||||
log.exception(e)
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif isinstance(handler, RawUpdateHandler):
|
|
||||||
args = (update, users, chats)
|
|
||||||
|
|
||||||
if args is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
if inspect.iscoroutinefunction(handler.callback):
|
|
||||||
await handler.callback(self.client, *args)
|
|
||||||
else:
|
|
||||||
await self.loop.run_in_executor(
|
|
||||||
self.client.executor,
|
|
||||||
handler.callback,
|
|
||||||
self.client,
|
|
||||||
*args
|
|
||||||
)
|
|
||||||
except pyrogram.StopPropagation:
|
|
||||||
raise
|
|
||||||
except pyrogram.ContinuePropagation:
|
|
||||||
continue
|
|
||||||
except Exception as e:
|
|
||||||
log.exception(e)
|
|
||||||
|
|
||||||
break
|
|
||||||
except pyrogram.StopPropagation:
|
except pyrogram.StopPropagation:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
finally:
|
||||||
|
self.updates_queue.task_done()
|
||||||
|
|
||||||
|
async def _handle_packet(self, packet, lock: asyncio.Lock):
|
||||||
|
update, users, chats = packet
|
||||||
|
parser = self.update_parsers.get(type(update))
|
||||||
|
|
||||||
|
parsed_update, handler_type = (
|
||||||
|
await parser(update, users, chats)
|
||||||
|
if parser is not None else (None, type(None))
|
||||||
|
)
|
||||||
|
async with lock:
|
||||||
|
await self._dispatch_to_handlers(update, users, chats, parsed_update, handler_type)
|
||||||
|
|
||||||
|
|
||||||
|
async def _dispatch_to_handlers(
|
||||||
|
self, update, users, chats, parsed_update, handler_type,
|
||||||
|
):
|
||||||
|
for group in self.groups.values():
|
||||||
|
for handler in group:
|
||||||
|
args = await self._match_handler(
|
||||||
|
handler, update, users, chats, parsed_update, handler_type,
|
||||||
|
)
|
||||||
|
if args is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
await self._execute_handler(handler, *args)
|
||||||
|
except pyrogram.StopPropagation:
|
||||||
|
raise
|
||||||
|
except pyrogram.ContinuePropagation:
|
||||||
|
continue
|
||||||
|
except Exception as error:
|
||||||
|
if parsed_update is not None:
|
||||||
|
await self._handle_exception(parsed_update, error)
|
||||||
|
break
|
||||||
|
|
||||||
|
async def _match_handler(
|
||||||
|
self, handler, update, users, chats, parsed_update, handler_type,
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
if isinstance(handler, handler_type):
|
||||||
|
if await handler.check(self.client, parsed_update):
|
||||||
|
return (parsed_update,)
|
||||||
|
elif isinstance(handler, RawUpdateHandler):
|
||||||
|
if await handler.check(self.client, update):
|
||||||
|
return (update, users, chats)
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(e)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def _execute_handler(self, handler, *args: Any):
|
||||||
|
if inspect.iscoroutinefunction(handler.callback):
|
||||||
|
await handler.callback(self.client, *args)
|
||||||
|
else:
|
||||||
|
await self.loop.run_in_executor(
|
||||||
|
self.client.executor,
|
||||||
|
handler.callback,
|
||||||
|
self.client,
|
||||||
|
*args
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _handle_exception(
|
||||||
|
self, parsed_update: types.Update, exception: Exception,
|
||||||
|
):
|
||||||
|
handled_error = False
|
||||||
|
for error_handler in self.error_handlers:
|
||||||
|
try:
|
||||||
|
if await error_handler.check(
|
||||||
|
self.client, parsed_update, exception,
|
||||||
|
):
|
||||||
|
handled_error = True
|
||||||
|
break
|
||||||
|
except pyrogram.StopPropagation:
|
||||||
|
raise
|
||||||
|
except pyrogram.ContinuePropagation:
|
||||||
|
continue
|
||||||
|
except Exception as inner_exception:
|
||||||
|
log.exception("Error in error handler: %s", inner_exception)
|
||||||
|
|
||||||
|
if not handled_error:
|
||||||
|
log.exception("Unhandled exception: %s", exception)
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,18 @@
|
||||||
from .business_schedule import BusinessSchedule
|
from .business_schedule import BusinessSchedule
|
||||||
from .chat_action import ChatAction
|
from .chat_action import ChatAction
|
||||||
from .chat_event_action import ChatEventAction
|
from .chat_event_action import ChatEventAction
|
||||||
|
from .chat_join_type import ChatJoinType
|
||||||
from .chat_member_status import ChatMemberStatus
|
from .chat_member_status import ChatMemberStatus
|
||||||
from .chat_members_filter import ChatMembersFilter
|
from .chat_members_filter import ChatMembersFilter
|
||||||
from .chat_type import ChatType
|
from .chat_type import ChatType
|
||||||
from .client_platform import ClientPlatform
|
from .client_platform import ClientPlatform
|
||||||
|
from .folder_color import FolderColor
|
||||||
|
from .gift_attribute_type import GiftAttributeType
|
||||||
|
from .gift_for_resale_order import GiftForResaleOrder
|
||||||
from .listerner_types import ListenerTypes
|
from .listerner_types import ListenerTypes
|
||||||
from .message_entity_type import MessageEntityType
|
from .message_entity_type import MessageEntityType
|
||||||
from .message_media_type import MessageMediaType
|
from .message_media_type import MessageMediaType
|
||||||
|
from .message_origin_type import MessageOriginType
|
||||||
from .message_service_type import MessageServiceType
|
from .message_service_type import MessageServiceType
|
||||||
from .messages_filter import MessagesFilter
|
from .messages_filter import MessagesFilter
|
||||||
from .next_code_type import NextCodeType
|
from .next_code_type import NextCodeType
|
||||||
|
|
@ -44,13 +49,18 @@ __all__ = [
|
||||||
'BusinessSchedule',
|
'BusinessSchedule',
|
||||||
'ChatAction',
|
'ChatAction',
|
||||||
'ChatEventAction',
|
'ChatEventAction',
|
||||||
|
'ChatJoinType',
|
||||||
'ChatMemberStatus',
|
'ChatMemberStatus',
|
||||||
'ChatMembersFilter',
|
'ChatMembersFilter',
|
||||||
'ChatType',
|
'ChatType',
|
||||||
'ClientPlatform',
|
'ClientPlatform',
|
||||||
|
'FolderColor',
|
||||||
|
'GiftAttributeType',
|
||||||
|
'GiftForResaleOrder',
|
||||||
'ListenerTypes',
|
'ListenerTypes',
|
||||||
'MessageEntityType',
|
'MessageEntityType',
|
||||||
'MessageMediaType',
|
'MessageMediaType',
|
||||||
|
'MessageOriginType',
|
||||||
'MessageServiceType',
|
'MessageServiceType',
|
||||||
'MessagesFilter',
|
'MessagesFilter',
|
||||||
'NextCodeType',
|
'NextCodeType',
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,13 @@ class ChatEventAction(AutoName):
|
||||||
"The linked chat has been changed (see ``old_linked_chat`` and ``new_linked_chat``)"
|
"The linked chat has been changed (see ``old_linked_chat`` and ``new_linked_chat``)"
|
||||||
|
|
||||||
# LOCATION_CHANGED = auto()
|
# LOCATION_CHANGED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
PHOTO_CHANGED = auto()
|
PHOTO_CHANGED = auto()
|
||||||
"The chat photo has been changed (see ``old_photo`` and ``new_photo``)"
|
"The chat photo has been changed (see ``old_photo`` and ``new_photo``)"
|
||||||
|
|
||||||
# STICKER_SET_CHANGED = auto()
|
# STICKER_SET_CHANGED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
TITLE_CHANGED = auto()
|
TITLE_CHANGED = auto()
|
||||||
"the chat title has been changed (see ``old_title`` and ``new_title``)"
|
"the chat title has been changed (see ``old_title`` and ``new_title``)"
|
||||||
|
|
@ -56,7 +56,7 @@ class ChatEventAction(AutoName):
|
||||||
"a message has been deleted (see ``deleted_message``)"
|
"a message has been deleted (see ``deleted_message``)"
|
||||||
|
|
||||||
# VOICE_CHAT_DISCARDED = auto()
|
# VOICE_CHAT_DISCARDED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
MESSAGE_EDITED = auto()
|
MESSAGE_EDITED = auto()
|
||||||
"a message has been edited (see ``old_message`` and ``new_message``)"
|
"a message has been edited (see ``old_message`` and ``new_message``)"
|
||||||
|
|
@ -77,13 +77,13 @@ class ChatEventAction(AutoName):
|
||||||
"a member joined by themselves. (see ``user``)"
|
"a member joined by themselves. (see ``user``)"
|
||||||
|
|
||||||
# MEMBER_JOINED_BY_LINK = auto()
|
# MEMBER_JOINED_BY_LINK = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
MEMBER_LEFT = auto()
|
MEMBER_LEFT = auto()
|
||||||
"a member left by themselves. (see ``user``)"
|
"a member left by themselves. (see ``user``)"
|
||||||
|
|
||||||
# MEMBER_MUTED = auto()
|
# MEMBER_MUTED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
ADMINISTRATOR_PRIVILEGES_CHANGED = auto()
|
ADMINISTRATOR_PRIVILEGES_CHANGED = auto()
|
||||||
"a chat member has been promoted/demoted or their administrator privileges has changed (see ``old_administrator_privileges`` and ``new_administrator_privileges``)"
|
"a chat member has been promoted/demoted or their administrator privileges has changed (see ``old_administrator_privileges`` and ``new_administrator_privileges``)"
|
||||||
|
|
@ -92,19 +92,19 @@ class ChatEventAction(AutoName):
|
||||||
"a chat member has been restricted/unrestricted or banned/unbanned, or their permissions has changed (see ``old_member_permissions`` and ``new_member_permissions``)"
|
"a chat member has been restricted/unrestricted or banned/unbanned, or their permissions has changed (see ``old_member_permissions`` and ``new_member_permissions``)"
|
||||||
|
|
||||||
# MEMBER_UNMUTED = auto()
|
# MEMBER_UNMUTED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
# MEMBER_VOLUME_CHANGED = auto()
|
# MEMBER_VOLUME_CHANGED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
# VIDEO_CHAT_STARTED = auto()
|
# VIDEO_CHAT_STARTED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
POLL_STOPPED = auto()
|
POLL_STOPPED = auto()
|
||||||
"a poll has been stopped (see ``stopped_poll``)"
|
"a poll has been stopped (see ``stopped_poll``)"
|
||||||
|
|
||||||
# VOICE_CHAT_SETTINGS_CHANGED = auto()
|
# VOICE_CHAT_SETTINGS_CHANGED = auto()
|
||||||
""
|
# ""
|
||||||
|
|
||||||
INVITES_ENABLED = auto()
|
INVITES_ENABLED = auto()
|
||||||
"the chat invitation has been enabled or disabled (see ``invites_enabled``)"
|
"the chat invitation has been enabled or disabled (see ``invites_enabled``)"
|
||||||
|
|
|
||||||
34
pyrogram/enums/chat_join_type.py
Normal file
34
pyrogram/enums/chat_join_type.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
from .auto_name import AutoName
|
||||||
|
|
||||||
|
|
||||||
|
class ChatJoinType(AutoName):
|
||||||
|
"""How the service message :obj:`~pyrogram.enums.MessageServiceType.NEW_CHAT_MEMBERS` was used for the member to join the chat."""
|
||||||
|
|
||||||
|
BY_ADD = auto()
|
||||||
|
"A new member joined the chat via an invite link"
|
||||||
|
|
||||||
|
BY_LINK = auto()
|
||||||
|
"A new member joined the chat via an invite link"
|
||||||
|
|
||||||
|
BY_REQUEST = auto()
|
||||||
|
"A new member was accepted to the chat by an administrator"
|
||||||
|
|
@ -39,3 +39,9 @@ class ChatType(AutoName):
|
||||||
|
|
||||||
CHANNEL = auto()
|
CHANNEL = auto()
|
||||||
"Chat is a channel"
|
"Chat is a channel"
|
||||||
|
|
||||||
|
FORUM = auto()
|
||||||
|
"Chat is a forum"
|
||||||
|
|
||||||
|
MONOFORUM = auto()
|
||||||
|
"Chat is a monoforum"
|
||||||
|
|
|
||||||
47
pyrogram/enums/folder_color.py
Normal file
47
pyrogram/enums/folder_color.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .auto_name import AutoName
|
||||||
|
|
||||||
|
|
||||||
|
class FolderColor(AutoName):
|
||||||
|
"""Folder color enumeration used in :obj:`~pyrogram.types.Folder`."""
|
||||||
|
|
||||||
|
NO_COLOR = None
|
||||||
|
"No color."
|
||||||
|
|
||||||
|
RED = 0
|
||||||
|
"Red color."
|
||||||
|
|
||||||
|
ORANGE = 1
|
||||||
|
"Orange color."
|
||||||
|
|
||||||
|
VIOLET = 2
|
||||||
|
"Violet color."
|
||||||
|
|
||||||
|
GREEN = 3
|
||||||
|
"Green color."
|
||||||
|
|
||||||
|
CYAN = 4
|
||||||
|
"Cyan color."
|
||||||
|
|
||||||
|
BLUE = 5
|
||||||
|
"Blue color."
|
||||||
|
|
||||||
|
PINK = 6
|
||||||
|
"Pink color."
|
||||||
36
pyrogram/enums/gift_attribute_type.py
Normal file
36
pyrogram/enums/gift_attribute_type.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram import raw
|
||||||
|
from .auto_name import AutoName
|
||||||
|
|
||||||
|
|
||||||
|
class GiftAttributeType(AutoName):
|
||||||
|
"""Star gift attribute type enumeration used in :obj:`~pyrogram.types.GiftAttribute`."""
|
||||||
|
|
||||||
|
MODEL = raw.types.StarGiftAttributeModel
|
||||||
|
"Model attribute"
|
||||||
|
|
||||||
|
SYMBOL = raw.types.StarGiftAttributePattern
|
||||||
|
"Symbol attribute"
|
||||||
|
|
||||||
|
BACKDROP = raw.types.StarGiftAttributeBackdrop
|
||||||
|
"Backdrop attribute"
|
||||||
|
|
||||||
|
ORIGINAL_DETAILS = raw.types.StarGiftAttributeOriginalDetails
|
||||||
|
"Original details attribute"
|
||||||
35
pyrogram/enums/gift_for_resale_order.py
Normal file
35
pyrogram/enums/gift_for_resale_order.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
from .auto_name import AutoName
|
||||||
|
|
||||||
|
|
||||||
|
class GiftForResaleOrder(AutoName):
|
||||||
|
"""Describes order in which upgraded gifts for resale will be sorted. Used in :meth:`~pyrogram.Client.search_gifts_for_resale`."""
|
||||||
|
|
||||||
|
PRICE = auto()
|
||||||
|
"The gifts will be sorted by their price from the lowest to the highest"
|
||||||
|
|
||||||
|
CHANGE_DATE = auto()
|
||||||
|
"The gifts will be sorted by the last date when their price was changed from the newest to the oldest"
|
||||||
|
|
||||||
|
NUMBER = auto()
|
||||||
|
"The gifts will be sorted by their number from the smallest to the largest"
|
||||||
|
|
@ -81,3 +81,9 @@ class MessageMediaType(AutoName):
|
||||||
|
|
||||||
INVOICE = auto()
|
INVOICE = auto()
|
||||||
"Invoice media"
|
"Invoice media"
|
||||||
|
|
||||||
|
PAID_MEDIA = auto()
|
||||||
|
"Paid media"
|
||||||
|
|
||||||
|
TODO = auto()
|
||||||
|
"To-Do list media"
|
||||||
|
|
|
||||||
42
pyrogram/enums/message_origin_type.py
Normal file
42
pyrogram/enums/message_origin_type.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
from .auto_name import AutoName
|
||||||
|
|
||||||
|
|
||||||
|
class MessageOriginType(AutoName):
|
||||||
|
"""Message origin type enumeration used in :obj:`~pyrogram.types.MessageOrigin`."""
|
||||||
|
|
||||||
|
CHANNEL = auto()
|
||||||
|
"The message was originally a post in a channel"
|
||||||
|
|
||||||
|
CHAT = auto()
|
||||||
|
"The message was originally sent on behalf of a chat"
|
||||||
|
|
||||||
|
HIDDEN_USER = auto()
|
||||||
|
"The message was originally sent by a user, which is hidden by their privacy settings"
|
||||||
|
|
||||||
|
IMPORT = auto()
|
||||||
|
"The message was imported from a foreign chat service"
|
||||||
|
|
||||||
|
|
||||||
|
USER = auto()
|
||||||
|
"The message was originally sent by a known user"
|
||||||
|
|
@ -28,9 +28,6 @@ class MessageServiceType(AutoName):
|
||||||
NEW_CHAT_MEMBERS = auto()
|
NEW_CHAT_MEMBERS = auto()
|
||||||
"New members join"
|
"New members join"
|
||||||
|
|
||||||
CHAT_JOINED_BY_REQUEST = auto()
|
|
||||||
"a member chat join request approved by admin."
|
|
||||||
|
|
||||||
LEFT_CHAT_MEMBERS = auto()
|
LEFT_CHAT_MEMBERS = auto()
|
||||||
"Left chat members"
|
"Left chat members"
|
||||||
|
|
||||||
|
|
@ -61,11 +58,8 @@ class MessageServiceType(AutoName):
|
||||||
GAME_HIGH_SCORE = auto()
|
GAME_HIGH_SCORE = auto()
|
||||||
"Game high score"
|
"Game high score"
|
||||||
|
|
||||||
ChannelShared = auto()
|
CHAT_SHARED = auto()
|
||||||
"a shared chat/channel"
|
"a shared chat/channel/user"
|
||||||
|
|
||||||
UserShared = auto()
|
|
||||||
"a shared user"
|
|
||||||
|
|
||||||
FORUM_TOPIC_CREATED = auto()
|
FORUM_TOPIC_CREATED = auto()
|
||||||
"a new forum topic created in the chat"
|
"a new forum topic created in the chat"
|
||||||
|
|
@ -114,3 +108,36 @@ class MessageServiceType(AutoName):
|
||||||
|
|
||||||
SUCCESSFUL_PAYMENT = auto()
|
SUCCESSFUL_PAYMENT = auto()
|
||||||
"Successful payment"
|
"Successful payment"
|
||||||
|
|
||||||
|
PAYMENT_REFUNDED = auto()
|
||||||
|
"Payment refunded"
|
||||||
|
|
||||||
|
BOT_ALLOWED = auto()
|
||||||
|
"Bot allowed"
|
||||||
|
|
||||||
|
CHAT_THEME_UPDATED = auto()
|
||||||
|
"Chat theme updated"
|
||||||
|
|
||||||
|
CHAT_WALLPAPER_UPDATED = auto()
|
||||||
|
"Chat wallpaper updated"
|
||||||
|
|
||||||
|
CONTACT_REGISTERED = auto()
|
||||||
|
"Contact registered"
|
||||||
|
|
||||||
|
GIFT_CODE = auto()
|
||||||
|
"Gift code"
|
||||||
|
|
||||||
|
GIFT = auto()
|
||||||
|
"Star gift"
|
||||||
|
|
||||||
|
SCREENSHOT_TAKEN = auto()
|
||||||
|
"Screenshot taken"
|
||||||
|
|
||||||
|
PAID_MESSAGE_PRICE_CHANGED = auto()
|
||||||
|
"Paid message price changed"
|
||||||
|
|
||||||
|
TODO_TASKS_ADDED = auto()
|
||||||
|
"To-Do tasks added"
|
||||||
|
|
||||||
|
TODO_TASKS_COMPLETION = auto()
|
||||||
|
"To-Do tasks completion/incompletion"
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,6 @@ class ReactionType(AutoName):
|
||||||
|
|
||||||
CUSTOM_EMOJI = auto()
|
CUSTOM_EMOJI = auto()
|
||||||
"""Custom emoji reaction type."""
|
"""Custom emoji reaction type."""
|
||||||
|
|
||||||
|
PAID = auto()
|
||||||
|
"""Paid reaction type."""
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,15 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .exceptions import *
|
EXCEPTION_AVAIL = False
|
||||||
|
try:
|
||||||
|
from .exceptions import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
EXCEPTION_AVAIL = True
|
||||||
from .pyromod import *
|
from .pyromod import *
|
||||||
from .rpc_error import UnknownError
|
from .rpc_error import RPCError, UnknownError
|
||||||
|
|
||||||
|
|
||||||
class BadMsgNotification(Exception):
|
class BadMsgNotification(Exception):
|
||||||
|
|
@ -65,3 +71,15 @@ class CDNFileHashMismatch(SecurityError):
|
||||||
|
|
||||||
def __init__(self, msg: str = None):
|
def __init__(self, msg: str = None):
|
||||||
super().__init__("A CDN file hash mismatch has occurred." if msg is None else msg)
|
super().__init__("A CDN file hash mismatch has occurred." if msg is None else msg)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"BadMsgNotification",
|
||||||
|
"SecurityError",
|
||||||
|
"SecurityCheckMismatch",
|
||||||
|
"CDNFileHashMismatch",
|
||||||
|
"RPCError",
|
||||||
|
"UnknownError"
|
||||||
|
]
|
||||||
|
if EXCEPTION_AVAIL:
|
||||||
|
__all__.extend(exceptions.__all__)
|
||||||
|
__all__.extend(pyromod.__all__)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ from datetime import datetime
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from typing import Type, Union
|
from typing import Type, Union
|
||||||
|
|
||||||
from pyrogram import raw
|
from pyrogram import __version__, raw
|
||||||
from pyrogram.raw.core import TLObject
|
from pyrogram.raw.core import TLObject
|
||||||
from .exceptions.all import exceptions
|
from .exceptions.all import exceptions
|
||||||
|
|
||||||
|
|
@ -40,12 +40,13 @@ class RPCError(Exception):
|
||||||
is_unknown: bool = False,
|
is_unknown: bool = False,
|
||||||
is_signed: bool = False
|
is_signed: bool = False
|
||||||
):
|
):
|
||||||
super().__init__("Telegram says: [{}{} {}] - {} {}".format(
|
super().__init__("Telegram says: [{}{} {}] {} Pyrogram {} thinks: {}".format(
|
||||||
"-" if is_signed else "",
|
"-" if is_signed else "",
|
||||||
self.CODE,
|
self.CODE,
|
||||||
self.ID or self.NAME,
|
self.ID or self.NAME,
|
||||||
|
f'(caused by "{rpc_name}")' if rpc_name else "",
|
||||||
|
__version__,
|
||||||
self.MESSAGE.format(value=value),
|
self.MESSAGE.format(value=value),
|
||||||
f'(caused by "{rpc_name}")' if rpc_name else ""
|
|
||||||
))
|
))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
|
@ -250,7 +251,7 @@ react = create(reaction_filter)
|
||||||
|
|
||||||
# region forwarded_filter
|
# region forwarded_filter
|
||||||
async def forwarded_filter(_, __, m: Message):
|
async def forwarded_filter(_, __, m: Message):
|
||||||
return bool(m.forward_date)
|
return bool(m.forward_origin)
|
||||||
|
|
||||||
|
|
||||||
forwarded = create(forwarded_filter)
|
forwarded = create(forwarded_filter)
|
||||||
|
|
@ -337,6 +338,34 @@ game = create(game_filter)
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
# region giveaway_filter
|
||||||
|
async def giveaway_filter(_, __, m: Message):
|
||||||
|
return bool(m.giveaway)
|
||||||
|
giveaway = create(giveaway_filter)
|
||||||
|
"""Filter messages that contain :obj:`~pyrogram.types.Giveaway` objects."""
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region giveaway_result_filter
|
||||||
|
async def giveaway_result_filter(_, __, m: Message):
|
||||||
|
return bool(m.giveaway_winners or m.giveaway_completed)
|
||||||
|
giveaway_result = create(giveaway_result_filter)
|
||||||
|
"""Filter messages that contain :obj:`~pyrogram.types.GiveawayWinners` or :obj:`~pyrogram.types.GiveawayCompleted` objects."""
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region gift_code_filter
|
||||||
|
async def gift_code_filter(_, __, m: Message):
|
||||||
|
return bool(m.gift_code)
|
||||||
|
gift_code = create(gift_code_filter)
|
||||||
|
"""Filter messages that contain :obj:`~pyrogram.types.GiftCode` objects."""
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region star_gift_filter
|
||||||
|
async def star_gift_filter(_, __, m: Message):
|
||||||
|
return bool(m.gift)
|
||||||
|
star_gift = create(star_gift_filter)
|
||||||
|
"""Filter messages that contain :obj:`~pyrogram.types.Gift` objects."""
|
||||||
|
# endregion
|
||||||
|
|
||||||
# region video_filter
|
# region video_filter
|
||||||
async def video_filter(_, __, m: Message):
|
async def video_filter(_, __, m: Message):
|
||||||
return bool(m.video)
|
return bool(m.video)
|
||||||
|
|
@ -767,7 +796,7 @@ from_scheduled = create(from_scheduled_filter)
|
||||||
|
|
||||||
# region linked_channel_filter
|
# region linked_channel_filter
|
||||||
async def linked_channel_filter(_, __, m: Message):
|
async def linked_channel_filter(_, __, m: Message):
|
||||||
return bool(m.forward_from_chat and not m.from_user)
|
return bool((m.forward_origin and m.forward_origin.chat) and not m.from_user)
|
||||||
|
|
||||||
|
|
||||||
linked_channel = create(linked_channel_filter)
|
linked_channel = create(linked_channel_filter)
|
||||||
|
|
@ -861,7 +890,12 @@ def command(commands: Union[str, List[str]], prefixes: Union[str, List[str]] = "
|
||||||
command_re = re.compile(r"([\"'])(.*?)(?<!\\)\1|(\S+)")
|
command_re = re.compile(r"([\"'])(.*?)(?<!\\)\1|(\S+)")
|
||||||
|
|
||||||
async def func(flt, client: pyrogram.Client, message: Message):
|
async def func(flt, client: pyrogram.Client, message: Message):
|
||||||
|
usernames = []
|
||||||
username = client.me.username or ""
|
username = client.me.username or ""
|
||||||
|
if client.me.usernames:
|
||||||
|
usernames.append(username)
|
||||||
|
for user in client.me.usernames:
|
||||||
|
usernames.append(user.username)
|
||||||
text = message.text or message.caption
|
text = message.text or message.caption
|
||||||
message.command = None
|
message.command = None
|
||||||
|
|
||||||
|
|
@ -875,6 +909,24 @@ def command(commands: Union[str, List[str]], prefixes: Union[str, List[str]] = "
|
||||||
without_prefix = text[len(prefix):]
|
without_prefix = text[len(prefix):]
|
||||||
|
|
||||||
for cmd in flt.commands:
|
for cmd in flt.commands:
|
||||||
|
if usernames:
|
||||||
|
for username in usernames:
|
||||||
|
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
|
||||||
|
flags=re.IGNORECASE if not flt.case_sensitive else 0):
|
||||||
|
continue
|
||||||
|
|
||||||
|
without_command = re.sub(rf"{cmd}(?:@?{username})?\s?", "", without_prefix, count=1,
|
||||||
|
flags=re.IGNORECASE if not flt.case_sensitive else 0)
|
||||||
|
|
||||||
|
# match.groups are 1-indexed, group(1) is the quote, group(2) is the text
|
||||||
|
# between the quotes, group(3) is unquoted, whitespace-split text
|
||||||
|
|
||||||
|
# Remove the escape character from the arguments
|
||||||
|
message.command = [cmd] + [
|
||||||
|
re.sub(r"\\([\"'])", r"\1", m.group(2) or m.group(3) or "")
|
||||||
|
for m in command_re.finditer(without_command)
|
||||||
|
]
|
||||||
|
return True
|
||||||
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
|
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
|
||||||
flags=re.IGNORECASE if not flt.case_sensitive else 0):
|
flags=re.IGNORECASE if not flt.case_sensitive else 0):
|
||||||
continue
|
continue
|
||||||
|
|
@ -982,12 +1034,22 @@ class user(Filter, set):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def __call__(self, _, message: Message):
|
async def __call__(self, _, message: Message):
|
||||||
|
is_usernames_in_filters = False
|
||||||
|
if message.from_user and message.from_user.usernames:
|
||||||
|
for username in message.from_user.usernames:
|
||||||
|
if (
|
||||||
|
username.username in self
|
||||||
|
or username.username.lower() in self
|
||||||
|
):
|
||||||
|
is_usernames_in_filters = True
|
||||||
|
break
|
||||||
return (message.from_user
|
return (message.from_user
|
||||||
and (message.from_user.id in self
|
and (message.from_user.id in self
|
||||||
or (message.from_user.username
|
or (message.from_user.username
|
||||||
and message.from_user.username.lower() in self)
|
and message.from_user.username.lower() in self)
|
||||||
or ("me" in self
|
or ("me" in self
|
||||||
and message.from_user.is_self)))
|
and message.from_user.is_self))
|
||||||
|
or is_usernames_in_filters)
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
|
|
@ -1015,6 +1077,15 @@ class chat(Filter, set):
|
||||||
|
|
||||||
async def __call__(self, _, message: Union[Message, Story]):
|
async def __call__(self, _, message: Union[Message, Story]):
|
||||||
if isinstance(message, Story):
|
if isinstance(message, Story):
|
||||||
|
is_usernames_in_filters = False
|
||||||
|
if message.sender_chat and message.sender_chat.usernames:
|
||||||
|
for username in message.sender_chat.usernames:
|
||||||
|
if (
|
||||||
|
username.username in self
|
||||||
|
or username.username.lower() in self
|
||||||
|
):
|
||||||
|
is_usernames_in_filters = True
|
||||||
|
break
|
||||||
return (
|
return (
|
||||||
message.sender_chat
|
message.sender_chat
|
||||||
and (
|
and (
|
||||||
|
|
@ -1033,8 +1104,17 @@ class chat(Filter, set):
|
||||||
and message.from_user.username.lower() in self
|
and message.from_user.username.lower() in self
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
) or is_usernames_in_filters
|
||||||
else:
|
else:
|
||||||
|
is_usernames_in_filters = False
|
||||||
|
if message.chat and message.chat.usernames:
|
||||||
|
for username in message.chat.usernames:
|
||||||
|
if (
|
||||||
|
username.username in self
|
||||||
|
or username.username.lower() in self
|
||||||
|
):
|
||||||
|
is_usernames_in_filters = True
|
||||||
|
break
|
||||||
return (message.chat
|
return (message.chat
|
||||||
and (message.chat.id in self
|
and (message.chat.id in self
|
||||||
or (message.chat.username
|
or (message.chat.username
|
||||||
|
|
@ -1042,7 +1122,10 @@ class chat(Filter, set):
|
||||||
or ("me" in self
|
or ("me" in self
|
||||||
and message.from_user
|
and message.from_user
|
||||||
and message.from_user.is_self
|
and message.from_user.is_self
|
||||||
and not message.outgoing)))
|
and not message.outgoing))
|
||||||
|
or (is_usernames_in_filters
|
||||||
|
and not message.outgoing)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
|
|
@ -1053,6 +1136,7 @@ class topic(Filter, set):
|
||||||
Parameters:
|
Parameters:
|
||||||
topics (``int`` | ``list``):
|
topics (``int`` | ``list``):
|
||||||
Pass one or more topic ids to filter messages in specific topics.
|
Pass one or more topic ids to filter messages in specific topics.
|
||||||
|
Pass 1 for general topic.
|
||||||
Defaults to None (no topics).
|
Defaults to None (no topics).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -1064,4 +1148,6 @@ class topic(Filter, set):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def __call__(self, _, message: Message):
|
async def __call__(self, _, message: Message):
|
||||||
|
if message.is_topic_message and not message.topic:
|
||||||
|
return 1 in self
|
||||||
return message.topic and message.topic.id in self
|
return message.topic and message.topic.id in self
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,43 @@ from .deleted_bot_business_messages_handler import DeletedBotBusinessMessagesHan
|
||||||
from .disconnect_handler import DisconnectHandler
|
from .disconnect_handler import DisconnectHandler
|
||||||
from .edited_message_handler import EditedMessageHandler
|
from .edited_message_handler import EditedMessageHandler
|
||||||
from .edited_bot_business_message_handler import EditedBotBusinessMessageHandler
|
from .edited_bot_business_message_handler import EditedBotBusinessMessageHandler
|
||||||
|
from .error_handler import ErrorHandler
|
||||||
from .inline_query_handler import InlineQueryHandler
|
from .inline_query_handler import InlineQueryHandler
|
||||||
from .message_handler import MessageHandler
|
from .message_handler import MessageHandler
|
||||||
from .poll_handler import PollHandler
|
from .poll_handler import PollHandler
|
||||||
from .pre_checkout_query_handler import PreCheckoutQueryHandler
|
from .purchased_paid_media_handler import PurchasedPaidMediaHandler
|
||||||
from .raw_update_handler import RawUpdateHandler
|
from .raw_update_handler import RawUpdateHandler
|
||||||
from .user_status_handler import UserStatusHandler
|
from .user_status_handler import UserStatusHandler
|
||||||
from .story_handler import StoryHandler
|
from .story_handler import StoryHandler
|
||||||
from .message_reaction_updated_handler import MessageReactionUpdatedHandler
|
from .message_reaction_updated_handler import MessageReactionUpdatedHandler
|
||||||
from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler
|
from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler
|
||||||
|
from .pre_checkout_query_handler import PreCheckoutQueryHandler
|
||||||
|
from .shipping_query_handler import ShippingQueryHandler
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"BotBusinessConnectHandler",
|
||||||
|
"BotBusinessMessageHandler",
|
||||||
|
"CallbackQueryHandler",
|
||||||
|
"ChatJoinRequestHandler",
|
||||||
|
"ChatMemberUpdatedHandler",
|
||||||
|
"ConversationHandler",
|
||||||
|
"ChosenInlineResultHandler",
|
||||||
|
"DeletedMessagesHandler",
|
||||||
|
"DeletedBotBusinessMessagesHandler",
|
||||||
|
"DisconnectHandler",
|
||||||
|
"EditedMessageHandler",
|
||||||
|
"EditedBotBusinessMessageHandler",
|
||||||
|
"ErrorHandler",
|
||||||
|
"InlineQueryHandler",
|
||||||
|
"MessageHandler",
|
||||||
|
"PollHandler",
|
||||||
|
"PreCheckoutQueryHandler",
|
||||||
|
"PurchasedPaidMediaHandler",
|
||||||
|
"RawUpdateHandler",
|
||||||
|
"UserStatusHandler",
|
||||||
|
"StoryHandler",
|
||||||
|
"MessageReactionUpdatedHandler",
|
||||||
|
"MessageReactionCountUpdatedHandler",
|
||||||
|
"PreCheckoutQueryHandler",
|
||||||
|
"ShippingQueryHandler",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ class ConversationHandler(MessageHandler, CallbackQueryHandler):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
# pylint: disable=method-hidden
|
||||||
async def callback(_, __):
|
async def callback(_, __):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,5 +58,4 @@ class DeletedBotBusinessMessagesHandler(Handler):
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if await super().check(client, message):
|
if await super().check(client, message):
|
||||||
return True
|
return True
|
||||||
else:
|
return False
|
||||||
return False
|
|
||||||
|
|
|
||||||
|
|
@ -58,5 +58,4 @@ class DeletedMessagesHandler(Handler):
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if await super().check(client, message):
|
if await super().check(client, message):
|
||||||
return True
|
return True
|
||||||
else:
|
return False
|
||||||
return False
|
|
||||||
|
|
|
||||||
79
pyrogram/handlers/error_handler.py
Normal file
79
pyrogram/handlers/error_handler.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from .handler import Handler
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram.types import Update
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorHandler(Handler):
|
||||||
|
"""The Error handler class. Used to handle errors.
|
||||||
|
It is intended to be used with :meth:`~pyrogram.Client.add_handler`
|
||||||
|
|
||||||
|
For a nicer way to register this handler, have a look at the
|
||||||
|
:meth:`~pyrogram.Client.on_error` decorator.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
callback (``Callable``):
|
||||||
|
Pass a function that will be called when a new Error arrives. It takes *(client, error)*
|
||||||
|
as positional arguments (look at the section below for a detailed description).
|
||||||
|
|
||||||
|
exceptions (``Exception`` | Iterable of ``Exception``, *optional*):
|
||||||
|
Pass one or more exception classes to allow only a subset of errors to be passed
|
||||||
|
in your callback function.
|
||||||
|
|
||||||
|
Other parameters:
|
||||||
|
client (:obj:`~pyrogram.Client`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the error handler.
|
||||||
|
|
||||||
|
update (:obj:`~pyrogram.Update`):
|
||||||
|
The update that caused the error.
|
||||||
|
|
||||||
|
error (``Exception``):
|
||||||
|
The error that was raised.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
callback: Callable,
|
||||||
|
exceptions: type[Exception] | Iterable[type[Exception]] | None = None,
|
||||||
|
):
|
||||||
|
self.exceptions = (
|
||||||
|
tuple(exceptions)
|
||||||
|
if isinstance(exceptions, Iterable)
|
||||||
|
else (exceptions,)
|
||||||
|
if exceptions
|
||||||
|
else (Exception,)
|
||||||
|
)
|
||||||
|
super().__init__(callback)
|
||||||
|
|
||||||
|
async def check(self, client: pyrogram.Client, update: Update, exception: Exception) -> bool:
|
||||||
|
if isinstance(exception, self.exceptions):
|
||||||
|
await self.callback(client, update, exception)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_remove(self, error: type[Exception] | Iterable[type[Exception]]) -> bool:
|
||||||
|
return isinstance(error, self.exceptions)
|
||||||
|
|
@ -62,6 +62,9 @@ class MessageHandler(Handler):
|
||||||
:return: A tuple of whether the message has a matching listener and its filters does match with the Message
|
:return: A tuple of whether the message has a matching listener and its filters does match with the Message
|
||||||
and the matching listener;
|
and the matching listener;
|
||||||
"""
|
"""
|
||||||
|
chat = message.chat
|
||||||
|
chat_id = chat.id if chat else None
|
||||||
|
chat_username = chat.username if chat else None
|
||||||
from_user = message.from_user
|
from_user = message.from_user
|
||||||
from_user_id = from_user.id if from_user else None
|
from_user_id = from_user.id if from_user else None
|
||||||
from_user_username = from_user.username if from_user else None
|
from_user_username = from_user.username if from_user else None
|
||||||
|
|
@ -70,7 +73,7 @@ class MessageHandler(Handler):
|
||||||
|
|
||||||
data = Identifier(
|
data = Identifier(
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
chat_id=[message.chat.id, message.chat.username],
|
chat_id=[chat_id, chat_username],
|
||||||
from_user_id=[from_user_id, from_user_username],
|
from_user_id=[from_user_id, from_user_username],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -102,7 +105,7 @@ class MessageHandler(Handler):
|
||||||
"""
|
"""
|
||||||
listener_does_match = (
|
listener_does_match = (
|
||||||
await self.check_if_has_matching_listener(client, message)
|
await self.check_if_has_matching_listener(client, message)
|
||||||
)[0] if message.chat is not None and message.from_user is not None else False
|
)[0]
|
||||||
|
|
||||||
if callable(self.filters):
|
if callable(self.filters):
|
||||||
if iscoroutinefunction(self.filters.__call__):
|
if iscoroutinefunction(self.filters.__call__):
|
||||||
|
|
@ -129,7 +132,7 @@ class MessageHandler(Handler):
|
||||||
"""
|
"""
|
||||||
listener_does_match, listener = await self.check_if_has_matching_listener(
|
listener_does_match, listener = await self.check_if_has_matching_listener(
|
||||||
client, message
|
client, message
|
||||||
) if message.chat is not None and message.from_user is not None else False, None
|
)
|
||||||
|
|
||||||
if listener and listener_does_match:
|
if listener and listener_does_match:
|
||||||
client.remove_listener(listener)
|
client.remove_listener(listener)
|
||||||
|
|
@ -148,4 +151,4 @@ class MessageHandler(Handler):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Listener must have either a future or a callback")
|
raise ValueError("Listener must have either a future or a callback")
|
||||||
else:
|
else:
|
||||||
await self.original_callback(client, message, *args)
|
await self.original_callback(client, message, *args)
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ class PreCheckoutQueryHandler(Handler):
|
||||||
The Client itself, useful when you want to call other API methods inside the message handler.
|
The Client itself, useful when you want to call other API methods inside the message handler.
|
||||||
|
|
||||||
pre_checkout_query (:obj:`~pyrogram.types.PreCheckoutQuery`):
|
pre_checkout_query (:obj:`~pyrogram.types.PreCheckoutQuery`):
|
||||||
The received callback query.
|
New incoming pre-checkout query. Contains full information about checkout.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, callback: Callable, filters=None):
|
def __init__(self, callback: Callable, filters=None):
|
||||||
|
|
|
||||||
49
pyrogram/handlers/purchased_paid_media_handler.py
Normal file
49
pyrogram/handlers/purchased_paid_media_handler.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from .handler import Handler
|
||||||
|
|
||||||
|
|
||||||
|
class PurchasedPaidMediaHandler(Handler):
|
||||||
|
"""The PurchasedPaidMedia handler class. Used to handle purchased paid medias.
|
||||||
|
It is intended to be used with :meth:`~pyrogram.Client.add_handler`
|
||||||
|
|
||||||
|
For a nicer way to register this handler, have a look at the
|
||||||
|
:meth:`~pyrogram.Client.on_purchased_paid_media` decorator.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
callback (``Callable``):
|
||||||
|
Pass a function that will be called when a paid media purchased. It takes *(client, update)*
|
||||||
|
as positional arguments (look at the section below for a detailed description).
|
||||||
|
|
||||||
|
filters (:obj:`Filters`):
|
||||||
|
Pass one or more filters to allow only a subset of updates to be passed
|
||||||
|
in your callback function.
|
||||||
|
|
||||||
|
Other parameters:
|
||||||
|
client (:obj:`~pyrogram.Client`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the handler.
|
||||||
|
|
||||||
|
update (:obj:`~pyrogram.types.PurchasedPaidMedia`):
|
||||||
|
Information about who bought paid media.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, callback: Callable, filters=None):
|
||||||
|
super().__init__(callback, filters)
|
||||||
|
|
@ -35,6 +35,10 @@ class RawUpdateHandler(Handler):
|
||||||
*(client, update, users, chats)* as positional arguments (look at the section below for
|
*(client, update, users, chats)* as positional arguments (look at the section below for
|
||||||
a detailed description).
|
a detailed description).
|
||||||
|
|
||||||
|
filters (:obj:`Filters`):
|
||||||
|
Pass one or more filters to allow only a subset of callback queries to be passed
|
||||||
|
in your callback function.
|
||||||
|
|
||||||
Other Parameters:
|
Other Parameters:
|
||||||
client (:obj:`~pyrogram.Client`):
|
client (:obj:`~pyrogram.Client`):
|
||||||
The Client itself, useful when you want to call other API methods inside the update handler.
|
The Client itself, useful when you want to call other API methods inside the update handler.
|
||||||
|
|
@ -64,5 +68,5 @@ class RawUpdateHandler(Handler):
|
||||||
- :obj:`~pyrogram.raw.types.ChannelForbidden`
|
- :obj:`~pyrogram.raw.types.ChannelForbidden`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, callback: Callable):
|
def __init__(self, callback: Callable, filters=None):
|
||||||
super().__init__(callback)
|
super().__init__(callback, filters)
|
||||||
|
|
|
||||||
51
pyrogram/handlers/shipping_query_handler.py
Normal file
51
pyrogram/handlers/shipping_query_handler.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from .handler import Handler
|
||||||
|
|
||||||
|
|
||||||
|
class ShippingQueryHandler(Handler):
|
||||||
|
"""The ShippingQueryHandler handler class. Used to handle shipping queries coming only from invoice buttons with flexible price.
|
||||||
|
|
||||||
|
It is intended to be used with :meth:`~pyrogram.Client.add_handler`
|
||||||
|
|
||||||
|
For a nicer way to register this handler, have a look at the
|
||||||
|
:meth:`~pyrogram.Client.on_shipping_query` decorator.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
callback (``Callable``):
|
||||||
|
Pass a function that will be called when a new PreCheckoutQuery arrives. It takes *(client, shipping_query)*
|
||||||
|
as positional arguments (look at the section below for a detailed description).
|
||||||
|
|
||||||
|
filters (:obj:`Filters`):
|
||||||
|
Pass one or more filters to allow only a subset of callback queries to be passed
|
||||||
|
in your callback function.
|
||||||
|
|
||||||
|
Other parameters:
|
||||||
|
client (:obj:`~pyrogram.Client`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the message handler.
|
||||||
|
|
||||||
|
shipping_query (:obj:`~pyrogram.types.ShippingQuery`):
|
||||||
|
New incoming shipping query. Only for invoices with flexible price.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, callback: Callable, filters=None):
|
||||||
|
super().__init__(callback, filters)
|
||||||
|
|
@ -13,4 +13,15 @@ GNU General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
from .helpers import ikb, bki, ntb, btn, kb, kbtn, array_chunk, force_reply
|
from .helpers import ikb, bki, ntb, btn, kb, kbtn, array_chunk, force_reply
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ikb",
|
||||||
|
"bki",
|
||||||
|
"ntb",
|
||||||
|
"btn",
|
||||||
|
"kb",
|
||||||
|
"kbtn",
|
||||||
|
"array_chunk",
|
||||||
|
"force_reply"
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -101,9 +101,9 @@ def kb(rows=None, **kwargs):
|
||||||
line = []
|
line = []
|
||||||
for button in row:
|
for button in row:
|
||||||
button_type = type(button)
|
button_type = type(button)
|
||||||
if button_type == str:
|
if isinstance(button_type, str):
|
||||||
button = KeyboardButton(button)
|
button = KeyboardButton(button)
|
||||||
elif button_type == dict:
|
elif isinstance(button_type, dict):
|
||||||
button = KeyboardButton(**button)
|
button = KeyboardButton(**button)
|
||||||
|
|
||||||
line.append(button)
|
line.append(button)
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,17 @@ from .bots import Bots
|
||||||
from .chats import Chats
|
from .chats import Chats
|
||||||
from .contacts import Contacts
|
from .contacts import Contacts
|
||||||
from .decorators import Decorators
|
from .decorators import Decorators
|
||||||
|
from .forums import Forums
|
||||||
from .invite_links import InviteLinks
|
from .invite_links import InviteLinks
|
||||||
from .messages import Messages
|
from .messages import Messages
|
||||||
from .password import Password
|
from .password import Password
|
||||||
from .pyromod import Pyromod
|
from .pyromod import Pyromod
|
||||||
from .stickers import Stickers
|
from .stickers import Stickers
|
||||||
|
from .payments import Payments
|
||||||
|
from .phone import Phone
|
||||||
from .users import Users
|
from .users import Users
|
||||||
from .utilities import Utilities
|
from .utilities import Utilities
|
||||||
|
from .business import TelegramBusiness
|
||||||
|
|
||||||
|
|
||||||
class Methods(
|
class Methods(
|
||||||
|
|
@ -39,12 +43,16 @@ class Methods(
|
||||||
Contacts,
|
Contacts,
|
||||||
Password,
|
Password,
|
||||||
Pyromod,
|
Pyromod,
|
||||||
|
Payments,
|
||||||
|
Phone,
|
||||||
Chats,
|
Chats,
|
||||||
|
Forums,
|
||||||
Stickers,
|
Stickers,
|
||||||
Users,
|
Users,
|
||||||
Messages,
|
Messages,
|
||||||
Decorators,
|
Decorators,
|
||||||
Utilities,
|
Utilities,
|
||||||
InviteLinks,
|
InviteLinks,
|
||||||
|
TelegramBusiness,
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import inspect
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import os
|
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import Union, BinaryIO, Callable
|
from typing import Union, BinaryIO, Callable
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .accept_terms_of_service import AcceptTermsOfService
|
|
||||||
from .check_password import CheckPassword
|
from .check_password import CheckPassword
|
||||||
from .connect import Connect
|
from .connect import Connect
|
||||||
from .disconnect import Disconnect
|
from .disconnect import Disconnect
|
||||||
|
from .get_active_sessions import GetActiveSessions
|
||||||
from .get_password_hint import GetPasswordHint
|
from .get_password_hint import GetPasswordHint
|
||||||
from .initialize import Initialize
|
from .initialize import Initialize
|
||||||
from .log_out import LogOut
|
from .log_out import LogOut
|
||||||
|
|
@ -30,15 +30,15 @@ from .send_code import SendCode
|
||||||
from .send_recovery_code import SendRecoveryCode
|
from .send_recovery_code import SendRecoveryCode
|
||||||
from .sign_in import SignIn
|
from .sign_in import SignIn
|
||||||
from .sign_in_bot import SignInBot
|
from .sign_in_bot import SignInBot
|
||||||
from .sign_up import SignUp
|
from .sign_in_qrcode import SignInQrcode
|
||||||
from .terminate import Terminate
|
from .terminate import Terminate
|
||||||
|
|
||||||
|
|
||||||
class Auth(
|
class Auth(
|
||||||
AcceptTermsOfService,
|
|
||||||
CheckPassword,
|
CheckPassword,
|
||||||
Connect,
|
Connect,
|
||||||
Disconnect,
|
Disconnect,
|
||||||
|
GetActiveSessions,
|
||||||
GetPasswordHint,
|
GetPasswordHint,
|
||||||
Initialize,
|
Initialize,
|
||||||
LogOut,
|
LogOut,
|
||||||
|
|
@ -48,7 +48,7 @@ class Auth(
|
||||||
SendRecoveryCode,
|
SendRecoveryCode,
|
||||||
SignIn,
|
SignIn,
|
||||||
SignInBot,
|
SignInBot,
|
||||||
SignUp,
|
SignInQrcode,
|
||||||
Terminate
|
Terminate
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ class Connect:
|
||||||
Raises:
|
Raises:
|
||||||
ConnectionError: In case you try to connect an already connected client.
|
ConnectionError: In case you try to connect an already connected client.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
if self.is_connected:
|
if self.is_connected:
|
||||||
raise ConnectionError("Client is already connected")
|
raise ConnectionError("Client is already connected")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ class Disconnect:
|
||||||
ConnectionError: In case you try to disconnect an already disconnected client or in case you try to
|
ConnectionError: In case you try to disconnect an already disconnected client or in case you try to
|
||||||
disconnect a client that needs to be terminated first.
|
disconnect a client that needs to be terminated first.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise ConnectionError("Client is already disconnected")
|
raise ConnectionError("Client is already disconnected")
|
||||||
|
|
||||||
|
|
|
||||||
38
pyrogram/methods/auth/get_active_sessions.py
Normal file
38
pyrogram/methods/auth/get_active_sessions.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw, types
|
||||||
|
|
||||||
|
|
||||||
|
class GetActiveSessions:
|
||||||
|
async def get_active_sessions(
|
||||||
|
self: "pyrogram.Client"
|
||||||
|
) -> "types.ActiveSessions":
|
||||||
|
"""Returns all active sessions of the current user.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`~pyrogram.types.ActiveSessions`: On success, all the active sessions of the current user is returned.
|
||||||
|
|
||||||
|
"""
|
||||||
|
r = await self.invoke(
|
||||||
|
raw.functions.account.GetAuthorizations()
|
||||||
|
)
|
||||||
|
return types.ActiveSessions._parse(r)
|
||||||
|
|
@ -41,6 +41,7 @@ class Initialize:
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise ConnectionError("Can't initialize a disconnected client")
|
raise ConnectionError("Can't initialize a disconnected client")
|
||||||
|
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
if self.is_initialized:
|
if self.is_initialized:
|
||||||
raise ConnectionError("Client is already initialized")
|
raise ConnectionError("Client is already initialized")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ class SendCode:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except (PhoneMigrate, NetworkMigrate) as e:
|
except (PhoneMigrate, NetworkMigrate) as e:
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
await self.session.stop()
|
await self.session.stop()
|
||||||
|
|
||||||
await self.storage.dc_id(e.value)
|
await self.storage.dc_id(e.value)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ from typing import Union
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
from pyrogram import types
|
from pyrogram import types
|
||||||
|
from pyrogram.errors import PhoneNumberUnoccupied
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -49,15 +50,13 @@ class SignIn:
|
||||||
The valid confirmation code you received (either as Telegram message or as SMS in your phone number).
|
The valid confirmation code you received (either as Telegram message or as SMS in your phone number).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`~pyrogram.types.User` | :obj:`~pyrogram.types.TermsOfService` | bool: On success, in case the
|
:obj:`~pyrogram.types.User` | bool: On success, in case the
|
||||||
authorization completed, the user is returned. In case the phone number needs to be registered first AND the
|
authorization completed, the user is returned.
|
||||||
terms of services accepted (with :meth:`~pyrogram.Client.accept_terms_of_service`), an object containing
|
|
||||||
them is returned. In case the phone number needs to be registered, but the terms of services don't need to
|
|
||||||
be accepted, False is returned instead.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
BadRequest: In case the arguments are invalid.
|
BadRequest: In case the arguments are invalid.
|
||||||
SessionPasswordNeeded: In case a password is needed to sign in.
|
SessionPasswordNeeded: In case a password is needed to sign in.
|
||||||
|
PhoneNumberUnoccupied: In case the phone number is not registered on Telegram.
|
||||||
"""
|
"""
|
||||||
phone_number = phone_number.strip(" +")
|
phone_number = phone_number.strip(" +")
|
||||||
|
|
||||||
|
|
@ -70,10 +69,7 @@ class SignIn:
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(r, raw.types.auth.AuthorizationSignUpRequired):
|
if isinstance(r, raw.types.auth.AuthorizationSignUpRequired):
|
||||||
if r.terms_of_service:
|
raise PhoneNumberUnoccupied("The phone number is not registered on Telegram. Please use official Telegram app to register it.")
|
||||||
return types.TermsOfService._parse(terms_of_service=r.terms_of_service)
|
|
||||||
|
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
await self.storage.user_id(r.user.id)
|
await self.storage.user_id(r.user.id)
|
||||||
await self.storage.is_bot(False)
|
await self.storage.is_bot(False)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ class SignInBot:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except UserMigrate as e:
|
except UserMigrate as e:
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
await self.session.stop()
|
await self.session.stop()
|
||||||
|
|
||||||
await self.storage.dc_id(e.value)
|
await self.storage.dc_id(e.value)
|
||||||
|
|
|
||||||
111
pyrogram/methods/auth/sign_in_qrcode.py
Normal file
111
pyrogram/methods/auth/sign_in_qrcode.py
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# 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 logging
|
||||||
|
from base64 import b64encode
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
|
from pyrogram.session import Session, Auth
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class SignInQrcode:
|
||||||
|
async def sign_in_qrcode(
|
||||||
|
self: "pyrogram.Client"
|
||||||
|
) -> Union["types.User", "types.LoginToken"]:
|
||||||
|
"""Authorize a user in Telegram with a QR code.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`~pyrogram.types.User` | :obj:`pyrogram.types.LoginToken`, in case the
|
||||||
|
authorization completed, the user is returned. In case the QR code is
|
||||||
|
not scanned, a login token is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ImportError: In case the qrcode library is not installed.
|
||||||
|
SessionPasswordNeeded: In case a password is needed to sign in.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
import qrcode
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("qrcode is missing! "
|
||||||
|
"Please install it with `pip install qrcode`")
|
||||||
|
r = await self.session.invoke(
|
||||||
|
raw.functions.auth.ExportLoginToken(
|
||||||
|
api_id=self.api_id,
|
||||||
|
api_hash=self.api_hash,
|
||||||
|
except_ids=[]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if isinstance(r, raw.types.auth.LoginToken):
|
||||||
|
base64_token = b64encode(r.token).decode("utf-8")
|
||||||
|
login_url = f"tg://login?token={base64_token}"
|
||||||
|
qr = qrcode.QRCode(
|
||||||
|
version=1,
|
||||||
|
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
||||||
|
box_size=10,
|
||||||
|
border=4,
|
||||||
|
)
|
||||||
|
qr.add_data(login_url)
|
||||||
|
qr.make(fit=True)
|
||||||
|
|
||||||
|
print("Scan the QR code with your Telegram app.")
|
||||||
|
qr.print_ascii()
|
||||||
|
|
||||||
|
return types.LoginToken._parse(r)
|
||||||
|
if isinstance(r, raw.types.auth.LoginTokenSuccess):
|
||||||
|
await self.storage.user_id(r.authorization.user.id)
|
||||||
|
await self.storage.is_bot(False)
|
||||||
|
|
||||||
|
return types.User._parse(self, r.authorization.user)
|
||||||
|
if isinstance(r, raw.types.auth.LoginTokenMigrateTo):
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
|
await self.session.stop()
|
||||||
|
|
||||||
|
await self.storage.dc_id(r.dc_id)
|
||||||
|
await self.storage.auth_key(
|
||||||
|
await Auth(
|
||||||
|
self, await self.storage.dc_id(),
|
||||||
|
await self.storage.test_mode()
|
||||||
|
).create()
|
||||||
|
)
|
||||||
|
self.session = Session(
|
||||||
|
self, await self.storage.dc_id(),
|
||||||
|
await self.storage.auth_key(), await self.storage.test_mode()
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.session.start()
|
||||||
|
r = await self.session.invoke(
|
||||||
|
raw.functions.auth.ImportLoginToken(
|
||||||
|
token=r.token
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if isinstance(r, raw.types.auth.LoginTokenSuccess):
|
||||||
|
await self.storage.user_id(r.authorization.user.id)
|
||||||
|
await self.storage.is_bot(False)
|
||||||
|
|
||||||
|
return types.User._parse(self, r.authorization.user)
|
||||||
|
raise pyrogram.exceptions.RPCError(
|
||||||
|
"Unknown response type from Telegram API"
|
||||||
|
)
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# 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 logging
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
from pyrogram import types
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class SignUp:
|
|
||||||
async def sign_up(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
phone_number: str,
|
|
||||||
phone_code_hash: str,
|
|
||||||
first_name: str,
|
|
||||||
last_name: str = ""
|
|
||||||
) -> "types.User":
|
|
||||||
"""Register a new user in Telegram.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
phone_number (``str``):
|
|
||||||
Phone number in international format (includes the country prefix).
|
|
||||||
|
|
||||||
phone_code_hash (``str``):
|
|
||||||
Code identifier taken from the result of :meth:`~pyrogram.Client.send_code`.
|
|
||||||
|
|
||||||
first_name (``str``):
|
|
||||||
New user first name.
|
|
||||||
|
|
||||||
last_name (``str``, *optional*):
|
|
||||||
New user last name. Defaults to "" (empty string, no last name).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`~pyrogram.types.User`: On success, the new registered user is returned.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
BadRequest: In case the arguments are invalid.
|
|
||||||
"""
|
|
||||||
phone_number = phone_number.strip(" +")
|
|
||||||
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.auth.SignUp(
|
|
||||||
phone_number=phone_number,
|
|
||||||
first_name=first_name,
|
|
||||||
last_name=last_name,
|
|
||||||
phone_code_hash=phone_code_hash
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.storage.user_id(r.user.id)
|
|
||||||
await self.storage.is_bot(False)
|
|
||||||
|
|
||||||
return types.User._parse(self, r.user)
|
|
||||||
|
|
@ -37,6 +37,7 @@ class Terminate:
|
||||||
Raises:
|
Raises:
|
||||||
ConnectionError: In case you try to terminate a client that is already terminated.
|
ConnectionError: In case you try to terminate a client that is already terminated.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=access-member-before-definition
|
||||||
if not self.is_initialized:
|
if not self.is_initialized:
|
||||||
raise ConnectionError("Client is already terminated")
|
raise ConnectionError("Client is already terminated")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
from .answer_callback_query import AnswerCallbackQuery
|
from .answer_callback_query import AnswerCallbackQuery
|
||||||
from .answer_inline_query import AnswerInlineQuery
|
from .answer_inline_query import AnswerInlineQuery
|
||||||
from .answer_pre_checkout_query import AnswerPreCheckoutQuery
|
|
||||||
from .answer_web_app_query import AnswerWebAppQuery
|
from .answer_web_app_query import AnswerWebAppQuery
|
||||||
from .delete_bot_commands import DeleteBotCommands
|
from .delete_bot_commands import DeleteBotCommands
|
||||||
from .get_bot_commands import GetBotCommands
|
from .get_bot_commands import GetBotCommands
|
||||||
|
|
@ -37,6 +36,8 @@ from .set_bot_default_privileges import SetBotDefaultPrivileges
|
||||||
from .set_bot_info import SetBotInfo
|
from .set_bot_info import SetBotInfo
|
||||||
from .set_chat_menu_button import SetChatMenuButton
|
from .set_chat_menu_button import SetChatMenuButton
|
||||||
from .set_game_score import SetGameScore
|
from .set_game_score import SetGameScore
|
||||||
|
from .get_owned_bots import GetOwnedBots
|
||||||
|
from .get_similar_bots import GetSimilarBots
|
||||||
|
|
||||||
|
|
||||||
class Bots(
|
class Bots(
|
||||||
|
|
@ -58,7 +59,8 @@ class Bots(
|
||||||
SetChatMenuButton,
|
SetChatMenuButton,
|
||||||
GetChatMenuButton,
|
GetChatMenuButton,
|
||||||
AnswerWebAppQuery,
|
AnswerWebAppQuery,
|
||||||
AnswerPreCheckoutQuery,
|
GetCollectibleItemInfo,
|
||||||
GetCollectibleItemInfo
|
GetOwnedBots,
|
||||||
|
GetSimilarBots,
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -28,17 +28,24 @@ class GetCollectibleItemInfo:
|
||||||
phone_number: str = None
|
phone_number: str = None
|
||||||
) -> "types.CollectibleInfo":
|
) -> "types.CollectibleInfo":
|
||||||
"""Returns information about a given collectible item that was purchased at https://fragment.com
|
"""Returns information about a given collectible item that was purchased at https://fragment.com
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
You must use exactly one of ``username`` OR ``phone_number``.
|
You must use exactly one of ``username`` OR ``phone_number``.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
username (``str``, *optional*):
|
username (``str``, *optional*):
|
||||||
Describes a collectible username that can be purchased at https://fragment.com
|
Describes a collectible username that can be purchased at https://fragment.com
|
||||||
|
|
||||||
phone_number (``str``, *optional*):
|
phone_number (``str``, *optional*):
|
||||||
Describes a collectible phone number that can be purchased at https://fragment.com
|
Describes a collectible phone number that can be purchased at https://fragment.com
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`~pyrogram.types.CollectibleInfo`: On success, a collectible info is returned.
|
:obj:`~pyrogram.types.CollectibleInfo`: On success, a collectible info is returned.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
username = await app.get_collectible_item_info(username="nerd")
|
username = await app.get_collectible_item_info(username="nerd")
|
||||||
print(username)
|
print(username)
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
46
pyrogram/methods/bots/get_owned_bots.py
Normal file
46
pyrogram/methods/bots/get_owned_bots.py
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw, types
|
||||||
|
|
||||||
|
|
||||||
|
class GetOwnedBots:
|
||||||
|
async def get_owned_bots(
|
||||||
|
self: "pyrogram.Client",
|
||||||
|
) -> List["types.User"]:
|
||||||
|
"""Returns the list of bots owned by the current user.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of :obj:`~pyrogram.types.User`: On success.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
bots = await app.get_owned_bots()
|
||||||
|
"""
|
||||||
|
|
||||||
|
bots = await self.invoke(raw.functions.bots.GetAdminedBots())
|
||||||
|
return types.List([
|
||||||
|
types.User._parse(self, b)
|
||||||
|
for b in bots
|
||||||
|
])
|
||||||
46
pyrogram/methods/bots/get_similar_bots.py
Normal file
46
pyrogram/methods/bots/get_similar_bots.py
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
from typing import List, Union
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw
|
||||||
|
|
||||||
|
|
||||||
|
class GetSimilarBots:
|
||||||
|
async def get_similar_bots(
|
||||||
|
self: "pyrogram.Client",
|
||||||
|
bot: Union[int, str]
|
||||||
|
) -> List["pyrogram.types.User"]:
|
||||||
|
"""Get a list of bots similar to the target bot.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
bot (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target bot.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of :obj:`~pyrogram.types.User`: On success.
|
||||||
|
"""
|
||||||
|
peer = await self.resolve_peer(bot)
|
||||||
|
r = await self.invoke(raw.functions.bots.GetBotRecommendations(bot=peer))
|
||||||
|
return pyrogram.types.List([
|
||||||
|
pyrogram.types.User._parse(self, u)
|
||||||
|
for u in r.users
|
||||||
|
])
|
||||||
|
|
@ -34,6 +34,7 @@ class SendGame:
|
||||||
business_connection_id: str = None,
|
business_connection_id: str = None,
|
||||||
reply_to_message_id: int = None,
|
reply_to_message_id: int = None,
|
||||||
protect_content: bool = None,
|
protect_content: bool = None,
|
||||||
|
allow_paid_broadcast: bool = None,
|
||||||
message_effect_id: int = None,
|
message_effect_id: int = None,
|
||||||
reply_markup: Union[
|
reply_markup: Union[
|
||||||
"types.InlineKeyboardMarkup",
|
"types.InlineKeyboardMarkup",
|
||||||
|
|
@ -74,6 +75,9 @@ class SendGame:
|
||||||
protect_content (``bool``, *optional*):
|
protect_content (``bool``, *optional*):
|
||||||
Protects the contents of the sent message from forwarding and saving.
|
Protects the contents of the sent message from forwarding and saving.
|
||||||
|
|
||||||
|
allow_paid_broadcast (``bool``, *optional*):
|
||||||
|
Pass True to allow the message to ignore regular broadcast limits for a small fee; for bots only
|
||||||
|
|
||||||
message_effect_id (``int`` ``64-bit``, *optional*):
|
message_effect_id (``int`` ``64-bit``, *optional*):
|
||||||
Unique identifier of the message effect to be added to the message; for private chats only.
|
Unique identifier of the message effect to be added to the message; for private chats only.
|
||||||
|
|
||||||
|
|
@ -109,6 +113,7 @@ class SendGame:
|
||||||
reply_to=reply_to,
|
reply_to=reply_to,
|
||||||
random_id=self.rnd_id(),
|
random_id=self.rnd_id(),
|
||||||
noforwards=protect_content,
|
noforwards=protect_content,
|
||||||
|
allow_paid_floodskip=allow_paid_broadcast,
|
||||||
effect=message_effect_id,
|
effect=message_effect_id,
|
||||||
reply_markup=await reply_markup.write(self) if reply_markup else None
|
reply_markup=await reply_markup.write(self) if reply_markup else None
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue