Compare commits
492 Commits
Author | SHA1 | Date |
---|---|---|
_run | e10517e088 | |
Artin GH | 1946393c36 | |
Badiboy | 0f52ca688f | |
Badiboy | b18bcd494a | |
Badiboy | 8f41df0ee4 | |
Kourva | cb7f6a8c99 | |
_run | 3960115ec7 | |
_run | 916569cdc5 | |
_run | 75d3fa2eba | |
_run | 67e3774e8e | |
_run | f799157314 | |
coder2020official | af3a98057f | |
_run | 447fc1d461 | |
_run | fb98df3dfe | |
Badiboy | 0b34da3900 | |
Artem Lukin | 5ea1abaadd | |
Badiboy | 5a81353420 | |
dependabot[bot] | eaf90cce7f | |
Badiboy | b219218c8d | |
Badiboy | 2dac17aa75 | |
Badiboy | 48377ac905 | |
Alexey Isaev | 14294d1aa3 | |
_run | ea3c159044 | |
AmirW | 58d53e1a54 | |
Badiboy | abec3dc60e | |
coder2020official | ecb5d9b4f6 | |
coder2020official | 26575dc5e7 | |
coder2020official | be69feb252 | |
coder2020official | 1d62adc262 | |
coder2020official | 77e1928628 | |
coder2020official | d6f4987197 | |
coder2020official | 966b451869 | |
coder2020official | d1417e5616 | |
_run | a7cafd1f24 | |
Badiboy | 92907ced30 | |
Badiboy | 1b2ed0e2f7 | |
_run | 370f0370c7 | |
Cub11k | e4bddd91cb | |
Cub11k | d466da3542 | |
Badiboy | e64c06b7bc | |
Badiboy | 7d168ebbd8 | |
Francisco Griman | c5689f383b | |
Francisco Griman | 8796168efb | |
_run | 100659fecd | |
_run | 7bf87a306a | |
_run | 351d021e01 | |
Badiboy | 4ffe0f8833 | |
Badiboy | 3f07dc4ce8 | |
Badiboy | 2e589ab6e1 | |
Badiboy | 8b63f6a6ef | |
Badiboy | dc98aca173 | |
Badiboy | 39360e0640 | |
Badiboy | b1c172c421 | |
Badiboy | 6b5c263ee8 | |
Badiboy | 46100edd97 | |
Badiboy | 018b89cdc0 | |
Badiboy | f3486b3730 | |
Badiboy | b0e64d828c | |
Badiboy | 14434b398e | |
_run | 1d62bf2ac8 | |
Badiboy | fe2e9a7a30 | |
Badiboy | c9ef0d71f0 | |
Badiboy | b0740a920a | |
Badiboy | 6a9c25cf80 | |
Badiboy | e56c60ac00 | |
Badiboy | 7c7a063fb6 | |
Mike Lei | bd69492ed4 | |
C̷̱̺͙͓̪͔̹͉͉̯̖̟̀͆́̽̔̈̚͠͝o̶̥̻̻̖̮͚͒̂̒͌̾̇͗͘͝d̸̢̡͈̮̦͈͙̖͔̦̭̩̰͎͉̣̰͆̈́͘͝e̸͖͆̎̏͒̀̈́͛́̍̀̀̿̚͝B̵̨̯̹̝͙͉̲̟̳̟͎̪̫̪̤̒͋̉̑̐̒̅̅̋͜y̵̞͚͕̭̤̱͖̟̫̜̓͐̏̕ͅZ̸͎̫̖͍̪̓̐͆e̶͈͇̽̔͂̉͊̈́ņ̶̣̣͎̤̯͖͉͍̳͇͈̘̳̗͚́̄̊̂̊̏̄͐͐̿̓́̽̃̄̚͝ | 37cdb52ed2 | |
C̷̱̺͙͓̪͔̹͉͉̯̖̟̀͆́̽̔̈̚͠͝o̶̥̻̻̖̮͚͒̂̒͌̾̇͗͘͝d̸̢̡͈̮̦͈͙̖͔̦̭̩̰͎͉̣̰͆̈́͘͝e̸͖͆̎̏͒̀̈́͛́̍̀̀̿̚͝B̵̨̯̹̝͙͉̲̟̳̟͎̪̫̪̤̒͋̉̑̐̒̅̅̋͜y̵̞͚͕̭̤̱͖̟̫̜̓͐̏̕ͅZ̸͎̫̖͍̪̓̐͆e̶͈͇̽̔͂̉͊̈́ņ̶̣̣͎̤̯͖͉͍̳͇͈̘̳̗͚́̄̊̂̊̏̄͐͐̿̓́̽̃̄̚͝ | d8569394b0 | |
_run | da57174635 | |
_run | 776ce0a7eb | |
coder2020official | 886806135e | |
coder2020official | 1e450ebd15 | |
_run | 41521f5618 | |
_run | 603a7cf9f2 | |
_run | 535a14ca0c | |
_run | 67a52b2e98 | |
Arash Nemat Zadeh | c47c26d2b0 | |
coder2020official | 9d2f7c02a4 | |
coder2020official | 991679bedc | |
coder2020official | 3b4e6fed04 | |
coder2020official | 5c6b867582 | |
coder2020official | 715aabaf49 | |
coder2020official | 9fa5b91e58 | |
coder2020official | de5a32e45c | |
coder2020official | db087427fc | |
coder2020official | 385fc6a6da | |
coder2020official | ac0b386625 | |
coder2020official | ae44b0022d | |
coder2020official | 73135d6012 | |
coder2020official | 19dcce0d5b | |
coder2020official | f527fc91f6 | |
coder2020official | c0185dad44 | |
coder2020official | 8a858cac4e | |
coder2020official | f30457bd75 | |
coder2020official | 54caf30f69 | |
coder2020official | 09e4a2a437 | |
coder2020official | 9b81a29a6a | |
coder2020official | 65dcd67140 | |
coder2020official | c84b771e5a | |
_run | 2bd81a5f5c | |
Badiboy | 5d9a76b0dd | |
Badiboy | 6459f13f25 | |
Badiboy | c9b6d3f868 | |
Badiboy | 80c1a4798d | |
Dmitry | 7a67d5f9f9 | |
zeldpol | d12ea91e12 | |
orocane | 4f2c89c4a8 | |
_run | fb7d60f09d | |
coder2020official | 8dc4e77287 | |
Badiboy | a999161384 | |
Badiboy | b4196f5891 | |
Badiboy | e55fe962ca | |
Badiboy | 3d2c5c9590 | |
_run | 40567570e8 | |
coder2020official | 4179e502c3 | |
coder2020official | a9b878107c | |
coder2020official | 2094120ec7 | |
coder2020official | d1348606e3 | |
coder2020official | d0d03d0c09 | |
Badiboy | fdd82a5e4b | |
coder2020official | 9e68f76f5d | |
coder2020official | 4000c9fb48 | |
coder2020official | ae42d0b1fe | |
coder2020official | a3891ff363 | |
coder2020official | 4d7f5310fb | |
_run | 3e0d69f7f4 | |
coder2020official | 2e5fb10430 | |
_run | c39c050abf | |
Muhammad Aadil | ed6d6cc03f | |
Muhammad Aadil | 10a80e1cfa | |
Badiboy | d99f48f975 | |
_run | dae2790c61 | |
Badiboy | f5eac56afa | |
_run | 268c3a9210 | |
Muhammad Aadil | ad7e4bbaf7 | |
Artem Lavrenov | b9bedef73f | |
Badiboy | 9fb5f89f18 | |
Oleg Belov | 409ff49603 | |
Albert | 5e0da40fcd | |
Badiboy | b743aa5813 | |
Cub11k | 1797f076dc | |
_run | 68c1fe8cb5 | |
Cub11k | 1eda7cafd4 | |
Badiboy | 291566908b | |
Ilya Krivoshein | bef29d9318 | |
Badiboy | a5af586a46 | |
Cub11k | 93dcbbeb02 | |
Badiboy | bd94d8d91c | |
_run | 6b399ab8cd | |
_run | 8744402efc | |
Badiboy | d5bbaa900e | |
Konstantin Ostashenko | 02ae255701 | |
Cub11k | c27f60b94b | |
Badiboy | a781929a2d | |
Cub11k | e6f8acadf4 | |
Cub11k | c298d95d0f | |
Cub11k | 8aee5372ee | |
_run | df105ab1d8 | |
Cub11k | b93ec5d0e0 | |
Cub11k | f201df3275 | |
_run | 206e4e024b | |
coder2020official | bd1290592b | |
_run | 9b9eb775f7 | |
Konstantin Ostashenko | 3cfa24f9c0 | |
Konstantin Ostashenko | b540a6c4d4 | |
Cub11k | a0ba5ae9af | |
Cub11k | 651db29cb2 | |
Cub11k | 490168f3f6 | |
Cub11k | bf38071e8f | |
Konstantin Ostashenko | e8aaa524fe | |
Konstantin Ostashenko | e2e754fdff | |
_run | d64f305fd4 | |
coder2020official | 611bf4235c | |
Konstantin Ostashenko | fe0dc6930c | |
Konstantin Ostashenko | 6d4d3f8005 | |
Cub11k | 0f7464e8c4 | |
Badiboy | 6f86382e33 | |
Badiboy | 43cc203654 | |
Badiboy | 3b62ad4765 | |
_run | 3be5015f9e | |
_run | 267a33c329 | |
_run | 667e82d073 | |
Cub11k | dd50273c95 | |
Cub11k | 8e9d566d5c | |
_run | 79bc869143 | |
Konstantin Ostashenko | 68edb4990c | |
Cub11k | 19544ecc58 | |
coder2020official | eed56be596 | |
coder2020official | 9f8256607a | |
coder2020official | f297ad23c7 | |
coder2020official | a20a3ae321 | |
coder2020official | 107f92314b | |
coder2020official | 9f5d9861a4 | |
coder2020official | 4537b237c8 | |
coder2020official | 4d11e97c25 | |
coder2020official | f0a1cefdda | |
_run | 24cd014410 | |
Badiboy | ba64180b5f | |
Cub11k | 3812fd05e3 | |
Cub11k | 69afd7232e | |
Badiboy | 81600cf27e | |
_run | bb8023ecc6 | |
Cub11k | a50a6e2e54 | |
Badiboy | 0329e5adb8 | |
Rudy Ayitinya Sulley | 2f25b56659 | |
dependabot[bot] | 2aaab08517 | |
_run | a6a22c351a | |
Cub11k | d211db90cf | |
_run | f2c211616c | |
_run | c5e733a4c1 | |
_run | 925f7012f1 | |
_run | 625ae09573 | |
coder2020official | 5b279b7ad9 | |
_run | 247cddf23d | |
_run | 171172d12e | |
_run | c3c12b93dd | |
_run | add240adfd | |
_run | 45fe2ea319 | |
Badiboy | 6373af78f3 | |
reddere | 4ed460b137 | |
reddere | ae20cb9f31 | |
reddere | 669c18fdc0 | |
reddere | 34acae9a59 | |
Badiboy | 109ae69f27 | |
Badiboy | 43abedbff7 | |
Badiboy | 42d162f732 | |
Badiboy | cd4dc899a1 | |
_run | 5066626692 | |
Konstantin Ostashenko | e255d9cbab | |
Konstantin Ostashenko | 8e1c8a2742 | |
Cub11k | e358abc1bd | |
_run | 42da2d1794 | |
Cub11k | feaef2b2b8 | |
Cub11k | 6cf60a3dcb | |
Konstantin Ostashenko | 91ff06eeba | |
Cub1tor | 1c2111d689 | |
_run | bf039df122 | |
_run | 44309797d1 | |
_run | 8489383eb4 | |
abdullaev388 | 848a2cc7ec | |
abdullaev388 | cc87dbce50 | |
abdullaev388 | 15f6bbeacb | |
abdullaev388 | 29befa4d0c | |
abdullaev388 | cce03dab78 | |
_run | 7702d63fd7 | |
_run | d636cdf88b | |
_run | 06a28380d7 | |
coder2020official | d7e9d3accc | |
coder2020official | 736c03fe84 | |
coder2020official | 7502d26b1a | |
Badiboy | b4d59fdf0a | |
Badiboy | 8d723bdcb3 | |
Badiboy | a169404a7c | |
Badiboy | 7a20017dfb | |
_run | 8d82b3d56b | |
_run | 0759c8e081 | |
_run | 8992db1d24 | |
_run | deb2099396 | |
_run | 8a74198276 | |
_run | 15bd5f991a | |
_run | 25571b581c | |
Badiboy | bf617ab8da | |
Badiboy | 74732f2eda | |
Badiboy | 0a79f7e4f3 | |
_run | 8b735aa114 | |
coder2020official | ae1845f285 | |
coder2020official | 0846852ea1 | |
coder2020official | 4825624d48 | |
coder2020official | 876d679765 | |
coder2020official | 7958d0dca7 | |
coder2020official | 4e2ea90db3 | |
coder2020official | 566aef1679 | |
Badiboy | 2dad99ad95 | |
coder2020official | f288470b43 | |
coder2020official | 475394d241 | |
coder2020official | 76f06cacfe | |
coder2020official | 77738b2537 | |
coder2020official | 070479f7af | |
coder2020official | f1f18c6df2 | |
_run | 81c8ee5820 | |
Badiboy | 76a689d939 | |
batmanscode | 92ecfdec48 | |
Badiboy | 20376168c1 | |
Yan Khachko | 507d53efbd | |
Yan Khachko | 1d8dc78c87 | |
Badiboy | ebec3bf5c1 | |
reddere | d11b9802da | |
coder2020official | 572f103db7 | |
Badiboy | 231371f1f8 | |
Badiboy | 623d8b27ec | |
Badiboy | 31c3a2b2a3 | |
_run | c45af810f9 | |
_run | 81f090cce6 | |
_run | 5d16b8bd4a | |
_run | 0fecf46201 | |
_run | 982e642c73 | |
byehack | 97bca49c00 | |
Badiboy | e0ee087162 | |
Badiboy | 620b1364a6 | |
Badiboy | c561cf3076 | |
coder2020official | b3953d6249 | |
coder2020official | 2d7170feee | |
Badiboy | 0ca8007633 | |
_run | c541533762 | |
byehack | 4798c26188 | |
byehack | 30aaf8d0f1 | |
Badiboy | 82ad37fed8 | |
coder2020official | 2d1f39085d | |
coder2020official | b523cec22f | |
coder2020official | 27e0197855 | |
coder2020official | ea69b8093d | |
coder2020official | 04ff428bba | |
coder2020official | eb576d83fb | |
_run | d3080b6d4e | |
Badiboy | 7c9b01b10a | |
Badiboy | b3993bb019 | |
Badiboy | 36b889feab | |
Anton | d943f40643 | |
_run | dafafd2ad2 | |
coder2020official | e002484a9b | |
Badiboy | 52e09637c2 | |
Badiboy | e7a96ec2ed | |
Badiboy | 598de25b6d | |
_run | b841fc10ed | |
byehack | c14760d81c | |
Badiboy | da639dd1f6 | |
_run | 96e137f5e6 | |
Badiboy | 8d9dfcfac8 | |
_run | a1c77db236 | |
coder2020official | 4f97b26e81 | |
coder2020official | 0028feb4c5 | |
orocane | a06b4a1e9c | |
coder2020official | da5084f53c | |
coder2020official | 2f8d878f06 | |
orocane | 783beb165b | |
_run | 4fd01e3ac8 | |
_run | b4c28de104 | |
_run | de344bd5e0 | |
_run | e3a4fdff9a | |
_run | 71d3ec8b42 | |
coder2020official | 1b1d6c8239 | |
coder2020official | 9216f15c16 | |
coder2020official | 0f7ab0d05f | |
coder2020official | e0ffe0b4f5 | |
Badiboy | f4c5dd0d22 | |
Ananth Bhaskararaman | e4179ea65f | |
Ananth Bhaskararaman | d7770bf670 | |
_run | 095bf03227 | |
_run | 85bd174fdc | |
Ananth Bhaskararaman | b86c38367a | |
Badiboy | b8214d32d5 | |
Badiboy | f4e66f6807 | |
Badiboy | b1a4136603 | |
Badiboy | 3d97b08289 | |
_run | 3d2576ca24 | |
Badiboy | b2d2ab5c33 | |
_run | c9a732e3dd | |
_run | 01be1fb583 | |
Badiboy | 7b95874627 | |
Badiboy | 426f9f3787 | |
Badiboy | 47ae696528 | |
Badiboy | a9b8baea2c | |
_run | d3cab9cdba | |
Badiboy | d6ef67073e | |
Badiboy | 345fa3433c | |
_run | c95ba8c9c2 | |
_run | 20bdb54e94 | |
Badiboy | 124dfbf392 | |
Badiboy | 9f9821bbe8 | |
Badiboy | c8d1dac61e | |
_run | ffb34da610 | |
_run | 2647a02fc6 | |
_run | dd4073fd74 | |
_run | 737c3a439d | |
_run | 40698408c9 | |
_run | ffa1c37204 | |
Badiboy | d42c8e2961 | |
_run | 5471b88da6 | |
_run | 26db76f207 | |
_run | e860f114c6 | |
_run | c5a69944be | |
Badiboy | 2fe5ba403e | |
Badiboy | d2a7f975de | |
Pablo Vazquez Rodriguez | 41b1519786 | |
Aaron Blakely | 93e1813139 | |
Badiboy | dab5d7f632 | |
Mahakam20000 | 1667b51034 | |
Badiboy | 7d94e01009 | |
v.korobov | c0ed659f30 | |
v.korobov | 047777fada | |
Badiboy | 839aced912 | |
_run | d03f3b2c52 | |
_run | 65b353ffae | |
Badiboy | 914c5fdf0c | |
Badiboy | 8aa3d052cc | |
_run | 5beb51f907 | |
Badiboy | c145b7ef8f | |
_run | 6303ecc7c6 | |
_run | fc01ec50fc | |
_run | 51b2ec701d | |
_run | 3d7f334d79 | |
Badiboy | a61508ca0c | |
robz-tirtlib | 9d9e76e724 | |
_run | b0e06253ff | |
Badiboy | 7c12162576 | |
_run | f0feb45e87 | |
_run | c2cfe24426 | |
_run | f6ec3493ad | |
Badiboy | e553f3aa1d | |
_run | 49d3b463ed | |
_run | 147278733b | |
Badiboy | 54ad1582aa | |
_run | e379708af6 | |
_run | 9f7b113e2f | |
_run | 482498e1e5 | |
_run | 22beead3b5 | |
Badiboy | 2b01765627 | |
Badiboy | 5dbe1b3523 | |
_run | 3ffd06fcca | |
_run | ea1efad1ea | |
_run | 1efe465e9d | |
_run | 0c6f84c79a | |
Badiboy | bf415e4bd7 | |
_run | 2fcfdc2584 | |
_run | 659501efef | |
Badiboy | 92654ee970 | |
Badiboy | a1bcd3c42e | |
Badiboy | b276bfacaf | |
Badiboy | 726b203724 | |
Badiboy | 16703161aa | |
Badiboy | a3a55e7393 | |
Badiboy | 1c11898ea1 | |
_run | 8c6f81546c | |
_run | 194bf6e95d | |
_run | 124606fdcb | |
_run | 90a90d4a34 | |
_run | d67ee2a5c5 | |
_run | 970b9d6be4 | |
Badiboy | 0b5b7ad39a | |
Badiboy | a7c420aa14 | |
_run | 0cf2a0fe77 | |
_run | 2f32236680 | |
_run | f8f147f9f4 | |
_run | 140befc132 | |
_run | 36fbb13663 | |
_run | e353572c03 | |
_run | ebca668979 | |
_run | 7b8c98d731 | |
_run | 3cf5305845 | |
_run | eb4cd7aba0 | |
Badiboy | 01f9e3b710 | |
_run | e1094c6f02 | |
_run | 174bbf9c84 | |
_run | 1df19e3b2d | |
Badiboy | e0e6eee374 | |
Badiboy | 78251cdf43 | |
Badiboy | 81cbddb8cd | |
Badiboy | 0aa9f0fb42 | |
Badiboy | f3b1f97362 | |
Badiboy | df1977911e | |
_run | d861fd0042 | |
_run | 1fb14e28d4 | |
Badiboy | b691a467c0 | |
咕谷酱 | badf982147 | |
咕谷酱 | 6d52090ef9 | |
咕谷酱 | cf3a85d699 | |
咕谷酱 | ef86453126 | |
Badiboy | d9ab5b0d28 | |
_run | c920809fa9 | |
_run | 5939e754bb | |
_run | 3019b71f7f | |
_run | 0bdf925fbe | |
_run | d14064a84d | |
Badiboy | 49c93b6027 | |
_run | 36749cbdd9 | |
_run | 6d12b1f2a7 | |
_run | 419bc5878f | |
Badiboy | b9b4885568 | |
Badiboy | ce0a974c91 | |
_run | c36f3a228e | |
_run | ca525b5bea | |
Badiboy | 6ff015689a | |
_run | 6459aded82 | |
_run | fec47cecaf | |
Badiboy | 3892b0fb80 | |
_run | fbb9a73fc0 | |
Badiboy | db5c53b8e5 | |
_run | 6e8abc709e | |
Badiboy | 752f35614c | |
_run | a2893945b2 | |
_run | 1686ce4f44 |
|
@ -20,7 +20,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [ '3.6','3.7','3.8','3.9', '3.10', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9']
|
||||
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9']
|
||||
name: ${{ matrix.python-version }} and tests
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the version of Python and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.9"
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# We recommend specifying your dependencies to enable reproducible builds:
|
||||
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
|
@ -4,6 +4,7 @@ python:
|
|||
- "3.8"
|
||||
- "3.9"
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "pypy3"
|
||||
install: "pip install -r requirements.txt"
|
||||
script:
|
||||
|
|
49
README.md
49
README.md
|
@ -2,7 +2,6 @@
|
|||
[![PyPi Package Version](https://img.shields.io/pypi/v/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
|
||||
[![Supported Python versions](https://img.shields.io/pypi/pyversions/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
|
||||
[![Documentation Status](https://readthedocs.org/projects/pytba/badge/?version=latest)](https://pytba.readthedocs.io/en/latest/?badge=latest)
|
||||
[![Build Status](https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master)](https://travis-ci.org/eternnoir/pyTelegramBotAPI)
|
||||
[![PyPi downloads](https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg)](https://pypi.org/project/pyTelegramBotAPI/)
|
||||
[![PyPi status](https://img.shields.io/pypi/status/pytelegrambotapi.svg?style=flat-square)](https://pypi.python.org/pypi/pytelegrambotapi)
|
||||
|
||||
|
@ -11,9 +10,10 @@
|
|||
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
|
||||
<p align="center">Both synchronous and asynchronous.</p>
|
||||
|
||||
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#june-20-2022">6.1</a>!
|
||||
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#april-21-2023">6.7</a>!
|
||||
|
||||
<h2><a href='https://pytba.readthedocs.io/en/latest/index.html'>Official documentation</a></h2>
|
||||
<h2><a href='https://pytba.readthedocs.io/ru/latest/index.html'>Official ru documentation</a></h2>
|
||||
|
||||
## Contents
|
||||
|
||||
|
@ -56,7 +56,7 @@
|
|||
* [Logging](#logging)
|
||||
* [Proxy](#proxy)
|
||||
* [Testing](#testing)
|
||||
* [API conformance](#api-conformance)
|
||||
* [API conformance limitations](#api-conformance-limitations)
|
||||
* [AsyncTeleBot](#asynctelebot)
|
||||
* [F.A.Q.](#faq)
|
||||
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
|
||||
|
@ -69,7 +69,7 @@
|
|||
|
||||
## Getting started
|
||||
|
||||
This API is tested with Python 3.6-3.10 and Pypy 3.
|
||||
This API is tested with Python 3.7-3.11 and Pypy 3.
|
||||
There are two ways to install the library:
|
||||
|
||||
* Installation using pip (a Python package manager):
|
||||
|
@ -165,7 +165,7 @@ To start the bot, simply open up a terminal and enter `python echo_bot.py` to ru
|
|||
All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)).
|
||||
|
||||
The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings:
|
||||
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`.
|
||||
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`, `web_app_data`.
|
||||
|
||||
You can use some types in one function. Example:
|
||||
|
||||
|
@ -265,7 +265,7 @@ def test_callback(call): # <- passes a CallbackQuery type object to your functio
|
|||
|
||||
#### Shipping Query Handler
|
||||
Handle shipping queries
|
||||
`@bot.shipping_query_handeler() # <- passes a ShippingQuery type object to your function`
|
||||
`@bot.shipping_query_handler() # <- passes a ShippingQuery type object to your function`
|
||||
|
||||
#### Pre Checkout Query Handler
|
||||
Handle pre checkoupt queries
|
||||
|
@ -398,7 +398,7 @@ Here is example of creating filter-class:
|
|||
```python
|
||||
class IsAdmin(telebot.custom_filters.SimpleCustomFilter):
|
||||
# Class will check whether the user is admin or creator in group or not
|
||||
key='is_admin'
|
||||
key='is_chat_admin'
|
||||
@staticmethod
|
||||
def check(message: telebot.types.Message):
|
||||
return bot.get_chat_member(message.chat.id,message.from_user.id).status in ['administrator','creator']
|
||||
|
@ -407,7 +407,7 @@ class IsAdmin(telebot.custom_filters.SimpleCustomFilter):
|
|||
bot.add_custom_filter(IsAdmin())
|
||||
|
||||
# Now, you can use it in handler.
|
||||
@bot.message_handler(is_admin=True)
|
||||
@bot.message_handler(is_chat_admin=True)
|
||||
def admin_of_group(message):
|
||||
bot.send_message(message.chat.id, 'You are admin of this group!')
|
||||
|
||||
|
@ -726,27 +726,10 @@ Result will be:
|
|||
|
||||
|
||||
|
||||
## API conformance
|
||||
* ✔ [Bot API 6.1](https://core.telegram.org/bots/api#june-20-2022)
|
||||
* ✔ [Bot API 6.0](https://core.telegram.org/bots/api#april-16-2022)
|
||||
* ✔ [Bot API 5.7](https://core.telegram.org/bots/api#january-31-2022)
|
||||
* ✔ [Bot API 5.6](https://core.telegram.org/bots/api#december-30-2021)
|
||||
* ✔ [Bot API 5.5](https://core.telegram.org/bots/api#december-7-2021)
|
||||
* ✔ [Bot API 5.4](https://core.telegram.org/bots/api#november-5-2021)
|
||||
* ➕ [Bot API 5.3](https://core.telegram.org/bots/api#june-25-2021) - ChatMember* classes are full copies of ChatMember
|
||||
* ✔ [Bot API 5.2](https://core.telegram.org/bots/api#april-26-2021)
|
||||
* ✔ [Bot API 5.1](https://core.telegram.org/bots/api#march-9-2021)
|
||||
* ✔ [Bot API 5.0](https://core.telegram.org/bots/api-changelog#november-4-2020)
|
||||
* ✔ [Bot API 4.9](https://core.telegram.org/bots/api-changelog#june-4-2020)
|
||||
* ✔ [Bot API 4.8](https://core.telegram.org/bots/api-changelog#april-24-2020)
|
||||
* ✔ [Bot API 4.7](https://core.telegram.org/bots/api-changelog#march-30-2020)
|
||||
* ✔ [Bot API 4.6](https://core.telegram.org/bots/api-changelog#january-23-2020)
|
||||
## API conformance limitations
|
||||
* ➕ [Bot API 4.5](https://core.telegram.org/bots/api-changelog#december-31-2019) - No nested MessageEntities and Markdown2 support
|
||||
* ✔ [Bot API 4.4](https://core.telegram.org/bots/api-changelog#july-29-2019)
|
||||
* ✔ [Bot API 4.3](https://core.telegram.org/bots/api-changelog#may-31-2019)
|
||||
* ✔ [Bot API 4.2](https://core.telegram.org/bots/api-changelog#april-14-2019)
|
||||
* ➕ [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support
|
||||
* ➕ [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support
|
||||
* ➕ [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support
|
||||
* ➕ [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support
|
||||
|
||||
|
||||
## AsyncTeleBot
|
||||
|
@ -894,10 +877,20 @@ Here are some examples of template:
|
|||
* [GrandQuiz Bot](https://github.com/Carlosma7/TFM-GrandQuiz) by [Carlosma7](https://github.com/Carlosma7). This bot is a trivia game that allows you to play with people from different ages. This project addresses the use of a system through chatbots to carry out a social and intergenerational game as an alternative to traditional game development.
|
||||
* [Diccionario de la RAE](https://t.me/dleraebot) ([source](https://github.com/studentenherz/dleraebot)) This bot lets you find difinitions of words in Spanish using [RAE's dictionary](https://dle.rae.es/). It features direct message and inline search.
|
||||
* [remoteTelegramShell](https://github.com/EnriqueMoran/remoteTelegramShell) by [EnriqueMoran](https://github.com/EnriqueMoran). Control your LinuxOS computer through Telegram.
|
||||
* [Commerce Telegram Bot](https://github.com/ayitinya/commerce-telegram-bot/). Make purchases of items in a store with an Admin panel for data control and notifications.
|
||||
* [Pyfram-telegram-bot](https://github.com/skelly37/pyfram-telegram-bot) Query wolframalpha.com and make use of its API through Telegram.
|
||||
* [TranslateThisVideoBot](https://gitlab.com/WuerfelDev/translatethisvideo) This Bot can understand spoken text in videos and translate it to English
|
||||
* [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX.
|
||||
* [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text.
|
||||
* [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...).
|
||||
* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang is a multi-functional robot, such as OSU game information query, IP test, animation screenshot search and other functions.
|
||||
* [Feedback-bot](https://github.com/coder2020official/feedbackbot) A feedback bot for user-admin communication. Made on AsyncTeleBot, using [template](https://github.com/coder2020official/asynctelebot_template).
|
||||
* [TeleServ](https://github.com/ablakely/TeleServ) by [ablakely](https://github.com/ablakely) This is a Telegram to IRC bridge which links as an IRC server and makes Telegram users appear as native IRC users.
|
||||
* [Simple Store Bot](https://github.com/AntonGlyzin/myshopbot) by [Anton Glyzin](https://github.com/AntonGlyzin) This is a simple telegram-store with an admin panel. Designed according to a template.
|
||||
* [Media Rating Bot](https://t.me/mediaratingbot) ([source](https://github.com/CommanderCRM/MediaRatingBot))by [CommanderCRM](https://github.com/CommanderCRM). This bot aggregates media (movies, TV series, etc.) ratings from IMDb, Rotten Tomatoes, Metacritic, TheMovieDB, FilmAffinity and also provides number of votes of said media on IMDb.
|
||||
* [Spot Seek Bot](https://t.me/SpotSeekBot) ([source](https://github.com/arashnm80/spot-seek-bot)) by [Arashnm80](https://github.com/arashnm80). This is a free & open source telegram bot for downloading tracks, albums or playlists from spotify.
|
||||
* [CalendarIT Bot](https://t.me/calendarit_bot) ([source](https://github.com/codebyzen/CalendarIT_Telegram_Bot))by [CodeByZen](https://github.com/codebyzen). A simple, but extensible Python Telegram bot, can post acquainted with what is happening today, tomorrow or what happened 20 years ago to channel.
|
||||
* [DownloadMusicBOT](https://github.com/fcoagz/DownloadMusicBOT) by *Francisco Griman* - It is a simple bot that downloads audio from YouTube videos on Telegram.
|
||||
* [AwesomeChatGPTBot](https://github.com/Kourva/AwesomeChatGPTBot) - Simple ChatGTP-3.5 bot. It is FREE and can remember chat history for a while With pre-defined roles!
|
||||
|
||||
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**
|
||||
|
|
|
@ -26,15 +26,6 @@ Asyncio filters
|
|||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Asynchronous storage for states
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: telebot.asyncio_storage
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Asyncio handler backends
|
||||
------------------------
|
||||
|
||||
|
@ -46,4 +37,12 @@ Asyncio handler backends
|
|||
:show-inheritance:
|
||||
|
||||
|
||||
Extensions
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
.. automodule:: telebot.ext.aio.webhooks
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'pyTelegramBotAPI Documentation'
|
||||
copyright = '2022, coder2020official'
|
||||
copyright = '2022-2023, coder2020official'
|
||||
author = 'coder2020official'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '4.6.0'
|
||||
release = '4.12.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
@ -68,3 +68,5 @@ html_theme_options = {
|
|||
"light_logo": "logo.png",
|
||||
"dark_logo": "logo2.png",
|
||||
}
|
||||
|
||||
locale_dirs = ["locales/"]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,127 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../calldata.rst:4
|
||||
msgid "Callback data factory"
|
||||
msgstr ""
|
||||
|
||||
#: ../../calldata.rst:6
|
||||
msgid "Callback data factory in pyTelegramBotAPI"
|
||||
msgstr ""
|
||||
|
||||
#: ../../calldata.rst:6
|
||||
msgid ""
|
||||
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, "
|
||||
"factory"
|
||||
msgstr ""
|
||||
|
||||
#: ../../calldata.rst:12
|
||||
msgid "callback\\_data file"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data:1
|
||||
msgid "Callback data factory's file."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData:1
|
||||
#: telebot.callback_data.CallbackDataFilter:1
|
||||
msgid "Bases: :py:class:`object`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData:1
|
||||
msgid "Callback data factory This class will help you to work with CallbackQuery"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter:1
|
||||
msgid "Generate filter"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter
|
||||
#: telebot.callback_data.CallbackData.new
|
||||
#: telebot.callback_data.CallbackData.parse
|
||||
#: telebot.callback_data.CallbackDataFilter.check
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter:3
|
||||
msgid "specified named parameters will be checked with CallbackQuery.data"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter
|
||||
#: telebot.callback_data.CallbackData.new
|
||||
#: telebot.callback_data.CallbackData.parse
|
||||
#: telebot.callback_data.CallbackDataFilter.check
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter:4
|
||||
msgid "CallbackDataFilter class"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:1
|
||||
msgid "Generate callback data"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:3
|
||||
msgid "positional parameters of CallbackData instance parts"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:4
|
||||
msgid "named parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:5
|
||||
msgid "str"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.parse:1
|
||||
msgid "Parse data from the callback data"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.parse:3
|
||||
msgid ""
|
||||
"string, use to telebot.types.CallbackQuery to parse it from string to a "
|
||||
"dict"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.parse:4
|
||||
msgid "dict parsed from callback data"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter:1
|
||||
msgid "Filter for CallbackData."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check:1
|
||||
msgid "Checks if query.data appropriates to specified config"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check:3
|
||||
msgid "telebot.types.CallbackQuery"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check:6
|
||||
msgid "True if query.data appropriates to specified config"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check
|
||||
msgid "Return type"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../formatting.rst:3
|
||||
msgid "Formatting options"
|
||||
msgstr ""
|
||||
|
||||
#: ../../formatting.rst:5
|
||||
msgid "Formatting options in pyTelegramBotAPI"
|
||||
msgstr ""
|
||||
|
||||
#: ../../formatting.rst:5
|
||||
msgid "html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting:1
|
||||
msgid "Markdown & HTML formatting functions."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:1
|
||||
msgid "Escapes HTML characters in a string of HTML."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
|
||||
#: telebot.formatting.format_text telebot.formatting.hbold
|
||||
#: telebot.formatting.hcode telebot.formatting.hide_link
|
||||
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
|
||||
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
|
||||
#: telebot.formatting.hunderline telebot.formatting.mbold
|
||||
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
|
||||
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
|
||||
#: telebot.formatting.munderline
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:3
|
||||
msgid "The string of HTML to escape."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
|
||||
#: telebot.formatting.format_text telebot.formatting.hbold
|
||||
#: telebot.formatting.hcode telebot.formatting.hide_link
|
||||
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
|
||||
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
|
||||
#: telebot.formatting.hunderline telebot.formatting.mbold
|
||||
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
|
||||
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
|
||||
#: telebot.formatting.munderline
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:6 telebot.formatting.escape_markdown:8
|
||||
msgid "The escaped string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
|
||||
#: telebot.formatting.format_text telebot.formatting.hbold
|
||||
#: telebot.formatting.hcode telebot.formatting.hide_link
|
||||
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
|
||||
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
|
||||
#: telebot.formatting.hunderline telebot.formatting.mbold
|
||||
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
|
||||
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
|
||||
#: telebot.formatting.munderline
|
||||
msgid "Return type"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:7 telebot.formatting.escape_markdown:9
|
||||
#: telebot.formatting.format_text:17 telebot.formatting.hbold:10
|
||||
#: telebot.formatting.hcode:10 telebot.formatting.hide_link:7
|
||||
#: telebot.formatting.hitalic:10 telebot.formatting.hlink:13
|
||||
#: telebot.formatting.hpre:10 telebot.formatting.hspoiler:10
|
||||
#: telebot.formatting.hstrikethrough:10 telebot.formatting.hunderline:10
|
||||
#: telebot.formatting.mbold:10 telebot.formatting.mcode:10
|
||||
#: telebot.formatting.mitalic:10 telebot.formatting.mlink:13
|
||||
#: telebot.formatting.mspoiler:10 telebot.formatting.mstrikethrough:10
|
||||
#: telebot.formatting.munderline:10
|
||||
msgid ":obj:`str`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_markdown:1
|
||||
msgid "Escapes Markdown characters in a string of Markdown."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_markdown:3
|
||||
msgid "Credits to: simonsmh"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_markdown:5
|
||||
msgid "The string of Markdown to escape."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.format_text:1
|
||||
msgid "Formats a list of strings into a single string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.format_text:10
|
||||
msgid "Strings to format."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.format_text:13
|
||||
msgid "The separator to use between each string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.format_text:16 telebot.formatting.hbold:9
|
||||
#: telebot.formatting.hcode:9 telebot.formatting.hitalic:9
|
||||
#: telebot.formatting.hlink:12 telebot.formatting.hpre:9
|
||||
#: telebot.formatting.hspoiler:9 telebot.formatting.hstrikethrough:9
|
||||
#: telebot.formatting.hunderline:9 telebot.formatting.mbold:9
|
||||
#: telebot.formatting.mcode:9 telebot.formatting.mitalic:9
|
||||
#: telebot.formatting.mlink:12 telebot.formatting.mspoiler:9
|
||||
#: telebot.formatting.mstrikethrough:9 telebot.formatting.munderline:9
|
||||
msgid "The formatted string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hbold:1
|
||||
msgid "Returns an HTML-formatted bold string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hbold:3 telebot.formatting.mbold:3
|
||||
msgid "The string to bold."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hbold:6 telebot.formatting.hcode:6
|
||||
#: telebot.formatting.hitalic:6 telebot.formatting.hlink:9
|
||||
#: telebot.formatting.hpre:6 telebot.formatting.hspoiler:6
|
||||
#: telebot.formatting.hstrikethrough:6 telebot.formatting.hunderline:6
|
||||
#: telebot.formatting.mbold:6 telebot.formatting.mcode:6
|
||||
#: telebot.formatting.mitalic:6 telebot.formatting.mlink:9
|
||||
#: telebot.formatting.mspoiler:6 telebot.formatting.mstrikethrough:6
|
||||
#: telebot.formatting.munderline:6
|
||||
msgid "True if you need to escape special characters. Defaults to True."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hcode:1
|
||||
msgid "Returns an HTML-formatted code string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hcode:3 telebot.formatting.mcode:3
|
||||
msgid "The string to code."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hide_link:1
|
||||
msgid "Hide url of an image."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hide_link:3
|
||||
msgid "The url of the image."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hide_link:6
|
||||
msgid "The hidden url."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hitalic:1
|
||||
msgid "Returns an HTML-formatted italic string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hitalic:3 telebot.formatting.mitalic:3
|
||||
msgid "The string to italicize."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hlink:1
|
||||
msgid "Returns an HTML-formatted link string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hlink:3 telebot.formatting.mlink:3
|
||||
msgid "The string to link."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hlink:6 telebot.formatting.mlink:6
|
||||
msgid "The URL to link to."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hpre:1
|
||||
msgid "Returns an HTML-formatted preformatted string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hpre:3
|
||||
msgid "The string to preformatted."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hspoiler:1
|
||||
msgid "Returns an HTML-formatted spoiler string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hspoiler:3 telebot.formatting.mspoiler:3
|
||||
msgid "The string to spoiler."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hstrikethrough:1
|
||||
msgid "Returns an HTML-formatted strikethrough string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hstrikethrough:3 telebot.formatting.mstrikethrough:3
|
||||
msgid "The string to strikethrough."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hunderline:1
|
||||
msgid "Returns an HTML-formatted underline string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.hunderline:3 telebot.formatting.munderline:3
|
||||
msgid "The string to underline."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.mbold:1
|
||||
msgid "Returns a Markdown-formatted bold string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.mcode:1
|
||||
msgid "Returns a Markdown-formatted code string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.mitalic:1
|
||||
msgid "Returns a Markdown-formatted italic string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.mlink:1
|
||||
msgid "Returns a Markdown-formatted link string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.mspoiler:1
|
||||
msgid "Returns a Markdown-formatted spoiler string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.mstrikethrough:1
|
||||
msgid "Returns a Markdown-formatted strikethrough string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.munderline:1
|
||||
msgid "Returns a Markdown-formatted underline string."
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../index.rst:8
|
||||
msgid "Welcome to pyTelegramBotAPI's documentation!"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:10
|
||||
msgid "Official documentation of pyTelegramBotAPI"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:10
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:17
|
||||
msgid "TeleBot"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:18
|
||||
msgid ""
|
||||
"TeleBot is synchronous and asynchronous implementation of `Telegram Bot "
|
||||
"API <https://core.telegram.org/bots/api>`_."
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:21
|
||||
msgid "Chats"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:22
|
||||
msgid ""
|
||||
"English chat: `Private chat "
|
||||
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:24
|
||||
msgid ""
|
||||
"Russian chat: `@pytelegrambotapi_talks_ru "
|
||||
"<https://t.me/pytelegrambotapi_talks_ru>`__"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:26
|
||||
msgid "News: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:28
|
||||
msgid "Pypi: `Pypi <https://pypi.org/project/pyTelegramBotAPI/>`__"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:30
|
||||
msgid ""
|
||||
"Source: `Github repository "
|
||||
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:33
|
||||
msgid "Some features:"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:34
|
||||
msgid "Easy to learn and use."
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:36
|
||||
msgid "Easy to understand."
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:38
|
||||
msgid "Both sync and async."
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:40
|
||||
msgid "Examples on features."
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:42
|
||||
msgid "States"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:44
|
||||
msgid "And more..."
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:47
|
||||
msgid "Content"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:63
|
||||
msgid "Indices and tables"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:65
|
||||
msgid ":ref:`genindex`"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:66
|
||||
msgid ":ref:`modindex`"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:67
|
||||
msgid ":ref:`search`"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../install.rst:3
|
||||
msgid "Installation Guide"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:5
|
||||
msgid "Installation of pyTelegramBotAPI"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:5
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, installation, guide"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:11
|
||||
msgid "Using PIP"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:17
|
||||
msgid "Using pipenv"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:23
|
||||
msgid "By cloning repository"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:31
|
||||
msgid "Directly using pip"
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:37
|
||||
msgid "It is generally recommended to use the first option."
|
||||
msgstr ""
|
||||
|
||||
#: ../../install.rst:39
|
||||
msgid ""
|
||||
"While the API is production-ready, it is still under development and it "
|
||||
"has regular updates, do not forget to update it regularly by calling:"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../quick_start.rst:4
|
||||
msgid "Quick start"
|
||||
msgstr ""
|
||||
|
||||
#: ../../quick_start.rst:6
|
||||
msgid "Quickstart guide"
|
||||
msgstr ""
|
||||
|
||||
#: ../../quick_start.rst:6
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide"
|
||||
msgstr ""
|
||||
|
||||
#: ../../quick_start.rst:11
|
||||
msgid "Synchronous TeleBot"
|
||||
msgstr ""
|
||||
|
||||
#: ../../quick_start.rst:16
|
||||
msgid "Asynchronous TeleBot"
|
||||
msgstr ""
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,355 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-08 23:07+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../source/util.rst:3
|
||||
msgid "Utils"
|
||||
msgstr ""
|
||||
|
||||
#: ../../source/util.rst:5
|
||||
msgid "Utils in pyTelegramBotAPI"
|
||||
msgstr ""
|
||||
|
||||
#: ../../source/util.rst:5
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, utils, guide"
|
||||
msgstr ""
|
||||
|
||||
#: ../../source/util.rst:11
|
||||
msgid "util file"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:1
|
||||
msgid ""
|
||||
"Use this function inside loops in order to avoid getting TooManyRequests "
|
||||
"error. Example:"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_bytes telebot.service_utils.is_dict
|
||||
#: telebot.service_utils.is_pil_image telebot.util.antiflood
|
||||
#: telebot.util.escape telebot.util.extract_arguments
|
||||
#: telebot.util.extract_command telebot.util.is_command
|
||||
#: telebot.util.parse_web_app_data telebot.util.quick_markup
|
||||
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
|
||||
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:10
|
||||
msgid "The function to call"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:13
|
||||
msgid "Number of retries to send"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:16
|
||||
msgid "The arguments to pass to the function"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:19
|
||||
msgid "The keyword arguments to pass to the function"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.generate_random_token
|
||||
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
|
||||
#: telebot.service_utils.is_pil_image telebot.util.antiflood
|
||||
#: telebot.util.escape telebot.util.extract_arguments
|
||||
#: telebot.util.extract_command telebot.util.is_command
|
||||
#: telebot.util.parse_web_app_data telebot.util.quick_markup
|
||||
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
|
||||
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:22
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.chunks:1
|
||||
msgid "Yield successive n-sized chunks from lst."
|
||||
msgstr ""
|
||||
|
||||
#: ../../docstring of telebot.util.content_type_media:1
|
||||
msgid "Contains all media content types."
|
||||
msgstr ""
|
||||
|
||||
#: ../../docstring of telebot.util.content_type_service:1
|
||||
msgid "Contains all service content types such as `User joined the group`."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.escape:1
|
||||
msgid ""
|
||||
"Replaces the following chars in `text` ('&' with '&', '<' with '<'"
|
||||
" and '>' with '>')."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.escape:3
|
||||
msgid "the text to escape"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.escape:4
|
||||
msgid "the escaped text"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_arguments:1
|
||||
msgid "Returns the argument after the command."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_arguments:3 telebot.util.extract_command:4
|
||||
msgid "Examples:"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_arguments:10
|
||||
msgid "String to extract the arguments from a command"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_arguments:13
|
||||
msgid "the arguments if `text` is a command (according to is_command), else None."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.generate_random_token
|
||||
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
|
||||
#: telebot.service_utils.is_pil_image telebot.util.extract_arguments
|
||||
#: telebot.util.extract_command telebot.util.is_command
|
||||
#: telebot.util.quick_markup telebot.util.smart_split telebot.util.split_string
|
||||
#: telebot.util.user_link
|
||||
msgid "Return type"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_arguments:14 telebot.util.extract_command:16
|
||||
msgid ":obj:`str` or :obj:`None`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_command:1
|
||||
msgid ""
|
||||
"Extracts the command from `text` (minus the '/') if `text` is a command "
|
||||
"(see is_command). If `text` is not a command, this function returns None."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_command:12
|
||||
msgid "String to extract the command from"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_command:15
|
||||
msgid "the command if `text` is a command (according to is_command), else None."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.generate_random_token:1
|
||||
msgid ""
|
||||
"Generates a random token consisting of letters and digits, 16 characters "
|
||||
"long."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.generate_random_token:3
|
||||
msgid "a random token"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.generate_random_token:4 telebot.util.user_link:22
|
||||
msgid ":obj:`str`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_bytes:1
|
||||
msgid "Returns True if the given object is a bytes object."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_bytes:3 telebot.service_utils.is_dict:3
|
||||
#: telebot.service_utils.is_pil_image:3
|
||||
msgid "object to be checked"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_bytes:6
|
||||
msgid "True if the given object is a bytes object."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_bytes:7 telebot.service_utils.is_dict:7
|
||||
#: telebot.service_utils.is_pil_image:7 telebot.util.is_command:7
|
||||
msgid ":obj:`bool`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.is_command:1
|
||||
msgid ""
|
||||
"Checks if `text` is a command. Telegram chat commands start with the '/' "
|
||||
"character."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.is_command:3
|
||||
msgid "Text to check."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.is_command:6
|
||||
msgid "True if `text` is a command, else False."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_dict:1
|
||||
msgid "Returns True if the given object is a dictionary."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_dict:6
|
||||
msgid "True if the given object is a dictionary."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_pil_image:1
|
||||
msgid "Returns True if the given object is a PIL.Image.Image object."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_pil_image:6
|
||||
msgid "True if the given object is a PIL.Image.Image object."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_string:1
|
||||
msgid "Returns True if the given object is a string."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.parse_web_app_data:1
|
||||
msgid "Parses web app data."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.parse_web_app_data:3 telebot.util.validate_web_app_data:3
|
||||
msgid "The bot token"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.parse_web_app_data:6 telebot.util.validate_web_app_data:6
|
||||
msgid "The raw init data"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.parse_web_app_data:9 telebot.util.validate_web_app_data:9
|
||||
msgid "The parsed init data"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:1
|
||||
msgid ""
|
||||
"Returns a reply markup from a dict in this format: {'text': kwargs} This "
|
||||
"is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2"
|
||||
" = InlineKeyboardButton(...)'"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:4 telebot.util.user_link:5
|
||||
msgid "Example:"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:6
|
||||
msgid "Using quick_markup:"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:31
|
||||
msgid ""
|
||||
"a dict containing all buttons to create in this format: {text: kwargs} "
|
||||
"{str:}"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:34
|
||||
msgid "number of :class:`telebot.types.InlineKeyboardButton` objects on each row"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:37
|
||||
msgid "InlineKeyboardMarkup"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:38
|
||||
msgid ":obj:`types.InlineKeyboardMarkup`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.smart_split:1
|
||||
msgid ""
|
||||
"Splits one string into multiple strings, with a maximum amount of "
|
||||
"`chars_per_string` characters per string. This is very useful for "
|
||||
"splitting one giant message into multiples. If `chars_per_string` > 4096:"
|
||||
" `chars_per_string` = 4096. Splits by '\\n', '. ' or ' ' in exactly this "
|
||||
"priority."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.smart_split:6 telebot.util.split_string:4
|
||||
msgid "The text to split"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.smart_split:9
|
||||
msgid "The number of maximum characters per part the text is split to."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.smart_split:12 telebot.util.split_string:10
|
||||
msgid "The splitted text as a list of strings."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.smart_split:13 telebot.util.split_string:11
|
||||
msgid ":obj:`list` of :obj:`str`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.split_string:1
|
||||
msgid ""
|
||||
"Splits one string into multiple strings, with a maximum amount of "
|
||||
"`chars_per_string` characters per string. This is very useful for "
|
||||
"splitting one giant message into multiples."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.split_string:7
|
||||
msgid "The number of characters per line the text is split into."
|
||||
msgstr ""
|
||||
|
||||
#: ../../docstring of telebot.util.update_types:1
|
||||
msgid "All update types, should be used for allowed_updates parameter in polling."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.user_link:1
|
||||
msgid ""
|
||||
"Returns an HTML user link. This is useful for reports. Attention: Don't "
|
||||
"forget to set parse_mode to 'HTML'!"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.user_link:11
|
||||
msgid ""
|
||||
"You can use formatting.* for all other formatting options(bold, italic, "
|
||||
"links, and etc.) This method is kept for backward compatibility, and it "
|
||||
"is recommended to use formatting.* for more options."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.user_link:15
|
||||
msgid "the user (not the user_id)"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.user_link:18
|
||||
msgid "include the user_id"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.user_link:21
|
||||
msgid "HTML user link"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.validate_web_app_data:1
|
||||
msgid "Validates web app data."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.webhook_google_functions:1
|
||||
msgid "A webhook endpoint for Google Cloud Functions FaaS."
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.webhook_google_functions:3
|
||||
msgid "The bot instance"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.webhook_google_functions:6
|
||||
msgid "The request object"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.webhook_google_functions:9
|
||||
msgid "The response object"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "int row width"
|
||||
#~ msgstr ""
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,130 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../calldata.rst:4
|
||||
msgid "Callback data factory"
|
||||
msgstr "Фабрика callback data"
|
||||
|
||||
#: ../../calldata.rst:6
|
||||
msgid "Callback data factory in pyTelegramBotAPI"
|
||||
msgstr "Фабрика callback data в pyTelegramBotAPI"
|
||||
|
||||
#: ../../calldata.rst:6
|
||||
msgid ""
|
||||
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, "
|
||||
"factory"
|
||||
msgstr ""
|
||||
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, гайд, callbackdata, "
|
||||
"фабрика"
|
||||
|
||||
#: ../../calldata.rst:12
|
||||
msgid "callback\\_data file"
|
||||
msgstr "Файл callback\\_data"
|
||||
|
||||
#: of telebot.callback_data:1
|
||||
msgid "Callback data factory's file."
|
||||
msgstr "Файл фабрики callback data."
|
||||
|
||||
#: of telebot.callback_data.CallbackData:1
|
||||
#: telebot.callback_data.CallbackDataFilter:1
|
||||
msgid "Bases: :py:class:`object`"
|
||||
msgstr "Базовые классы: :py:class:`object`"
|
||||
|
||||
#: of telebot.callback_data.CallbackData:1
|
||||
msgid "Callback data factory This class will help you to work with CallbackQuery"
|
||||
msgstr "Фабрика Callback data. Этот класс поможет вам в работе с CallbackQuery"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter:1
|
||||
msgid "Generate filter"
|
||||
msgstr "Сгенерировать фильтр"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter
|
||||
#: telebot.callback_data.CallbackData.new
|
||||
#: telebot.callback_data.CallbackData.parse
|
||||
#: telebot.callback_data.CallbackDataFilter.check
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter:3
|
||||
msgid "specified named parameters will be checked with CallbackQuery.data"
|
||||
msgstr "заданные именованные параметры будут проверены в CallbackQuery.data"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter
|
||||
#: telebot.callback_data.CallbackData.new
|
||||
#: telebot.callback_data.CallbackData.parse
|
||||
#: telebot.callback_data.CallbackDataFilter.check
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.filter:4
|
||||
msgid "CallbackDataFilter class"
|
||||
msgstr "Класс CallbackDataFilter"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:1
|
||||
msgid "Generate callback data"
|
||||
msgstr "Сгенерировать callback data"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:3
|
||||
msgid "positional parameters of CallbackData instance parts"
|
||||
msgstr "позиционные параметры экземпляра CallbackData"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:4
|
||||
msgid "named parameters"
|
||||
msgstr "именованные параметры"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.new:5
|
||||
msgid "str"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackData.parse:1
|
||||
msgid "Parse data from the callback data"
|
||||
msgstr "Получить данные из callback data"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.parse:3
|
||||
msgid ""
|
||||
"string, use to telebot.types.CallbackQuery to parse it from string to a "
|
||||
"dict"
|
||||
msgstr ""
|
||||
"string, примените к telebot.types.CallbackQuery, чтобы преобразовать "
|
||||
"callback_data из строки (str) в словарь (dict)"
|
||||
|
||||
#: of telebot.callback_data.CallbackData.parse:4
|
||||
msgid "dict parsed from callback data"
|
||||
msgstr "словарь (dict), полученный из callback data"
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter:1
|
||||
msgid "Filter for CallbackData."
|
||||
msgstr "Фильтр для CallbackData."
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check:1
|
||||
msgid "Checks if query.data appropriates to specified config"
|
||||
msgstr "Проверяет, соответствует ли query.data заданной конфигурации"
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check:3
|
||||
msgid "telebot.types.CallbackQuery"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check:6
|
||||
msgid "True if query.data appropriates to specified config"
|
||||
msgstr "True, если query.data соответствует заданной конфигурации"
|
||||
|
||||
#: of telebot.callback_data.CallbackDataFilter.check
|
||||
msgid "Return type"
|
||||
msgstr ""
|
|
@ -0,0 +1,251 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../formatting.rst:3
|
||||
msgid "Formatting options"
|
||||
msgstr "Параметры форматирования"
|
||||
|
||||
#: ../../formatting.rst:5
|
||||
msgid "Formatting options in pyTelegramBotAPI"
|
||||
msgstr "Параметры форматирования в pyTelegramBotAPI"
|
||||
|
||||
#: ../../formatting.rst:5
|
||||
msgid "html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI"
|
||||
msgstr "html, markdown, parse_mode, форматирование, ptba, pytba, pyTelegramBotAPI"
|
||||
|
||||
#: of telebot.formatting:1
|
||||
msgid "Markdown & HTML formatting functions."
|
||||
msgstr "Функции форматирования Markdown & HTML."
|
||||
|
||||
#: of telebot.formatting.escape_html:1
|
||||
msgid "Escapes HTML characters in a string of HTML."
|
||||
msgstr "Пропускает HTML символы в HTML строке."
|
||||
|
||||
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
|
||||
#: telebot.formatting.format_text telebot.formatting.hbold
|
||||
#: telebot.formatting.hcode telebot.formatting.hide_link
|
||||
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
|
||||
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
|
||||
#: telebot.formatting.hunderline telebot.formatting.mbold
|
||||
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
|
||||
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
|
||||
#: telebot.formatting.munderline
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:3
|
||||
msgid "The string of HTML to escape."
|
||||
msgstr "HTML строка, которую нужно пропустить."
|
||||
|
||||
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
|
||||
#: telebot.formatting.format_text telebot.formatting.hbold
|
||||
#: telebot.formatting.hcode telebot.formatting.hide_link
|
||||
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
|
||||
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
|
||||
#: telebot.formatting.hunderline telebot.formatting.mbold
|
||||
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
|
||||
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
|
||||
#: telebot.formatting.munderline
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:6 telebot.formatting.escape_markdown:8
|
||||
msgid "The escaped string."
|
||||
msgstr "Пропускаемая строка."
|
||||
|
||||
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
|
||||
#: telebot.formatting.format_text telebot.formatting.hbold
|
||||
#: telebot.formatting.hcode telebot.formatting.hide_link
|
||||
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
|
||||
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
|
||||
#: telebot.formatting.hunderline telebot.formatting.mbold
|
||||
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
|
||||
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
|
||||
#: telebot.formatting.munderline
|
||||
msgid "Return type"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_html:7 telebot.formatting.escape_markdown:9
|
||||
#: telebot.formatting.format_text:17 telebot.formatting.hbold:10
|
||||
#: telebot.formatting.hcode:10 telebot.formatting.hide_link:7
|
||||
#: telebot.formatting.hitalic:10 telebot.formatting.hlink:13
|
||||
#: telebot.formatting.hpre:10 telebot.formatting.hspoiler:10
|
||||
#: telebot.formatting.hstrikethrough:10 telebot.formatting.hunderline:10
|
||||
#: telebot.formatting.mbold:10 telebot.formatting.mcode:10
|
||||
#: telebot.formatting.mitalic:10 telebot.formatting.mlink:13
|
||||
#: telebot.formatting.mspoiler:10 telebot.formatting.mstrikethrough:10
|
||||
#: telebot.formatting.munderline:10
|
||||
msgid ":obj:`str`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_markdown:1
|
||||
msgid "Escapes Markdown characters in a string of Markdown."
|
||||
msgstr "Пропускает Markdown символы в Markdown строке."
|
||||
|
||||
#: of telebot.formatting.escape_markdown:3
|
||||
msgid "Credits to: simonsmh"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.formatting.escape_markdown:5
|
||||
msgid "The string of Markdown to escape."
|
||||
msgstr "Markdown строка, которую нужно пропустить."
|
||||
|
||||
#: of telebot.formatting.format_text:1
|
||||
msgid "Formats a list of strings into a single string."
|
||||
msgstr "Преобразовывает набор строк в одну."
|
||||
|
||||
#: of telebot.formatting.format_text:10
|
||||
msgid "Strings to format."
|
||||
msgstr "Строки для преобразования."
|
||||
|
||||
#: of telebot.formatting.format_text:13
|
||||
msgid "The separator to use between each string."
|
||||
msgstr "Символ для разделения строк."
|
||||
|
||||
#: of telebot.formatting.format_text:16 telebot.formatting.hbold:9
|
||||
#: telebot.formatting.hcode:9 telebot.formatting.hitalic:9
|
||||
#: telebot.formatting.hlink:12 telebot.formatting.hpre:9
|
||||
#: telebot.formatting.hspoiler:9 telebot.formatting.hstrikethrough:9
|
||||
#: telebot.formatting.hunderline:9 telebot.formatting.mbold:9
|
||||
#: telebot.formatting.mcode:9 telebot.formatting.mitalic:9
|
||||
#: telebot.formatting.mlink:12 telebot.formatting.mspoiler:9
|
||||
#: telebot.formatting.mstrikethrough:9 telebot.formatting.munderline:9
|
||||
msgid "The formatted string."
|
||||
msgstr "Преобразованная строка."
|
||||
|
||||
#: of telebot.formatting.hbold:1
|
||||
msgid "Returns an HTML-formatted bold string."
|
||||
msgstr "Возвращает выделенную жирным шрифтом HTML строку."
|
||||
|
||||
#: of telebot.formatting.hbold:3 telebot.formatting.mbold:3
|
||||
msgid "The string to bold."
|
||||
msgstr "Строка для выделения жирным шрифтом."
|
||||
|
||||
#: of telebot.formatting.hbold:6 telebot.formatting.hcode:6
|
||||
#: telebot.formatting.hitalic:6 telebot.formatting.hlink:9
|
||||
#: telebot.formatting.hpre:6 telebot.formatting.hspoiler:6
|
||||
#: telebot.formatting.hstrikethrough:6 telebot.formatting.hunderline:6
|
||||
#: telebot.formatting.mbold:6 telebot.formatting.mcode:6
|
||||
#: telebot.formatting.mitalic:6 telebot.formatting.mlink:9
|
||||
#: telebot.formatting.mspoiler:6 telebot.formatting.mstrikethrough:6
|
||||
#: telebot.formatting.munderline:6
|
||||
msgid "True if you need to escape special characters. Defaults to True."
|
||||
msgstr "True если вам нужно пропустить спец. символы. По умолчанию True."
|
||||
|
||||
#: of telebot.formatting.hcode:1
|
||||
msgid "Returns an HTML-formatted code string."
|
||||
msgstr "Возвращает выделенную как код HTML строку."
|
||||
|
||||
#: of telebot.formatting.hcode:3 telebot.formatting.mcode:3
|
||||
msgid "The string to code."
|
||||
msgstr "Строка для выделения как код."
|
||||
|
||||
#: of telebot.formatting.hide_link:1
|
||||
msgid "Hide url of an image."
|
||||
msgstr "Делает невидимым URL изображения."
|
||||
|
||||
#: of telebot.formatting.hide_link:3
|
||||
msgid "The url of the image."
|
||||
msgstr "URL изображения."
|
||||
|
||||
#: of telebot.formatting.hide_link:6
|
||||
msgid "The hidden url."
|
||||
msgstr "Невидимый URL."
|
||||
|
||||
#: of telebot.formatting.hitalic:1
|
||||
msgid "Returns an HTML-formatted italic string."
|
||||
msgstr "Возвращает выделенную курсивом HTML строку."
|
||||
|
||||
#: of telebot.formatting.hitalic:3 telebot.formatting.mitalic:3
|
||||
msgid "The string to italicize."
|
||||
msgstr "Строка для выделения курсивом."
|
||||
|
||||
#: of telebot.formatting.hlink:1
|
||||
msgid "Returns an HTML-formatted link string."
|
||||
msgstr "Возвращает HTML строку с гиперссылкой."
|
||||
|
||||
#: of telebot.formatting.hlink:3 telebot.formatting.mlink:3
|
||||
msgid "The string to link."
|
||||
msgstr "Строка для добавления гиперссылки."
|
||||
|
||||
#: of telebot.formatting.hlink:6 telebot.formatting.mlink:6
|
||||
msgid "The URL to link to."
|
||||
msgstr "URL для создания гиперссылки."
|
||||
|
||||
#: of telebot.formatting.hpre:1
|
||||
msgid "Returns an HTML-formatted preformatted string."
|
||||
msgstr "Возвращает предварительно отформатированную HTML строку."
|
||||
|
||||
#: of telebot.formatting.hpre:3
|
||||
msgid "The string to preformatted."
|
||||
msgstr "Строка для предварительного форматирования."
|
||||
|
||||
#: of telebot.formatting.hspoiler:1
|
||||
msgid "Returns an HTML-formatted spoiler string."
|
||||
msgstr "Возвращает выделенную как спойлер HTML строку."
|
||||
|
||||
#: of telebot.formatting.hspoiler:3 telebot.formatting.mspoiler:3
|
||||
msgid "The string to spoiler."
|
||||
msgstr "Строка для выделения как спойлер."
|
||||
|
||||
#: of telebot.formatting.hstrikethrough:1
|
||||
msgid "Returns an HTML-formatted strikethrough string."
|
||||
msgstr "Возвращает зачеркнутую HTML строку."
|
||||
|
||||
#: of telebot.formatting.hstrikethrough:3 telebot.formatting.mstrikethrough:3
|
||||
msgid "The string to strikethrough."
|
||||
msgstr "Строка для зачеркивания."
|
||||
|
||||
#: of telebot.formatting.hunderline:1
|
||||
msgid "Returns an HTML-formatted underline string."
|
||||
msgstr "Возвращает подчеркнутую HTML строку."
|
||||
|
||||
#: of telebot.formatting.hunderline:3 telebot.formatting.munderline:3
|
||||
msgid "The string to underline."
|
||||
msgstr "Строка для подчёркивания."
|
||||
|
||||
#: of telebot.formatting.mbold:1
|
||||
msgid "Returns a Markdown-formatted bold string."
|
||||
msgstr "Возвращает выделенную жирным шрифтом Markdown строку."
|
||||
|
||||
#: of telebot.formatting.mcode:1
|
||||
msgid "Returns a Markdown-formatted code string."
|
||||
msgstr "Возвращает выделенную как код Markdown строку."
|
||||
|
||||
#: of telebot.formatting.mitalic:1
|
||||
msgid "Returns a Markdown-formatted italic string."
|
||||
msgstr "Возвращает выделенную курсивом Markdown строку."
|
||||
|
||||
#: of telebot.formatting.mlink:1
|
||||
msgid "Returns a Markdown-formatted link string."
|
||||
msgstr "Возвращает Markdown строку с гиперссылкой."
|
||||
|
||||
#: of telebot.formatting.mspoiler:1
|
||||
msgid "Returns a Markdown-formatted spoiler string."
|
||||
msgstr "Возвращает выделенную как спойлер Markdown строку."
|
||||
|
||||
#: of telebot.formatting.mstrikethrough:1
|
||||
msgid "Returns a Markdown-formatted strikethrough string."
|
||||
msgstr "Возвращает зачеркнутую Markdown строку."
|
||||
|
||||
#: of telebot.formatting.munderline:1
|
||||
msgid "Returns a Markdown-formatted underline string."
|
||||
msgstr "Возвращает подчеркнутую Markdown строку."
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../index.rst:8
|
||||
msgid "Welcome to pyTelegramBotAPI's documentation!"
|
||||
msgstr "Добро пожаловать в документацию pyTelegramBotAPI!"
|
||||
|
||||
#: ../../index.rst:10
|
||||
msgid "Official documentation of pyTelegramBotAPI"
|
||||
msgstr "Официальная документация pyTelegramBotAPI"
|
||||
|
||||
#: ../../index.rst:10
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide"
|
||||
msgstr "ptba, pytba, pyTelegramBotAPI, документация, гайд"
|
||||
|
||||
#: ../../index.rst:17
|
||||
msgid "TeleBot"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:18
|
||||
msgid ""
|
||||
"TeleBot is synchronous and asynchronous implementation of `Telegram Bot "
|
||||
"API <https://core.telegram.org/bots/api>`_."
|
||||
msgstr ""
|
||||
"TeleBot это синхронная и асинхронная реализация `Telegram Bot "
|
||||
"API <https://core.telegram.org/bots/api>`_."
|
||||
|
||||
#: ../../index.rst:21
|
||||
msgid "Chats"
|
||||
msgstr "Чаты"
|
||||
|
||||
#: ../../index.rst:22
|
||||
msgid ""
|
||||
"English chat: `Private chat "
|
||||
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
|
||||
msgstr ""
|
||||
"Англоязычный чат: `Private chat "
|
||||
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
|
||||
|
||||
#: ../../index.rst:24
|
||||
msgid ""
|
||||
"Russian chat: `@pytelegrambotapi_talks_ru "
|
||||
"<https://t.me/pytelegrambotapi_talks_ru>`__"
|
||||
msgstr ""
|
||||
"Русскоязычный чат: `@pytelegrambotapi_talks_ru "
|
||||
"<https://t.me/pytelegrambotapi_talks_ru>`__"
|
||||
|
||||
#: ../../index.rst:26
|
||||
msgid "News: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
|
||||
msgstr "Новости: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
|
||||
|
||||
#: ../../index.rst:28
|
||||
msgid "Pypi: `Pypi <https://pypi.org/project/pyTelegramBotAPI/>`__"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:30
|
||||
msgid ""
|
||||
"Source: `Github repository "
|
||||
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
|
||||
msgstr ""
|
||||
"Исходники: `Github repository "
|
||||
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
|
||||
|
||||
#: ../../index.rst:33
|
||||
msgid "Some features:"
|
||||
msgstr "Некоторые особенности:"
|
||||
|
||||
#: ../../index.rst:34
|
||||
msgid "Easy to learn and use."
|
||||
msgstr "Простой в изучении и использовании."
|
||||
|
||||
#: ../../index.rst:36
|
||||
msgid "Easy to understand."
|
||||
msgstr "Простой в понимании."
|
||||
|
||||
#: ../../index.rst:38
|
||||
msgid "Both sync and async."
|
||||
msgstr "И синхронный, и асинхронный."
|
||||
|
||||
#: ../../index.rst:40
|
||||
msgid "Examples on features."
|
||||
msgstr "Примеры возможностей."
|
||||
|
||||
#: ../../index.rst:42
|
||||
msgid "States"
|
||||
msgstr "Состояния (стейты, FSM)"
|
||||
|
||||
#: ../../index.rst:44
|
||||
msgid "And more..."
|
||||
msgstr "И другое..."
|
||||
|
||||
#: ../../index.rst:47
|
||||
msgid "Content"
|
||||
msgstr "Содержимое"
|
||||
|
||||
#: ../../index.rst:63
|
||||
msgid "Indices and tables"
|
||||
msgstr "Ссылки"
|
||||
|
||||
#: ../../index.rst:65
|
||||
msgid ":ref:`genindex`"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:66
|
||||
msgid ":ref:`modindex`"
|
||||
msgstr ""
|
||||
|
||||
#: ../../index.rst:67
|
||||
msgid ":ref:`search`"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../install.rst:3
|
||||
msgid "Installation Guide"
|
||||
msgstr "Гайд по установке"
|
||||
|
||||
#: ../../install.rst:5
|
||||
msgid "Installation of pyTelegramBotAPI"
|
||||
msgstr "Установка pyTelegramBotAPI"
|
||||
|
||||
#: ../../install.rst:5
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, installation, guide"
|
||||
msgstr "ptba, pytba, pyTelegramBotAPI, установка, гайд"
|
||||
|
||||
#: ../../install.rst:11
|
||||
msgid "Using PIP"
|
||||
msgstr "Используя PIP"
|
||||
|
||||
#: ../../install.rst:17
|
||||
msgid "Using pipenv"
|
||||
msgstr "Используя pipenv"
|
||||
|
||||
#: ../../install.rst:23
|
||||
msgid "By cloning repository"
|
||||
msgstr "Клонируя репозиторий"
|
||||
|
||||
#: ../../install.rst:31
|
||||
msgid "Directly using pip"
|
||||
msgstr "Напрямую используя pip"
|
||||
|
||||
#: ../../install.rst:37
|
||||
msgid "It is generally recommended to use the first option."
|
||||
msgstr "Рекомендуется использовать первый вариант."
|
||||
|
||||
#: ../../install.rst:39
|
||||
msgid ""
|
||||
"While the API is production-ready, it is still under development and it "
|
||||
"has regular updates, do not forget to update it regularly by calling:"
|
||||
msgstr "Новые версии библиотеки имеют больше фич, улучшений и баг фиксов. Не забывайте"
|
||||
" обновляться вызывая:"
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../quick_start.rst:4
|
||||
msgid "Quick start"
|
||||
msgstr "Быстрый старт"
|
||||
|
||||
#: ../../quick_start.rst:6
|
||||
msgid "Quickstart guide"
|
||||
msgstr "Быстрый старт - гайд"
|
||||
|
||||
#: ../../quick_start.rst:6
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide"
|
||||
msgstr "ptba, pytba, pyTelegramBotAPI, быстрый старт, гайд"
|
||||
|
||||
#: ../../quick_start.rst:11
|
||||
msgid "Synchronous TeleBot"
|
||||
msgstr "Синхронный телебот"
|
||||
|
||||
#: ../../quick_start.rst:16
|
||||
msgid "Asynchronous TeleBot"
|
||||
msgstr "Асинхронный телебот"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,393 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2022, coder2020official
|
||||
# This file is distributed under the same license as the pyTelegramBotAPI
|
||||
# Documentation package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-08 23:07+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: ../../source/util.rst:3
|
||||
msgid "Utils"
|
||||
msgstr "Утилиты"
|
||||
|
||||
#: ../../source/util.rst:5
|
||||
msgid "Utils in pyTelegramBotAPI"
|
||||
msgstr "Утилиты в pyTelegramBotAPI"
|
||||
|
||||
#: ../../source/util.rst:5
|
||||
msgid "ptba, pytba, pyTelegramBotAPI, utils, guide"
|
||||
msgstr "ptba, pytba, pyTelegramBotAPI, утилиты, гайд"
|
||||
|
||||
#: ../../source/util.rst:11
|
||||
msgid "util file"
|
||||
msgstr "Файл util"
|
||||
|
||||
#: of telebot.util.antiflood:1
|
||||
msgid ""
|
||||
"Use this function inside loops in order to avoid getting TooManyRequests "
|
||||
"error. Example:"
|
||||
msgstr ""
|
||||
"Используйте эту функцию в циклах, чтобы избежать ошибки TooManyRequests. "
|
||||
"Пример:"
|
||||
|
||||
#: of telebot.service_utils.is_bytes telebot.service_utils.is_dict
|
||||
#: telebot.service_utils.is_pil_image telebot.util.antiflood
|
||||
#: telebot.util.escape telebot.util.extract_arguments
|
||||
#: telebot.util.extract_command telebot.util.is_command
|
||||
#: telebot.util.parse_web_app_data telebot.util.quick_markup
|
||||
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
|
||||
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:10
|
||||
msgid "The function to call"
|
||||
msgstr "Вызываемая функция"
|
||||
|
||||
#: of telebot.util.antiflood:13
|
||||
msgid "Number of retries to send"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:16
|
||||
msgid "The arguments to pass to the function"
|
||||
msgstr "Аргументы, для передачи в функцию"
|
||||
|
||||
#: of telebot.util.antiflood:19
|
||||
msgid "The keyword arguments to pass to the function"
|
||||
msgstr "Именованные аргументы для передачи в функцию"
|
||||
|
||||
#: of telebot.service_utils.generate_random_token
|
||||
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
|
||||
#: telebot.service_utils.is_pil_image telebot.util.antiflood
|
||||
#: telebot.util.escape telebot.util.extract_arguments
|
||||
#: telebot.util.extract_command telebot.util.is_command
|
||||
#: telebot.util.parse_web_app_data telebot.util.quick_markup
|
||||
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
|
||||
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.antiflood:22
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.chunks:1
|
||||
msgid "Yield successive n-sized chunks from lst."
|
||||
msgstr "Генерирует последовательные части списка, состоящие из n элементов."
|
||||
|
||||
#: ../../docstring of telebot.util.content_type_media:1
|
||||
msgid "Contains all media content types."
|
||||
msgstr "Содержит все виды медиа."
|
||||
|
||||
#: ../../docstring of telebot.util.content_type_service:1
|
||||
msgid "Contains all service content types such as `User joined the group`."
|
||||
msgstr "Содержит все виды сервисных сообщений, такие как `User joined the group`."
|
||||
|
||||
#: of telebot.util.escape:1
|
||||
msgid ""
|
||||
"Replaces the following chars in `text` ('&' with '&', '<' with '<'"
|
||||
" and '>' with '>')."
|
||||
msgstr ""
|
||||
"Заменяет следующие символы в `text` ('&' на '&', '<' на '<' и '>' "
|
||||
"на '>')."
|
||||
|
||||
#: of telebot.util.escape:3
|
||||
msgid "the text to escape"
|
||||
msgstr "Текст для замены символов"
|
||||
|
||||
#: of telebot.util.escape:4
|
||||
msgid "the escaped text"
|
||||
msgstr "Отформатированный текст"
|
||||
|
||||
#: of telebot.util.extract_arguments:1
|
||||
msgid "Returns the argument after the command."
|
||||
msgstr "Возвращает аргументы команды."
|
||||
|
||||
#: of telebot.util.extract_arguments:3 telebot.util.extract_command:4
|
||||
msgid "Examples:"
|
||||
msgstr "Примеры:"
|
||||
|
||||
#: of telebot.util.extract_arguments:10
|
||||
msgid "String to extract the arguments from a command"
|
||||
msgstr "Строка для извлечения аргументов команды"
|
||||
|
||||
#: of telebot.util.extract_arguments:13
|
||||
msgid "the arguments if `text` is a command (according to is_command), else None."
|
||||
msgstr ""
|
||||
"Аргументы, если `text` является командой (согласно is_command), в "
|
||||
"остальных случаях None."
|
||||
|
||||
#: of telebot.service_utils.generate_random_token
|
||||
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
|
||||
#: telebot.service_utils.is_pil_image telebot.util.extract_arguments
|
||||
#: telebot.util.extract_command telebot.util.is_command
|
||||
#: telebot.util.quick_markup telebot.util.smart_split telebot.util.split_string
|
||||
#: telebot.util.user_link
|
||||
msgid "Return type"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.extract_arguments:14 telebot.util.extract_command:16
|
||||
msgid ":obj:`str` or :obj:`None`"
|
||||
msgstr ":obj:`str` или :obj:`None`"
|
||||
|
||||
#: of telebot.util.extract_command:1
|
||||
msgid ""
|
||||
"Extracts the command from `text` (minus the '/') if `text` is a command "
|
||||
"(see is_command). If `text` is not a command, this function returns None."
|
||||
msgstr ""
|
||||
"Извлекает команду из `text` (исключает '/') если `text` является командой"
|
||||
" (см. is_command). Если `text` не является командой, эта функция "
|
||||
"возвращает None."
|
||||
|
||||
#: of telebot.util.extract_command:12
|
||||
msgid "String to extract the command from"
|
||||
msgstr "Строка, из которой нужно извлечь команду"
|
||||
|
||||
#: of telebot.util.extract_command:15
|
||||
msgid "the command if `text` is a command (according to is_command), else None."
|
||||
msgstr ""
|
||||
"Команда, если `text` является командой (согласно is_command), в остальных"
|
||||
" случаях None."
|
||||
|
||||
#: of telebot.service_utils.generate_random_token:1
|
||||
msgid ""
|
||||
"Generates a random token consisting of letters and digits, 16 characters "
|
||||
"long."
|
||||
msgstr ""
|
||||
"Генерирует рандомный токен, состоящий из латинских букв и цифр длиной 16 "
|
||||
"символов."
|
||||
|
||||
#: of telebot.service_utils.generate_random_token:3
|
||||
msgid "a random token"
|
||||
msgstr "Сгенерированный токен"
|
||||
|
||||
#: of telebot.service_utils.generate_random_token:4 telebot.util.user_link:22
|
||||
msgid ":obj:`str`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.service_utils.is_bytes:1
|
||||
msgid "Returns True if the given object is a bytes object."
|
||||
msgstr "Возвращает True если полученный объект является bytes."
|
||||
|
||||
#: of telebot.service_utils.is_bytes:3 telebot.service_utils.is_dict:3
|
||||
#: telebot.service_utils.is_pil_image:3
|
||||
msgid "object to be checked"
|
||||
msgstr "Объект для проверки"
|
||||
|
||||
#: of telebot.service_utils.is_bytes:6
|
||||
msgid "True if the given object is a bytes object."
|
||||
msgstr "True, если полученный объект является bytes."
|
||||
|
||||
#: of telebot.service_utils.is_bytes:7 telebot.service_utils.is_dict:7
|
||||
#: telebot.service_utils.is_pil_image:7 telebot.util.is_command:7
|
||||
msgid ":obj:`bool`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.is_command:1
|
||||
msgid ""
|
||||
"Checks if `text` is a command. Telegram chat commands start with the '/' "
|
||||
"character."
|
||||
msgstr ""
|
||||
"Проверяет, является ли `text` командой. Команды в Telegram начинаются с "
|
||||
"символа '/'."
|
||||
|
||||
#: of telebot.util.is_command:3
|
||||
msgid "Text to check."
|
||||
msgstr "Текст для проверки."
|
||||
|
||||
#: of telebot.util.is_command:6
|
||||
msgid "True if `text` is a command, else False."
|
||||
msgstr "True, если `text` является командой, иначе False."
|
||||
|
||||
#: of telebot.service_utils.is_dict:1
|
||||
msgid "Returns True if the given object is a dictionary."
|
||||
msgstr "Возвращает True, если полученный объект является словарём (dict)."
|
||||
|
||||
#: of telebot.service_utils.is_dict:6
|
||||
msgid "True if the given object is a dictionary."
|
||||
msgstr "True, если полученный объект является словарём (dict)."
|
||||
|
||||
#: of telebot.service_utils.is_pil_image:1
|
||||
msgid "Returns True if the given object is a PIL.Image.Image object."
|
||||
msgstr "Возвращает True, если полученный объект является PIL.Image.Image."
|
||||
|
||||
#: of telebot.service_utils.is_pil_image:6
|
||||
msgid "True if the given object is a PIL.Image.Image object."
|
||||
msgstr "True, если полученный объект является PIL.Image.Image."
|
||||
|
||||
#: of telebot.service_utils.is_string:1
|
||||
msgid "Returns True if the given object is a string."
|
||||
msgstr "Возвращает True, если полученный объект является строкой (str)."
|
||||
|
||||
#: of telebot.util.parse_web_app_data:1
|
||||
msgid "Parses web app data."
|
||||
msgstr "Обрабатывает данные, полученные от web app."
|
||||
|
||||
#: of telebot.util.parse_web_app_data:3 telebot.util.validate_web_app_data:3
|
||||
msgid "The bot token"
|
||||
msgstr "Токен бота"
|
||||
|
||||
#: of telebot.util.parse_web_app_data:6 telebot.util.validate_web_app_data:6
|
||||
msgid "The raw init data"
|
||||
msgstr "Необработанные данные"
|
||||
|
||||
#: of telebot.util.parse_web_app_data:9 telebot.util.validate_web_app_data:9
|
||||
msgid "The parsed init data"
|
||||
msgstr "Обработанные данные"
|
||||
|
||||
#: of telebot.util.quick_markup:1
|
||||
msgid ""
|
||||
"Returns a reply markup from a dict in this format: {'text': kwargs} This "
|
||||
"is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2"
|
||||
" = InlineKeyboardButton(...)'"
|
||||
msgstr ""
|
||||
"Возвращает reply markup из словаря следующего формата: {'text': kwargs}. "
|
||||
"Удобно использовать вместо постоянного использования 'btn1 = "
|
||||
"InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)'"
|
||||
|
||||
#: of telebot.util.quick_markup:4 telebot.util.user_link:5
|
||||
msgid "Example:"
|
||||
msgstr "Пример:"
|
||||
|
||||
#: of telebot.util.quick_markup:6
|
||||
msgid "Using quick_markup:"
|
||||
msgstr "Используя quick_markup:"
|
||||
|
||||
#: of telebot.util.quick_markup:31
|
||||
msgid ""
|
||||
"a dict containing all buttons to create in this format: {text: kwargs} "
|
||||
"{str:}"
|
||||
msgstr ""
|
||||
"Словарь, содержащий все кнопки для создания reply markup в следующем "
|
||||
"формате: {text: kwargs} {str:}"
|
||||
|
||||
#: of telebot.util.quick_markup:34
|
||||
msgid "number of :class:`telebot.types.InlineKeyboardButton` objects on each row"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:37
|
||||
msgid "InlineKeyboardMarkup"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.quick_markup:38
|
||||
msgid ":obj:`types.InlineKeyboardMarkup`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.smart_split:1
|
||||
msgid ""
|
||||
"Splits one string into multiple strings, with a maximum amount of "
|
||||
"`chars_per_string` characters per string. This is very useful for "
|
||||
"splitting one giant message into multiples. If `chars_per_string` > 4096:"
|
||||
" `chars_per_string` = 4096. Splits by '\\n', '. ' or ' ' in exactly this "
|
||||
"priority."
|
||||
msgstr ""
|
||||
"Разбивает строку на несколько, каждая из которых будет не длиннее "
|
||||
"`characters_per_string`. Удобно использовать для разбиения одного "
|
||||
"гигантского сообщения на несколько. Если `chars_per_string` > 4096: "
|
||||
"`chars_per_string` = 4096. Разбивает строку по '\\n', '. ' или ' ' именно"
|
||||
" в таком порядке."
|
||||
|
||||
#: of telebot.util.smart_split:6 telebot.util.split_string:4
|
||||
msgid "The text to split"
|
||||
msgstr "Текст для разбиения"
|
||||
|
||||
#: of telebot.util.smart_split:9
|
||||
msgid "The number of maximum characters per part the text is split to."
|
||||
msgstr ""
|
||||
"Максимальное количество символов в части текста, на которые он будет "
|
||||
"разбит."
|
||||
|
||||
#: of telebot.util.smart_split:12 telebot.util.split_string:10
|
||||
msgid "The splitted text as a list of strings."
|
||||
msgstr "Список частей разбитого текста."
|
||||
|
||||
#: of telebot.util.smart_split:13 telebot.util.split_string:11
|
||||
msgid ":obj:`list` of :obj:`str`"
|
||||
msgstr ""
|
||||
|
||||
#: of telebot.util.split_string:1
|
||||
msgid ""
|
||||
"Splits one string into multiple strings, with a maximum amount of "
|
||||
"`chars_per_string` characters per string. This is very useful for "
|
||||
"splitting one giant message into multiples."
|
||||
msgstr ""
|
||||
"Разбивает одну строку на несколько, каждая из которых будет не длиннее "
|
||||
"`characters_per_string`. Удобно использовать для разбиения одного "
|
||||
"гигантского сообщения на несколько."
|
||||
|
||||
#: of telebot.util.split_string:7
|
||||
msgid "The number of characters per line the text is split into."
|
||||
msgstr "Количество символов в одной строке, на которые будет разбит текст."
|
||||
|
||||
#: ../../docstring of telebot.util.update_types:1
|
||||
msgid "All update types, should be used for allowed_updates parameter in polling."
|
||||
msgstr ""
|
||||
"Все виды апдейтов, рекомендуется использовать в качестве параметра "
|
||||
"allowed_updates функции polling."
|
||||
|
||||
#: of telebot.util.user_link:1
|
||||
msgid ""
|
||||
"Returns an HTML user link. This is useful for reports. Attention: Don't "
|
||||
"forget to set parse_mode to 'HTML'!"
|
||||
msgstr ""
|
||||
"Возвращает HTML ссылку на пользователя. Удобно использовать для отчетов. "
|
||||
"Важно: Не забудьте установить значение 'HTML' в parse_mode!"
|
||||
|
||||
#: of telebot.util.user_link:11
|
||||
msgid ""
|
||||
"You can use formatting.* for all other formatting options(bold, italic, "
|
||||
"links, and etc.) This method is kept for backward compatibility, and it "
|
||||
"is recommended to use formatting.* for more options."
|
||||
msgstr ""
|
||||
"Вы можете использовать formatting.* во всех остальных вариантах "
|
||||
"форматирования(bold, italic, links, и прочее). Этот метод сохранён для "
|
||||
"обратной совместимости, рекомендуется использовать formatting.* для "
|
||||
"большего количества вариантов."
|
||||
|
||||
#: of telebot.util.user_link:15
|
||||
msgid "the user (not the user_id)"
|
||||
msgstr "Пользователь (не id пользователя)"
|
||||
|
||||
#: of telebot.util.user_link:18
|
||||
msgid "include the user_id"
|
||||
msgstr "Добавить id пользователя"
|
||||
|
||||
#: of telebot.util.user_link:21
|
||||
msgid "HTML user link"
|
||||
msgstr "Ссылка на пользователя в формате HTML"
|
||||
|
||||
#: of telebot.util.validate_web_app_data:1
|
||||
msgid "Validates web app data."
|
||||
msgstr "Проверяет данные, полученные от web app."
|
||||
|
||||
#: of telebot.util.webhook_google_functions:1
|
||||
msgid "A webhook endpoint for Google Cloud Functions FaaS."
|
||||
msgstr "Endpoint вебхука для Google Cloud Functions FaaS."
|
||||
|
||||
#: of telebot.util.webhook_google_functions:3
|
||||
msgid "The bot instance"
|
||||
msgstr "Инстанс бота"
|
||||
|
||||
#: of telebot.util.webhook_google_functions:6
|
||||
msgid "The request object"
|
||||
msgstr "HTTP-запрос"
|
||||
|
||||
#: of telebot.util.webhook_google_functions:9
|
||||
msgid "The response object"
|
||||
msgstr "Объект, полученный в качестве ответа"
|
||||
|
||||
#~ msgid "int row width"
|
||||
#~ msgstr "Количество кнопок в одной строке, int"
|
||||
|
|
@ -21,14 +21,6 @@ custom_filters file
|
|||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Synchronous storage for states
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: telebot.storage
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
handler_backends file
|
||||
--------------------------------
|
||||
|
||||
|
@ -37,3 +29,13 @@ handler_backends file
|
|||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Extensions
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
.. automodule:: telebot.ext.sync.webhooks
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
|
@ -0,0 +1,27 @@
|
|||
from telebot.async_telebot import AsyncTeleBot
|
||||
from telebot.asyncio_handler_backends import ContinueHandling
|
||||
|
||||
|
||||
bot = AsyncTeleBot('TOKEN')
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
async def start(message):
|
||||
await bot.send_message(message.chat.id, 'Hello World!')
|
||||
return ContinueHandling()
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
async def start2(message):
|
||||
"""
|
||||
This handler comes after the first one, but it will never be called.
|
||||
But you can call it by returning ContinueHandling() in the first handler.
|
||||
|
||||
If you return ContinueHandling() in the first handler, the next
|
||||
registered handler with appropriate filters will be called.
|
||||
"""
|
||||
await bot.send_message(message.chat.id, 'Hello World2!')
|
||||
|
||||
import asyncio
|
||||
asyncio.run(bot.polling()) # just a reminder that infinity polling
|
||||
# wraps polling into try/except block just as sync version,
|
||||
# but you can use any of them because neither of them stops if you
|
||||
# pass non_stop=True
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# This is a simple echo bot using the decorator mechanism.
|
||||
# It echoes any incoming text messages.
|
||||
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
bot = AsyncTeleBot('TOKEN')
|
||||
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
async def send_welcome(message):
|
||||
await bot.reply_to(message, """\
|
||||
Hi there, I am EchoBot.
|
||||
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
|
||||
""")
|
||||
|
||||
|
||||
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
|
||||
@bot.message_handler(func=lambda message: True)
|
||||
async def echo_message(message):
|
||||
await bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
import asyncio
|
||||
# only for versions 4.7.0+
|
||||
asyncio.run(bot.polling(restart_on_change=True))
|
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This is an async echo bot using decorators and webhook with aiohttp
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import logging
|
||||
import ssl
|
||||
import asyncio
|
||||
from aiohttp import web
|
||||
import telebot
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
WEBHOOK_HOST = '<ip/host where the bot is running>'
|
||||
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
|
||||
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN)
|
||||
|
||||
# Quick'n'dirty SSL certificate generation:
|
||||
#
|
||||
# openssl genrsa -out webhook_pkey.pem 2048
|
||||
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
|
||||
#
|
||||
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
|
||||
# with the same value in you put in WEBHOOK_HOST
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
bot = AsyncTeleBot(API_TOKEN)
|
||||
|
||||
|
||||
# Process webhook calls
|
||||
async def handle(request):
|
||||
if request.match_info.get('token') == bot.token:
|
||||
request_body_dict = await request.json()
|
||||
update = telebot.types.Update.de_json(request_body_dict)
|
||||
asyncio.ensure_future(bot.process_new_updates([update]))
|
||||
return web.Response()
|
||||
else:
|
||||
return web.Response(status=403)
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
async def send_welcome(message):
|
||||
await bot.reply_to(message,
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
# Handle all other messages
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
async def echo_message(message):
|
||||
await bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# Remove webhook and closing session before exiting
|
||||
async def shutdown(app):
|
||||
logger.info('Shutting down: removing webhook')
|
||||
await bot.remove_webhook()
|
||||
logger.info('Shutting down: closing session')
|
||||
await bot.close_session()
|
||||
|
||||
|
||||
async def setup():
|
||||
# Remove webhook, it fails sometimes the set if there is a previous webhook
|
||||
logger.info('Starting up: removing old webhook')
|
||||
await bot.remove_webhook()
|
||||
# Set webhook
|
||||
logger.info('Starting up: setting webhook')
|
||||
await bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
app = web.Application()
|
||||
app.router.add_post('/{token}/', handle)
|
||||
app.on_cleanup.append(shutdown)
|
||||
return app
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Build ssl context
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
|
||||
# Start aiohttp server
|
||||
web.run_app(
|
||||
setup(),
|
||||
host=WEBHOOK_LISTEN,
|
||||
port=WEBHOOK_PORT,
|
||||
ssl_context=context,
|
||||
)
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# This is a simple echo bot using the decorator mechanism.
|
||||
# It echoes any incoming text messages.
|
||||
# Example on built-in function to receive and process webhooks.
|
||||
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
import asyncio
|
||||
bot = AsyncTeleBot('TOKEN')
|
||||
|
||||
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
DOMAIN = '1.2.3.4' # either domain, or ip address of vps
|
||||
|
||||
# Quick'n'dirty SSL certificate generation:
|
||||
#
|
||||
# openssl genrsa -out webhook_pkey.pem 2048
|
||||
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
|
||||
#
|
||||
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
|
||||
# with the same value in you put in WEBHOOK_HOST
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
async def send_welcome(message):
|
||||
await bot.reply_to(message, """\
|
||||
Hi there, I am EchoBot.
|
||||
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
|
||||
""")
|
||||
|
||||
|
||||
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
|
||||
@bot.message_handler(func=lambda message: True)
|
||||
async def echo_message(message):
|
||||
await bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# it uses fastapi + uvicorn
|
||||
asyncio.run(bot.run_webhooks(
|
||||
listen=DOMAIN,
|
||||
certificate=WEBHOOK_SSL_CERT,
|
||||
certificate_key=WEBHOOK_SSL_PRIV
|
||||
))
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
Asynchronous Telegram Echo Bot example.
|
||||
|
||||
This is a simple bot that echoes each message that is received onto the chat.
|
||||
It uses the Starlette ASGI framework to receive updates via webhook requests.
|
||||
"""
|
||||
|
||||
import uvicorn
|
||||
from starlette.applications import Starlette
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import PlainTextResponse, Response
|
||||
from starlette.routing import Route
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
from telebot.types import Message, Update
|
||||
|
||||
API_TOKEN = "TOKEN"
|
||||
|
||||
WEBHOOK_HOST = "<ip/domain>"
|
||||
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
|
||||
WEBHOOK_LISTEN = "0.0.0.0"
|
||||
WEBHOOK_SSL_CERT = "./webhook_cert.pem" # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = "./webhook_pkey.pem" # Path to the ssl private key
|
||||
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}/telegram"
|
||||
WEBHOOK_SECRET_TOKEN = "SECRET_TOKEN"
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
bot = AsyncTeleBot(token=API_TOKEN)
|
||||
|
||||
# BOT HANDLERS
|
||||
@bot.message_handler(commands=["help", "start"])
|
||||
async def send_welcome(message: Message):
|
||||
"""
|
||||
Handle '/start' and '/help'
|
||||
"""
|
||||
await bot.reply_to(
|
||||
message,
|
||||
("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you."),
|
||||
)
|
||||
|
||||
|
||||
@bot.message_handler(func=lambda _: True, content_types=["text"])
|
||||
async def echo_message(message: Message):
|
||||
"""
|
||||
Handle all other messages
|
||||
"""
|
||||
await bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# WEBSERVER HANDLERS
|
||||
async def telegram(request: Request) -> Response:
|
||||
"""Handle incoming Telegram updates."""
|
||||
token_header_name = "X-Telegram-Bot-Api-Secret-Token"
|
||||
if request.headers.get(token_header_name) != WEBHOOK_SECRET_TOKEN:
|
||||
return PlainTextResponse("Forbidden", status_code=403)
|
||||
await bot.process_new_updates([Update.de_json(await request.json())])
|
||||
return Response()
|
||||
|
||||
|
||||
async def startup() -> None:
|
||||
"""Register webhook for telegram updates."""
|
||||
webhook_info = await bot.get_webhook_info(30)
|
||||
if WEBHOOK_URL != webhook_info.url:
|
||||
logger.debug(
|
||||
f"updating webhook url, old: {webhook_info.url}, new: {WEBHOOK_URL}"
|
||||
)
|
||||
if not await bot.set_webhook(
|
||||
url=WEBHOOK_URL, secret_token=WEBHOOK_SECRET_TOKEN
|
||||
):
|
||||
raise RuntimeError("unable to set webhook")
|
||||
|
||||
|
||||
app = Starlette(
|
||||
routes=[
|
||||
Route("/telegram", telegram, methods=["POST"]),
|
||||
],
|
||||
on_startup=[startup],
|
||||
)
|
||||
|
||||
|
||||
uvicorn.run(
|
||||
app,
|
||||
host=WEBHOOK_HOST,
|
||||
port=WEBHOOK_LISTEN,
|
||||
ssl_certfile=WEBHOOK_SSL_CERT,
|
||||
ssl_keyfile=WEBHOOK_SSL_PRIV,
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
from telebot import TeleBot
|
||||
from telebot.handler_backends import ContinueHandling
|
||||
|
||||
|
||||
bot = TeleBot('TOKEN')
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
bot.send_message(message.chat.id, 'Hello World!')
|
||||
return ContinueHandling()
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start2(message):
|
||||
"""
|
||||
This handler comes after the first one, but it will never be called.
|
||||
But you can call it by returning ContinueHandling() in the first handler.
|
||||
|
||||
If you return ContinueHandling() in the first handler, the next
|
||||
registered handler with appropriate filters will be called.
|
||||
"""
|
||||
bot.send_message(message.chat.id, 'Hello World2!')
|
||||
|
||||
bot.infinity_polling()
|
|
@ -47,7 +47,7 @@ def start_ex(message):
|
|||
|
||||
|
||||
# Any state
|
||||
@bot.message_handler(state="*", commands='cancel')
|
||||
@bot.message_handler(state="*", commands=['cancel'])
|
||||
def any_state(message):
|
||||
"""
|
||||
Cancel state
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# This is a simple echo bot using the decorator mechanism.
|
||||
# It echoes any incoming text messages.
|
||||
|
||||
import telebot
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message, """\
|
||||
Hi there, I am EchoBot.
|
||||
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
|
||||
""")
|
||||
|
||||
|
||||
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
|
||||
@bot.message_handler(func=lambda message: True)
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
# only for versions 4.7.0+
|
||||
bot.infinity_polling(restart_on_change=True)
|
|
@ -42,7 +42,7 @@ def query_video(inline_query):
|
|||
try:
|
||||
r = types.InlineQueryResultVideo('1',
|
||||
'https://github.com/eternnoir/pyTelegramBotAPI/blob/master/tests/test_data/test_video.mp4?raw=true',
|
||||
'video/mp4', 'Video',
|
||||
'video/mp4',
|
||||
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg',
|
||||
'Title'
|
||||
)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# This is an example file to create quiz polls
|
||||
import telebot
|
||||
|
||||
API_TOKEN = "<api_token>"
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
@bot.message_handler(commands=["poll"])
|
||||
def create_poll(message):
|
||||
bot.send_message(message.chat.id, "English Article Test")
|
||||
answer_options = ["a", "an", "the", "-"]
|
||||
|
||||
bot.send_poll(
|
||||
chat_id=message.chat.id,
|
||||
question="We are going to '' park.",
|
||||
options=answer_options,
|
||||
type="quiz",
|
||||
correct_option_id=2,
|
||||
is_anonymous=False,
|
||||
)
|
||||
|
||||
|
||||
@bot.poll_answer_handler()
|
||||
def handle_poll(poll):
|
||||
# This handler can be used to log User answers and to send next poll
|
||||
pass
|
||||
|
||||
|
||||
bot.infinity_polling()
|
|
@ -0,0 +1,50 @@
|
|||
"""
|
||||
Example of running PyTelegramBotAPI serverless in Amazon AWS Lambdaю
|
||||
You have to set your lambda's url as telegram webhook manually https://core.telegram.org/bots/api#setwebhook
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
import telebot
|
||||
import json
|
||||
import os
|
||||
|
||||
API_TOKEN = os.environ['TELEGRAM_TOKEN']
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN, threaded=False)
|
||||
|
||||
|
||||
def process_event(event):
|
||||
# Get telegram webhook json from event
|
||||
request_body_dict = json.loads(event['body'])
|
||||
# Parse updates from json
|
||||
update = telebot.types.Update.de_json(request_body_dict)
|
||||
# Run handlers and etc for updates
|
||||
bot.process_new_updates([update])
|
||||
|
||||
|
||||
def lambda_handler(event, context):
|
||||
# Process event from aws and respond
|
||||
process_event(event)
|
||||
return {
|
||||
'statusCode': 200
|
||||
}
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message,
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
# Handle all other messages
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# This is a simple echo bot using the decorator mechanism.
|
||||
# It echoes any incoming text messages.
|
||||
# Example on built-in function to receive and process webhooks.
|
||||
|
||||
import telebot
|
||||
|
||||
API_TOKEN = 'TOKEN'
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
DOMAIN = '1.2.3.4' # either domain, or ip address of vps
|
||||
|
||||
# Quick'n'dirty SSL certificate generation:
|
||||
#
|
||||
# openssl genrsa -out webhook_pkey.pem 2048
|
||||
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
|
||||
#
|
||||
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
|
||||
# with the same value in you put in WEBHOOK_HOST
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message, """\
|
||||
Hi there, I am EchoBot.
|
||||
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
|
||||
""")
|
||||
|
||||
|
||||
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
|
||||
@bot.message_handler(func=lambda message: True)
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
bot.run_webhooks(
|
||||
listen=DOMAIN,
|
||||
certificate=WEBHOOK_SSL_CERT,
|
||||
certificate_key=WEBHOOK_SSL_PRIV
|
||||
)
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import logging
|
||||
import fastapi
|
||||
import uvicorn
|
||||
import telebot
|
||||
|
||||
API_TOKEN = 'TOKEN'
|
||||
|
@ -33,12 +34,14 @@ telebot.logger.setLevel(logging.INFO)
|
|||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
app = fastapi.FastAPI()
|
||||
app = fastapi.FastAPI(docs=None, redoc_url=None)
|
||||
|
||||
|
||||
# Process webhook calls
|
||||
@app.post(f'/{API_TOKEN}/')
|
||||
def process_webhook(update: dict):
|
||||
"""
|
||||
Process webhook calls
|
||||
"""
|
||||
if update:
|
||||
update = telebot.types.Update.de_json(update)
|
||||
bot.process_new_updates([update])
|
||||
|
@ -46,18 +49,21 @@ def process_webhook(update: dict):
|
|||
return
|
||||
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
"""
|
||||
Handle '/start' and '/help'
|
||||
"""
|
||||
bot.reply_to(message,
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
# Handle all other messages
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
"""
|
||||
Handle all other messages
|
||||
"""
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
|
@ -65,11 +71,12 @@ def echo_message(message):
|
|||
bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
bot.set_webhook(
|
||||
url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r')
|
||||
)
|
||||
|
||||
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
app,
|
||||
host=WEBHOOK_LISTEN,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pytest
|
||||
requests==2.20.0
|
||||
wheel==0.24.0
|
||||
requests==2.31.0
|
||||
wheel==0.38.1
|
||||
aiohttp>=3.8.0,<3.9.0
|
6
setup.py
6
setup.py
|
@ -27,7 +27,13 @@ setup(name='pyTelegramBotAPI',
|
|||
'json': 'ujson',
|
||||
'PIL': 'Pillow',
|
||||
'redis': 'redis>=3.4.1',
|
||||
'aioredis': 'aioredis',
|
||||
'aiohttp': 'aiohttp',
|
||||
'fastapi': 'fastapi',
|
||||
'uvicorn': 'uvicorn',
|
||||
'psutil': 'psutil',
|
||||
'coloredlogs': 'coloredlogs',
|
||||
'watchdog': 'watchdog'
|
||||
},
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
|
|
4587
telebot/__init__.py
4587
telebot/__init__.py
File diff suppressed because it is too large
Load Diff
|
@ -87,6 +87,15 @@ def _make_request(token, method_name, method='get', params=None, files=None):
|
|||
logger.debug("Request: method={0} url={1} params={2} files={3}".format(method, request_url, params, files).replace(token, token.split(':')[0] + ":{TOKEN}"))
|
||||
read_timeout = READ_TIMEOUT
|
||||
connect_timeout = CONNECT_TIMEOUT
|
||||
|
||||
if files:
|
||||
files_copy = dict(files)
|
||||
# process types.InputFile
|
||||
for key, value in files_copy.items():
|
||||
if isinstance(value, types.InputFile):
|
||||
files[key] = value.file
|
||||
|
||||
|
||||
if files and format_header_param:
|
||||
fields.format_header_param = _no_encode(format_header_param)
|
||||
if params:
|
||||
|
@ -102,7 +111,13 @@ def _make_request(token, method_name, method='get', params=None, files=None):
|
|||
|
||||
params = params or None # Set params to None if empty
|
||||
result = None
|
||||
if RETRY_ON_ERROR and RETRY_ENGINE == 1:
|
||||
|
||||
if CUSTOM_REQUEST_SENDER:
|
||||
# noinspection PyCallingNonCallable
|
||||
result = CUSTOM_REQUEST_SENDER(
|
||||
method, request_url, params=params, files=files,
|
||||
timeout=(connect_timeout, read_timeout), proxies=proxy)
|
||||
elif RETRY_ON_ERROR and RETRY_ENGINE == 1:
|
||||
got_result = False
|
||||
current_try = 0
|
||||
while not got_result and current_try<MAX_RETRIES-1:
|
||||
|
@ -137,11 +152,6 @@ def _make_request(token, method_name, method='get', params=None, files=None):
|
|||
result = http.request(
|
||||
method, request_url, params=params, files=files,
|
||||
timeout=(connect_timeout, read_timeout), proxies=proxy)
|
||||
elif CUSTOM_REQUEST_SENDER:
|
||||
# noinspection PyCallingNonCallable
|
||||
result = CUSTOM_REQUEST_SENDER(
|
||||
method, request_url, params=params, files=files,
|
||||
timeout=(connect_timeout, read_timeout), proxies=proxy)
|
||||
else:
|
||||
result = _get_req_session().request(
|
||||
method, request_url, params=params, files=files,
|
||||
|
@ -227,23 +237,8 @@ def send_message(
|
|||
token, chat_id, text,
|
||||
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None, timeout=None,
|
||||
entities=None, allow_sending_without_reply=None, protect_content=None):
|
||||
"""
|
||||
Use this method to send text messages. On success, the sent Message is returned.
|
||||
:param token:
|
||||
:param chat_id:
|
||||
:param text:
|
||||
:param disable_web_page_preview:
|
||||
:param reply_to_message_id:
|
||||
:param reply_markup:
|
||||
:param parse_mode:
|
||||
:param disable_notification:
|
||||
:param timeout:
|
||||
:param entities:
|
||||
:param allow_sending_without_reply:
|
||||
:param protect_content:
|
||||
:return:
|
||||
"""
|
||||
entities=None, allow_sending_without_reply=None, protect_content=None,
|
||||
message_thread_id=None):
|
||||
method_url = r'sendMessage'
|
||||
payload = {'chat_id': str(chat_id), 'text': text}
|
||||
if disable_web_page_preview is not None:
|
||||
|
@ -264,6 +259,8 @@ def send_message(
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
|
@ -358,15 +355,15 @@ def get_chat_member_count(token, chat_id):
|
|||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def set_sticker_set_thumb(token, name, user_id, thumb):
|
||||
method_url = r'setStickerSetThumb'
|
||||
def set_sticker_set_thumbnail(token, name, user_id, thumbnail):
|
||||
method_url = r'setStickerSetThumbnail'
|
||||
payload = {'name': name, 'user_id': user_id}
|
||||
files = {}
|
||||
if thumb:
|
||||
if not isinstance(thumb, str):
|
||||
files['thumb'] = thumb
|
||||
if thumbnail:
|
||||
if not isinstance(thumbnail, str):
|
||||
files['thumbnail'] = thumbnail
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
payload['thumbnail'] = thumbnail
|
||||
return _make_request(token, method_url, params=payload, files=files or None)
|
||||
|
||||
|
||||
|
@ -390,7 +387,7 @@ def get_chat_member(token, chat_id, user_id):
|
|||
|
||||
def forward_message(
|
||||
token, chat_id, from_chat_id, message_id,
|
||||
disable_notification=None, timeout=None, protect_content=None):
|
||||
disable_notification=None, timeout=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'forwardMessage'
|
||||
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
|
||||
if disable_notification is not None:
|
||||
|
@ -399,12 +396,14 @@ def forward_message(
|
|||
payload['timeout'] = timeout
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
|
||||
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
|
||||
reply_markup=None, timeout=None, protect_content=None):
|
||||
reply_markup=None, timeout=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'copyMessage'
|
||||
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
|
||||
if caption is not None:
|
||||
|
@ -425,13 +424,15 @@ def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_m
|
|||
payload['timeout'] = timeout
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_dice(
|
||||
token, chat_id,
|
||||
emoji=None, disable_notification=None, reply_to_message_id=None,
|
||||
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
|
||||
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendDice'
|
||||
payload = {'chat_id': chat_id}
|
||||
if emoji:
|
||||
|
@ -448,6 +449,8 @@ def send_dice(
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
|
@ -455,7 +458,8 @@ def send_photo(
|
|||
token, chat_id, photo,
|
||||
caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None, timeout=None,
|
||||
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
|
||||
caption_entities=None, allow_sending_without_reply=None, protect_content=None,
|
||||
message_thread_id=None, has_spoiler=None):
|
||||
method_url = r'sendPhoto'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -483,13 +487,17 @@ def send_photo(
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
if has_spoiler is not None:
|
||||
payload['has_spoiler'] = has_spoiler
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_media_group(
|
||||
token, chat_id, media,
|
||||
disable_notification=None, reply_to_message_id=None,
|
||||
timeout=None, allow_sending_without_reply=None, protect_content=None):
|
||||
timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendMediaGroup'
|
||||
media_json, files = convert_input_media_array(media)
|
||||
payload = {'chat_id': chat_id, 'media': media_json}
|
||||
|
@ -503,6 +511,8 @@ def send_media_group(
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(
|
||||
token, method_url, params=payload,
|
||||
method='post' if files else 'get',
|
||||
|
@ -514,7 +524,8 @@ def send_location(
|
|||
live_period=None, reply_to_message_id=None,
|
||||
reply_markup=None, disable_notification=None,
|
||||
timeout=None, horizontal_accuracy=None, heading=None,
|
||||
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
|
||||
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None,
|
||||
message_thread_id=None):
|
||||
method_url = r'sendLocation'
|
||||
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
|
||||
if live_period:
|
||||
|
@ -537,6 +548,8 @@ def send_location(
|
|||
payload['timeout'] = timeout
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
|
@ -588,7 +601,7 @@ def send_venue(
|
|||
foursquare_id=None, foursquare_type=None, disable_notification=None,
|
||||
reply_to_message_id=None, reply_markup=None, timeout=None,
|
||||
allow_sending_without_reply=None, google_place_id=None,
|
||||
google_place_type=None, protect_content=None):
|
||||
google_place_type=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendVenue'
|
||||
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
|
||||
if foursquare_id:
|
||||
|
@ -611,13 +624,15 @@ def send_venue(
|
|||
payload['google_place_type'] = google_place_type
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_contact(
|
||||
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
|
||||
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
|
||||
allow_sending_without_reply=None, protect_content=None):
|
||||
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendContact'
|
||||
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
|
||||
if last_name:
|
||||
|
@ -636,21 +651,26 @@ def send_contact(
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_chat_action(token, chat_id, action, timeout=None):
|
||||
def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None):
|
||||
method_url = r'sendChatAction'
|
||||
payload = {'chat_id': chat_id, 'action': action}
|
||||
if timeout:
|
||||
payload['timeout'] = timeout
|
||||
if message_thread_id is not None:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
|
||||
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None):
|
||||
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
|
||||
thumbnail=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None,
|
||||
message_thread_id=None, has_spoiler=None):
|
||||
method_url = r'sendVideo'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -674,14 +694,14 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
|
|||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['timeout'] = timeout
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
if thumbnail:
|
||||
if not util.is_string(thumbnail):
|
||||
if files:
|
||||
files['thumb'] = thumb
|
||||
files['thumbnail'] = thumbnail
|
||||
else:
|
||||
files = {'thumb': thumb}
|
||||
files = {'thumbnail': thumbnail}
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
payload['thumbnail'] = thumbnail
|
||||
if width:
|
||||
payload['width'] = width
|
||||
if height:
|
||||
|
@ -692,13 +712,18 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
if has_spoiler is not None:
|
||||
payload['has_spoiler'] = has_spoiler
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_animation(
|
||||
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
|
||||
allow_sending_without_reply=None, protect_content=None, width=None, height=None):
|
||||
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
|
||||
allow_sending_without_reply=None, protect_content=None, width=None, height=None, message_thread_id=None,
|
||||
has_spoiler=None):
|
||||
method_url = r'sendAnimation'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -720,14 +745,14 @@ def send_animation(
|
|||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['timeout'] = timeout
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
if thumbnail:
|
||||
if not util.is_string(thumbnail):
|
||||
if files:
|
||||
files['thumb'] = thumb
|
||||
files['thumbnail'] = thumbnail
|
||||
else:
|
||||
files = {'thumb': thumb}
|
||||
files = {'thumbnail': thumbnail}
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
payload['thumbnail'] = thumbnail
|
||||
if caption_entities:
|
||||
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
|
||||
if allow_sending_without_reply is not None:
|
||||
|
@ -738,12 +763,16 @@ def send_animation(
|
|||
payload['width'] = width
|
||||
if height:
|
||||
payload['height'] = height
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
if has_spoiler is not None:
|
||||
payload['has_spoiler'] = has_spoiler
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
|
||||
allow_sending_without_reply=None, protect_content=None):
|
||||
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendVoice'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -771,11 +800,14 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
|
||||
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
|
||||
disable_notification=None, timeout=None, thumbnail=None, allow_sending_without_reply=None, protect_content=None,
|
||||
message_thread_id=None):
|
||||
method_url = r'sendVideoNote'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -797,24 +829,26 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m
|
|||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['timeout'] = timeout
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
if thumbnail:
|
||||
if not util.is_string(thumbnail):
|
||||
if files:
|
||||
files['thumb'] = thumb
|
||||
files['thumbnail'] = thumbnail
|
||||
else:
|
||||
files = {'thumb': thumb}
|
||||
files = {'thumbnail': thumbnail}
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
payload['thumbnail'] = thumbnail
|
||||
if allow_sending_without_reply is not None:
|
||||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
|
||||
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
|
||||
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
|
||||
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
|
||||
caption_entities=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendAudio'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -840,27 +874,29 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
|
|||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['timeout'] = timeout
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
if thumbnail:
|
||||
if not util.is_string(thumbnail):
|
||||
if files:
|
||||
files['thumb'] = thumb
|
||||
files['thumbnail'] = thumbnail
|
||||
else:
|
||||
files = {'thumb': thumb}
|
||||
files = {'thumbnail': thumbnail}
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
payload['thumbnail'] = thumbnail
|
||||
if caption_entities:
|
||||
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
|
||||
if allow_sending_without_reply is not None:
|
||||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
|
||||
disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None,
|
||||
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
|
||||
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None,
|
||||
protect_content = None):
|
||||
protect_content = None, message_thread_id=None, emoji=None):
|
||||
method_url = get_method_by_type(data_type)
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
|
@ -883,14 +919,14 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
|
|||
payload['timeout'] = timeout
|
||||
if caption:
|
||||
payload['caption'] = caption
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
if thumbnail:
|
||||
if not util.is_string(thumbnail):
|
||||
if files:
|
||||
files['thumb'] = thumb
|
||||
files['thumbnail'] = thumbnail
|
||||
else:
|
||||
files = {'thumb': thumb}
|
||||
files = {'thumbnail': thumbnail}
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
payload['thumbnail'] = thumbnail
|
||||
if caption_entities:
|
||||
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
|
||||
if allow_sending_without_reply is not None:
|
||||
|
@ -899,6 +935,10 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
|
|||
payload['protect_content'] = protect_content
|
||||
if method_url == 'sendDocument' and disable_content_type_detection is not None:
|
||||
payload['disable_content_type_detection'] = disable_content_type_detection
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
if emoji:
|
||||
payload['emoji'] = emoji
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
|
@ -930,36 +970,19 @@ def unban_chat_member(token, chat_id, user_id, only_if_banned):
|
|||
|
||||
|
||||
def restrict_chat_member(
|
||||
token, chat_id, user_id, until_date=None,
|
||||
can_send_messages=None, can_send_media_messages=None,
|
||||
can_send_polls=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None, can_change_info=None,
|
||||
can_invite_users=None, can_pin_messages=None):
|
||||
token, chat_id, user_id, permissions, until_date=None,
|
||||
use_independent_chat_permissions=None):
|
||||
method_url = 'restrictChatMember'
|
||||
permissions = {}
|
||||
if can_send_messages is not None:
|
||||
permissions['can_send_messages'] = can_send_messages
|
||||
if can_send_media_messages is not None:
|
||||
permissions['can_send_media_messages'] = can_send_media_messages
|
||||
if can_send_polls is not None:
|
||||
permissions['can_send_polls'] = can_send_polls
|
||||
if can_send_other_messages is not None:
|
||||
permissions['can_send_other_messages'] = can_send_other_messages
|
||||
if can_add_web_page_previews is not None:
|
||||
permissions['can_add_web_page_previews'] = can_add_web_page_previews
|
||||
if can_change_info is not None:
|
||||
permissions['can_change_info'] = can_change_info
|
||||
if can_invite_users is not None:
|
||||
permissions['can_invite_users'] = can_invite_users
|
||||
if can_pin_messages is not None:
|
||||
permissions['can_pin_messages'] = can_pin_messages
|
||||
permissions_json = json.dumps(permissions)
|
||||
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
|
||||
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
|
||||
|
||||
if use_independent_chat_permissions is not None:
|
||||
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
|
||||
if until_date is not None:
|
||||
if isinstance(until_date, datetime):
|
||||
payload['until_date'] = until_date.timestamp()
|
||||
else:
|
||||
payload['until_date'] = until_date
|
||||
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
|
@ -967,7 +990,8 @@ def promote_chat_member(
|
|||
token, chat_id, user_id, can_change_info=None, can_post_messages=None,
|
||||
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
|
||||
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
|
||||
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None):
|
||||
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None,
|
||||
can_manage_topics=None):
|
||||
method_url = 'promoteChatMember'
|
||||
payload = {'chat_id': chat_id, 'user_id': user_id}
|
||||
if can_change_info is not None:
|
||||
|
@ -992,6 +1016,8 @@ def promote_chat_member(
|
|||
payload['can_manage_chat'] = can_manage_chat
|
||||
if can_manage_video_chats is not None:
|
||||
payload['can_manage_video_chats'] = can_manage_video_chats
|
||||
if can_manage_topics is not None:
|
||||
payload['can_manage_topics'] = can_manage_topics
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
|
@ -1015,12 +1041,14 @@ def unban_chat_sender_chat(token, chat_id, sender_chat_id):
|
|||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_chat_permissions(token, chat_id, permissions):
|
||||
def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
|
||||
method_url = 'setChatPermissions'
|
||||
payload = {
|
||||
'chat_id': chat_id,
|
||||
'permissions': permissions.to_json()
|
||||
}
|
||||
if use_independent_chat_permissions is not None:
|
||||
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
|
@ -1126,6 +1154,39 @@ def set_chat_title(token, chat_id, title):
|
|||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_my_description(token, description=None, language_code=None):
|
||||
method_url = r'setMyDescription'
|
||||
payload = {}
|
||||
if description is not None:
|
||||
payload['description'] = description
|
||||
if language_code is not None:
|
||||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def get_my_description(token, language_code=None):
|
||||
method_url = r'getMyDescription'
|
||||
payload = {}
|
||||
if language_code:
|
||||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def set_my_short_description(token, short_description=None, language_code=None):
|
||||
method_url = r'setMyShortDescription'
|
||||
payload = {}
|
||||
if short_description is not None:
|
||||
payload['short_description'] = short_description
|
||||
if language_code is not None:
|
||||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
def get_my_short_description(token, language_code=None):
|
||||
method_url = r'getMyShortDescription'
|
||||
payload = {}
|
||||
if language_code:
|
||||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def get_my_commands(token, scope=None, language_code=None):
|
||||
method_url = r'getMyCommands'
|
||||
payload = {}
|
||||
|
@ -1135,6 +1196,22 @@ def get_my_commands(token, scope=None, language_code=None):
|
|||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def set_my_name(token, name=None, language_code=None):
|
||||
method_url = r'setMyName'
|
||||
payload = {}
|
||||
if name is not None:
|
||||
payload['name'] = name
|
||||
if language_code is not None:
|
||||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
def get_my_name(token, language_code=None):
|
||||
method_url = r'getMyName'
|
||||
payload = {}
|
||||
if language_code is not None:
|
||||
payload['language_code'] = language_code
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def set_chat_menu_button(token, chat_id=None, menu_button=None):
|
||||
method_url = r'setChatMenuButton'
|
||||
payload = {}
|
||||
|
@ -1304,7 +1381,7 @@ def delete_message(token, chat_id, message_id, timeout=None):
|
|||
def send_game(
|
||||
token, chat_id, game_short_name,
|
||||
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
|
||||
allow_sending_without_reply=None, protect_content=None):
|
||||
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendGame'
|
||||
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
|
||||
if disable_notification is not None:
|
||||
|
@ -1319,6 +1396,8 @@ def send_game(
|
|||
payload['allow_sending_without_reply'] = allow_sending_without_reply
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
|
@ -1384,7 +1463,7 @@ def send_invoice(
|
|||
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
|
||||
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
|
||||
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None,
|
||||
protect_content=None):
|
||||
protect_content=None, message_thread_id=None):
|
||||
"""
|
||||
Use this method to send invoices. On success, the sent Message is returned.
|
||||
:param token: Bot's token (you don't need to fill this)
|
||||
|
@ -1416,7 +1495,8 @@ def send_invoice(
|
|||
:param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency
|
||||
:param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency.
|
||||
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
|
||||
:param protect_content:
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
|
||||
:return:
|
||||
"""
|
||||
method_url = r'sendInvoice'
|
||||
|
@ -1465,6 +1545,8 @@ def send_invoice(
|
|||
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
|
||||
if protect_content is not None:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
|
@ -1532,7 +1614,7 @@ def answer_callback_query(token, callback_query_id, text=None, show_alert=None,
|
|||
|
||||
|
||||
def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
|
||||
switch_pm_text=None, switch_pm_parameter=None):
|
||||
button=None):
|
||||
method_url = 'answerInlineQuery'
|
||||
payload = {'inline_query_id': inline_query_id, 'results': _convert_list_json_serializable(results)}
|
||||
if cache_time is not None:
|
||||
|
@ -1541,10 +1623,8 @@ def answer_inline_query(token, inline_query_id, results, cache_time=None, is_per
|
|||
payload['is_personal'] = is_personal
|
||||
if next_offset is not None:
|
||||
payload['next_offset'] = next_offset
|
||||
if switch_pm_text:
|
||||
payload['switch_pm_text'] = switch_pm_text
|
||||
if switch_pm_parameter:
|
||||
payload['switch_pm_parameter'] = switch_pm_parameter
|
||||
if button is not None:
|
||||
payload["button"] = button.to_json()
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
|
@ -1552,57 +1632,88 @@ def get_sticker_set(token, name):
|
|||
method_url = 'getStickerSet'
|
||||
return _make_request(token, method_url, params={'name': name})
|
||||
|
||||
def get_custom_emoji_stickers(token, custom_emoji_ids):
|
||||
method_url = r'getCustomEmojiStickers'
|
||||
return _make_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)})
|
||||
|
||||
def upload_sticker_file(token, user_id, png_sticker):
|
||||
def set_sticker_keywords(token, sticker, keywords=None):
|
||||
method_url = 'setStickerKeywords'
|
||||
payload = {'sticker': sticker}
|
||||
if keywords:
|
||||
payload['keywords'] = json.dumps(keywords)
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
def set_sticker_mask_position(token, sticker, mask_position=None):
|
||||
method_url = 'setStickerMaskPosition'
|
||||
payload = {'sticker': sticker}
|
||||
if mask_position:
|
||||
payload['mask_position'] = mask_position.to_json()
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def upload_sticker_file(token, user_id, sticker, sticker_format):
|
||||
method_url = 'uploadStickerFile'
|
||||
payload = {'user_id': user_id}
|
||||
files = {'png_sticker': png_sticker}
|
||||
payload = {'user_id': user_id, 'sticker_format': sticker_format}
|
||||
files = {'sticker': sticker}
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None):
|
||||
method_url = 'setCustomEmojiStickerSetThumbnail'
|
||||
payload = {'name': name}
|
||||
if custom_emoji_id is not None:
|
||||
payload['custom_emoji_id'] = custom_emoji_id
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_sticker_set_title(token, name, title):
|
||||
method_url = 'setStickerSetTitle'
|
||||
payload = {'name': name, 'title': title}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
def delete_sticker_set(token, name):
|
||||
method_url = 'deleteStickerSet'
|
||||
payload = {'name': name}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
def set_sticker_emoji_list(token, sticker, emoji_list):
|
||||
method_url = 'setStickerEmojiList'
|
||||
payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
def create_new_sticker_set(
|
||||
token, user_id, name, title, emojis, png_sticker, tgs_sticker,
|
||||
contains_masks=None, mask_position=None, webm_sticker=None):
|
||||
token, user_id, name, title, stickers, sticker_format, sticker_type=None, needs_repainting=None):
|
||||
method_url = 'createNewStickerSet'
|
||||
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
|
||||
if png_sticker:
|
||||
stype = 'png_sticker'
|
||||
elif webm_sticker:
|
||||
stype = 'webm_sticker'
|
||||
else:
|
||||
stype = 'tgs_sticker'
|
||||
sticker = png_sticker or tgs_sticker or webm_sticker
|
||||
files = None
|
||||
if not util.is_string(sticker):
|
||||
files = {stype: sticker}
|
||||
else:
|
||||
payload[stype] = sticker
|
||||
if contains_masks is not None:
|
||||
payload['contains_masks'] = contains_masks
|
||||
if mask_position:
|
||||
payload['mask_position'] = mask_position.to_json()
|
||||
if webm_sticker:
|
||||
payload['webm_sticker'] = webm_sticker
|
||||
payload = {'user_id': user_id, 'name': name, 'title': title, 'sticker_format': sticker_format}
|
||||
if sticker_type:
|
||||
payload['sticker_type'] = sticker_type
|
||||
if needs_repainting:
|
||||
payload['needs_repainting'] = needs_repainting
|
||||
|
||||
files = {}
|
||||
lst = []
|
||||
|
||||
for sticker in stickers:
|
||||
json_dict, file = sticker.convert_input_sticker()
|
||||
json_dict = sticker.to_dict()
|
||||
|
||||
if file:
|
||||
list_keys = list(file.keys())
|
||||
files[list_keys[0]] = file[list_keys[0]]
|
||||
lst.append(json_dict)
|
||||
|
||||
payload['stickers'] = json.dumps(lst)
|
||||
|
||||
|
||||
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker):
|
||||
def add_sticker_to_set(token, user_id, name, sticker):
|
||||
method_url = 'addStickerToSet'
|
||||
payload = {'user_id': user_id, 'name': name, 'emojis': emojis}
|
||||
if png_sticker:
|
||||
stype = 'png_sticker'
|
||||
elif webm_sticker:
|
||||
stype = 'webm_sticker'
|
||||
else:
|
||||
stype = 'tgs_sticker'
|
||||
sticker = png_sticker or tgs_sticker or webm_sticker
|
||||
files = None
|
||||
if not util.is_string(sticker):
|
||||
files = {stype: sticker}
|
||||
else:
|
||||
payload[stype] = sticker
|
||||
if mask_position:
|
||||
payload['mask_position'] = mask_position.to_json()
|
||||
json_dict, files = sticker.convert_input_sticker()
|
||||
payload = {'user_id': user_id, 'name': name, 'sticker': json_dict}
|
||||
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
|
@ -1670,7 +1781,7 @@ def send_poll(
|
|||
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
|
||||
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
|
||||
disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None,
|
||||
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
|
||||
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None):
|
||||
method_url = r'sendPoll'
|
||||
payload = {
|
||||
'chat_id': str(chat_id),
|
||||
|
@ -1714,8 +1825,51 @@ def send_poll(
|
|||
types.MessageEntity.to_list_of_dicts(explanation_entities))
|
||||
if protect_content:
|
||||
payload['protect_content'] = protect_content
|
||||
if message_thread_id:
|
||||
payload['message_thread_id'] = message_thread_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_id=None):
|
||||
method_url = r'createForumTopic'
|
||||
payload = {'chat_id': chat_id, 'name': name}
|
||||
if icon_color:
|
||||
payload['icon_color'] = icon_color
|
||||
if icon_custom_emoji_id:
|
||||
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None):
|
||||
method_url = r'editForumTopic'
|
||||
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
|
||||
if name is not None:
|
||||
payload['name'] = name
|
||||
if icon_custom_emoji_id is not None:
|
||||
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def close_forum_topic(token, chat_id, message_thread_id):
|
||||
method_url = r'closeForumTopic'
|
||||
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def reopen_forum_topic(token, chat_id, message_thread_id):
|
||||
method_url = r'reopenForumTopic'
|
||||
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def delete_forum_topic(token, chat_id, message_thread_id):
|
||||
method_url = r'deleteForumTopic'
|
||||
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def unpin_all_forum_topic_messages(token, chat_id, message_thread_id):
|
||||
method_url = r'unpinAllForumTopicMessages'
|
||||
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def get_forum_topic_icon_stickers(token):
|
||||
method_url = r'getForumTopicIconStickers'
|
||||
return _make_request(token, method_url)
|
||||
|
||||
def stop_poll(token, chat_id, message_id, reply_markup=None):
|
||||
method_url = r'stopPoll'
|
||||
|
@ -1724,6 +1878,31 @@ def stop_poll(token, chat_id, message_id, reply_markup=None):
|
|||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def edit_general_forum_topic(token, chat_id, name):
|
||||
method_url = r'editGeneralForumTopic'
|
||||
payload = {'chat_id': chat_id, 'name': name}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def close_general_forum_topic(token, chat_id):
|
||||
method_url = r'closeGeneralForumTopic'
|
||||
payload = {'chat_id': chat_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def reopen_general_forum_topic(token, chat_id):
|
||||
method_url = r'reopenGeneralForumTopic'
|
||||
payload = {'chat_id': chat_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def hide_general_forum_topic(token, chat_id):
|
||||
method_url = r'hideGeneralForumTopic'
|
||||
payload = {'chat_id': chat_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
def unhide_general_forum_topic(token, chat_id):
|
||||
method_url = r'unhideGeneralForumTopic'
|
||||
payload = {'chat_id': chat_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def _convert_list_json_serializable(results):
|
||||
ret = ''
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,8 +10,19 @@ class SimpleCustomFilter(ABC):
|
|||
Simple Custom Filter base class.
|
||||
Create child class with check() method.
|
||||
Accepts only message, returns bool value, that is compared with given in handler.
|
||||
|
||||
|
||||
Child classes should have .key property.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example on creating a simple custom filter.
|
||||
|
||||
class ForwardFilter(SimpleCustomFilter):
|
||||
# Check whether message was forwarded from channel or group.
|
||||
key = 'is_forwarded'
|
||||
|
||||
def check(self, message):
|
||||
return message.forward_date is not None
|
||||
|
||||
"""
|
||||
|
||||
key: str = None
|
||||
|
@ -25,13 +36,23 @@ class SimpleCustomFilter(ABC):
|
|||
|
||||
class AdvancedCustomFilter(ABC):
|
||||
"""
|
||||
Simple Custom Filter base class.
|
||||
Advanced Custom Filter base class.
|
||||
Create child class with check() method.
|
||||
Accepts two parameters, returns bool: True - filter passed, False - filter failed.
|
||||
message: Message class
|
||||
text: Filter value given in handler
|
||||
|
||||
Child classes should have .key property.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example on creating an advanced custom filter.
|
||||
|
||||
class TextStartsFilter(AdvancedCustomFilter):
|
||||
# Filter to check whether message starts with some text.
|
||||
key = 'text_startswith'
|
||||
|
||||
def check(self, message, text):
|
||||
return message.text.startswith(text)
|
||||
"""
|
||||
|
||||
key: str = None
|
||||
|
@ -48,6 +69,25 @@ class TextFilter:
|
|||
Advanced text filter to check (types.Message, types.CallbackQuery, types.InlineQuery, types.Poll)
|
||||
|
||||
example of usage is in examples/asynchronous_telebot/custom_filters/advanced_text_filter.py
|
||||
|
||||
:param equals: string, True if object's text is equal to passed string
|
||||
:type equals: :obj:`str`
|
||||
|
||||
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
|
||||
:type contains: list[str] or tuple[str]
|
||||
|
||||
:param starts_with: string, True if object's text starts with passed string
|
||||
:type starts_with: :obj:`str`
|
||||
|
||||
:param ends_with: string, True if object's text starts with passed string
|
||||
:type ends_with: :obj:`str`
|
||||
|
||||
:param ignore_case: bool (default False), case insensitive
|
||||
:type ignore_case: :obj:`bool`
|
||||
|
||||
:raises ValueError: if incorrect value for a parameter was supplied
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
|
@ -56,13 +96,25 @@ class TextFilter:
|
|||
starts_with: Optional[Union[str, list, tuple]] = None,
|
||||
ends_with: Optional[Union[str, list, tuple]] = None,
|
||||
ignore_case: bool = False):
|
||||
|
||||
"""
|
||||
:param equals: string, True if object's text is equal to passed string
|
||||
:type equals: :obj:`str`
|
||||
|
||||
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
|
||||
:type contains: list[str] or tuple[str]
|
||||
|
||||
:param starts_with: string, True if object's text starts with passed string
|
||||
:type starts_with: :obj:`str`
|
||||
|
||||
:param ends_with: string, True if object's text starts with passed string
|
||||
:type ends_with: :obj:`str`
|
||||
|
||||
:param ignore_case: bool (default False), case insensitive
|
||||
:type ignore_case: :obj:`bool`
|
||||
|
||||
:raises ValueError: if incorrect value for a parameter was supplied
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
to_check = sum((pattern is not None for pattern in (equals, contains, starts_with, ends_with)))
|
||||
|
@ -87,7 +139,9 @@ class TextFilter:
|
|||
return iterable
|
||||
|
||||
async def check(self, obj: Union[types.Message, types.CallbackQuery, types.InlineQuery, types.Poll]):
|
||||
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(obj, types.Poll):
|
||||
text = obj.question
|
||||
elif isinstance(obj, types.Message):
|
||||
|
@ -135,15 +189,20 @@ class TextFilter:
|
|||
class TextMatchFilter(AdvancedCustomFilter):
|
||||
"""
|
||||
Filter to check Text message.
|
||||
key: text
|
||||
|
||||
Example:
|
||||
@bot.message_handler(text=['account'])
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(text=['account'])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'text'
|
||||
|
||||
async def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(text, TextFilter):
|
||||
return await text.check(message)
|
||||
elif type(text) is list:
|
||||
|
@ -157,14 +216,21 @@ class TextContainsFilter(AdvancedCustomFilter):
|
|||
Filter to check Text message.
|
||||
key: text
|
||||
|
||||
Example:
|
||||
# Will respond if any message.text contains word 'account'
|
||||
@bot.message_handler(text_contains=['account'])
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
# Will respond if any message.text contains word 'account'
|
||||
@bot.message_handler(text_contains=['account'])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'text_contains'
|
||||
|
||||
async def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if not isinstance(text, str) and not isinstance(text, list) and not isinstance(text, tuple):
|
||||
raise ValueError("Incorrect text_contains value")
|
||||
elif isinstance(text, str):
|
||||
|
@ -179,14 +245,20 @@ class TextStartsFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Filter to check whether message starts with some text.
|
||||
|
||||
Example:
|
||||
# Will work if message.text starts with 'Sir'.
|
||||
@bot.message_handler(text_startswith='Sir')
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
# Will work if message.text starts with 'sir'.
|
||||
@bot.message_handler(text_startswith='sir')
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'text_startswith'
|
||||
|
||||
async def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
return message.text.startswith(text)
|
||||
|
||||
|
||||
|
@ -194,13 +266,21 @@ class ChatFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Check whether chat_id corresponds to given chat_id.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(chat_id=[99999])
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(chat_id=[99999])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'chat_id'
|
||||
|
||||
async def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(message, types.CallbackQuery):
|
||||
return message.message.chat.id in text
|
||||
return message.chat.id in text
|
||||
|
||||
|
||||
|
@ -208,29 +288,41 @@ class ForwardFilter(SimpleCustomFilter):
|
|||
"""
|
||||
Check whether message was forwarded from channel or group.
|
||||
|
||||
Example:
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(is_forwarded=True)
|
||||
@bot.message_handler(is_forwarded=True)
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'is_forwarded'
|
||||
|
||||
async def check(self, message):
|
||||
return message.forward_from_chat is not None
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
return message.forward_date is not None
|
||||
|
||||
|
||||
class IsReplyFilter(SimpleCustomFilter):
|
||||
"""
|
||||
Check whether message is a reply.
|
||||
|
||||
Example:
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(is_reply=True)
|
||||
@bot.message_handler(is_reply=True)
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'is_reply'
|
||||
|
||||
async def check(self, message):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(message, types.CallbackQuery):
|
||||
return message.message.reply_to_message is not None
|
||||
return message.reply_to_message is not None
|
||||
|
||||
|
||||
|
@ -238,14 +330,19 @@ class LanguageFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Check users language_code.
|
||||
|
||||
Example:
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(language_code=['ru'])
|
||||
@bot.message_handler(language_code=['ru'])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'language_code'
|
||||
|
||||
async def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if type(text) is list:
|
||||
return message.from_user.language_code in text
|
||||
else:
|
||||
|
@ -256,8 +353,11 @@ class IsAdminFilter(SimpleCustomFilter):
|
|||
"""
|
||||
Check whether the user is administrator / owner of the chat.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'is_chat_admin'
|
||||
|
@ -266,6 +366,12 @@ class IsAdminFilter(SimpleCustomFilter):
|
|||
self._bot = bot
|
||||
|
||||
async def check(self, message):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(message, types.CallbackQuery):
|
||||
result = await self._bot.get_chat_member(message.message.chat.id, message.from_user.id)
|
||||
return result.status ('creator', 'administrator')
|
||||
result = await self._bot.get_chat_member(message.chat.id, message.from_user.id)
|
||||
return result.status in ['creator', 'administrator']
|
||||
|
||||
|
@ -274,8 +380,11 @@ class StateFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Filter to check state.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(state=1)
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(state=1)
|
||||
# your function
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
|
@ -284,6 +393,9 @@ class StateFilter(AdvancedCustomFilter):
|
|||
key = 'state'
|
||||
|
||||
async def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if text == '*': return True
|
||||
|
||||
# needs to work with callbackquery
|
||||
|
@ -307,8 +419,8 @@ class StateFilter(AdvancedCustomFilter):
|
|||
elif isinstance(text, State):
|
||||
text = text.name
|
||||
|
||||
if message.chat.type == 'group':
|
||||
group_state = await self.bot.current_states.get_state(user_id, chat_id)
|
||||
if message.chat.type in ['group', 'supergroup']:
|
||||
group_state = await self.bot.current_states.get_state(chat_id, user_id)
|
||||
if group_state == text:
|
||||
return True
|
||||
elif type(text) is list and group_state in text:
|
||||
|
@ -316,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
|
|||
|
||||
|
||||
else:
|
||||
user_state = await self.bot.current_states.get_state(user_id, chat_id)
|
||||
user_state = await self.bot.current_states.get_state(chat_id, user_id)
|
||||
if user_state == text:
|
||||
return True
|
||||
elif type(text) is list and user_state in text:
|
||||
|
@ -327,10 +439,16 @@ class IsDigitFilter(SimpleCustomFilter):
|
|||
"""
|
||||
Filter to check whether the string is made up of only digits.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(is_digit=True)
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(is_digit=True)
|
||||
# your function
|
||||
"""
|
||||
key = 'is_digit'
|
||||
|
||||
async def check(self, message):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
return message.text.isdigit()
|
||||
|
|
|
@ -1,9 +1,43 @@
|
|||
"""
|
||||
File with all middleware classes, states.
|
||||
"""
|
||||
|
||||
|
||||
class BaseMiddleware:
|
||||
"""
|
||||
Base class for middleware.
|
||||
Your middlewares should be inherited from this class.
|
||||
|
||||
Set update_sensitive=True if you want to get different updates on
|
||||
different functions. For example, if you want to handle pre_process for
|
||||
message update, then you will have to create pre_process_message function, and
|
||||
so on. Same applies to post_process.
|
||||
|
||||
.. code-block:: python
|
||||
:caption: Example of class-based middlewares
|
||||
|
||||
class MyMiddleware(BaseMiddleware):
|
||||
def __init__(self):
|
||||
self.update_sensitive = True
|
||||
self.update_types = ['message', 'edited_message']
|
||||
|
||||
async def pre_process_message(self, message, data):
|
||||
# only message update here
|
||||
pass
|
||||
|
||||
async def post_process_message(self, message, data, exception):
|
||||
pass # only message update here for post_process
|
||||
|
||||
async def pre_process_edited_message(self, message, data):
|
||||
# only edited_message update here
|
||||
pass
|
||||
|
||||
async def post_process_edited_message(self, message, data, exception):
|
||||
pass # only edited_message update here for post_process
|
||||
"""
|
||||
|
||||
update_sensitive: bool = False
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
@ -15,6 +49,14 @@ class BaseMiddleware:
|
|||
|
||||
|
||||
class State:
|
||||
"""
|
||||
Class representing a state.
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
class MyStates(StatesGroup):
|
||||
my_state = State() # returns my_state:State string.
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
self.name = None
|
||||
|
||||
|
@ -23,12 +65,27 @@ class State:
|
|||
|
||||
|
||||
class StatesGroup:
|
||||
def __init_subclass__(cls) -> None:
|
||||
"""
|
||||
Class representing common states.
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
class MyStates(StatesGroup):
|
||||
my_state = State() # returns my_state:State string.
|
||||
"""
|
||||
def __init_subclass__(cls) -> None:
|
||||
state_list = []
|
||||
for name, value in cls.__dict__.items():
|
||||
if not name.startswith('__') and not callable(value) and isinstance(value, State):
|
||||
# change value of that variable
|
||||
value.name = ':'.join((cls.__name__, name))
|
||||
value.group = cls
|
||||
state_list.append(value)
|
||||
cls._state_list = state_list
|
||||
|
||||
@property
|
||||
def state_list(self):
|
||||
return self._state_list
|
||||
|
||||
|
||||
class SkipHandler:
|
||||
|
@ -43,6 +100,7 @@ class SkipHandler:
|
|||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class CancelUpdate:
|
||||
"""
|
||||
Class for canceling updates.
|
||||
|
@ -53,4 +111,27 @@ class CancelUpdate:
|
|||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class ContinueHandling:
|
||||
"""
|
||||
Class for continue updates in handlers.
|
||||
Just return instance of this class
|
||||
in handlers to continue process.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example of using ContinueHandling
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
async def start(message):
|
||||
await bot.send_message(message.chat.id, 'Hello World!')
|
||||
return ContinueHandling()
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
async def start2(message):
|
||||
await bot.send_message(message.chat.id, 'Hello World2!')
|
||||
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,7 +28,7 @@ class StatePickleStorage(StateStorageBase):
|
|||
"""
|
||||
Create directory .save-handlers.
|
||||
"""
|
||||
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
|
||||
dirs, filename = os.path.split(self.file_path)
|
||||
os.makedirs(dirs, exist_ok=True)
|
||||
if not os.path.isfile(self.file_path):
|
||||
with open(self.file_path,'wb') as file:
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
from telebot.asyncio_storage.base_storage import StateStorageBase, StateContext
|
||||
import json
|
||||
|
||||
|
||||
redis_installed = True
|
||||
is_actual_aioredis = False
|
||||
try:
|
||||
import aioredis
|
||||
except:
|
||||
redis_installed = False
|
||||
is_actual_aioredis = True
|
||||
except ImportError:
|
||||
try:
|
||||
from redis import asyncio as aioredis
|
||||
except ImportError:
|
||||
redis_installed = False
|
||||
|
||||
|
||||
class StateRedisStorage(StateStorageBase):
|
||||
|
@ -20,10 +24,10 @@ class StateRedisStorage(StateStorageBase):
|
|||
if not redis_installed:
|
||||
raise ImportError('AioRedis is not installed. Install it via "pip install aioredis"')
|
||||
|
||||
|
||||
aioredis_version = tuple(map(int, aioredis.__version__.split(".")[0]))
|
||||
if aioredis_version < (2,):
|
||||
raise ImportError('Invalid aioredis version. Aioredis version should be >= 2.0.0')
|
||||
if is_actual_aioredis:
|
||||
aioredis_version = tuple(map(int, aioredis.__version__.split(".")[0]))
|
||||
if aioredis_version < (2,):
|
||||
raise ImportError('Invalid aioredis version. Aioredis version should be >= 2.0.0')
|
||||
self.redis = aioredis.Redis(host=host, port=port, db=db, password=password)
|
||||
|
||||
self.prefix = prefix
|
||||
|
@ -167,6 +171,6 @@ class StateRedisStorage(StateStorageBase):
|
|||
user_id = str(user_id)
|
||||
if response:
|
||||
if user_id in response:
|
||||
response[user_id]['data'] = dict(data, **response[user_id]['data'])
|
||||
response[user_id]['data'] = data
|
||||
await self.set_record(chat_id, response)
|
||||
return True
|
||||
|
|
|
@ -1,18 +1,55 @@
|
|||
"""
|
||||
Callback data factory's file.
|
||||
"""
|
||||
|
||||
"""
|
||||
Copyright (c) 2017-2018 Alex Root Junior
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software
|
||||
without restriction, including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies
|
||||
or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
This file was added during the pull request. The maintainers overlooked that it was copied
|
||||
"as is" from another project and they do not consider it as a right way to develop a project.
|
||||
However, due to backward compatibility we had to leave this file in the project with the above
|
||||
copyright added, as it is required by the original project license.
|
||||
"""
|
||||
|
||||
import typing
|
||||
|
||||
|
||||
class CallbackDataFilter:
|
||||
"""
|
||||
Filter for CallbackData.
|
||||
"""
|
||||
|
||||
def __init__(self, factory, config: typing.Dict[str, str]):
|
||||
self.config = config
|
||||
self.factory = factory
|
||||
|
||||
def check(self, query):
|
||||
def check(self, query) -> bool:
|
||||
"""
|
||||
Checks if query.data appropriates to specified config
|
||||
|
||||
:param query: telebot.types.CallbackQuery
|
||||
:return: bool
|
||||
:type query: telebot.types.CallbackQuery
|
||||
|
||||
:return: True if query.data appropriates to specified config
|
||||
:rtype: bool
|
||||
"""
|
||||
|
||||
try:
|
||||
|
@ -108,7 +145,7 @@ class CallbackData:
|
|||
"""
|
||||
Generate filter
|
||||
|
||||
:param config: specified named parameters will be checked with CallbackQury.data
|
||||
:param config: specified named parameters will be checked with CallbackQuery.data
|
||||
:return: CallbackDataFilter class
|
||||
"""
|
||||
|
||||
|
|
|
@ -14,6 +14,17 @@ class SimpleCustomFilter(ABC):
|
|||
Accepts only message, returns bool value, that is compared with given in handler.
|
||||
|
||||
Child classes should have .key property.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example on creating a simple custom filter.
|
||||
|
||||
class ForwardFilter(SimpleCustomFilter):
|
||||
# Check whether message was forwarded from channel or group.
|
||||
key = 'is_forwarded'
|
||||
|
||||
def check(self, message):
|
||||
return message.forward_date is not None
|
||||
|
||||
"""
|
||||
|
||||
key: str = None
|
||||
|
@ -27,13 +38,23 @@ class SimpleCustomFilter(ABC):
|
|||
|
||||
class AdvancedCustomFilter(ABC):
|
||||
"""
|
||||
Simple Custom Filter base class.
|
||||
Advanced Custom Filter base class.
|
||||
Create child class with check() method.
|
||||
Accepts two parameters, returns bool: True - filter passed, False - filter failed.
|
||||
message: Message class
|
||||
text: Filter value given in handler
|
||||
|
||||
Child classes should have .key property.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example on creating an advanced custom filter.
|
||||
|
||||
class TextStartsFilter(AdvancedCustomFilter):
|
||||
# Filter to check whether message starts with some text.
|
||||
key = 'text_startswith'
|
||||
|
||||
def check(self, message, text):
|
||||
return message.text.startswith(text)
|
||||
"""
|
||||
|
||||
key: str = None
|
||||
|
@ -50,6 +71,25 @@ class TextFilter:
|
|||
Advanced text filter to check (types.Message, types.CallbackQuery, types.InlineQuery, types.Poll)
|
||||
|
||||
example of usage is in examples/custom_filters/advanced_text_filter.py
|
||||
|
||||
:param equals: string, True if object's text is equal to passed string
|
||||
:type equals: :obj:`str`
|
||||
|
||||
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
|
||||
:type contains: list[str] or tuple[str]
|
||||
|
||||
:param starts_with: string, True if object's text starts with passed string
|
||||
:type starts_with: :obj:`str`
|
||||
|
||||
:param ends_with: string, True if object's text starts with passed string
|
||||
:type ends_with: :obj:`str`
|
||||
|
||||
:param ignore_case: bool (default False), case insensitive
|
||||
:type ignore_case: :obj:`bool`
|
||||
|
||||
:raises ValueError: if incorrect value for a parameter was supplied
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
|
@ -58,15 +98,27 @@ class TextFilter:
|
|||
starts_with: Optional[Union[str, list, tuple]] = None,
|
||||
ends_with: Optional[Union[str, list, tuple]] = None,
|
||||
ignore_case: bool = False):
|
||||
|
||||
"""
|
||||
:param equals: string, True if object's text is equal to passed string
|
||||
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
|
||||
:param starts_with: string, True if object's text starts with passed string
|
||||
:param ends_with: string, True if object's text starts with passed string
|
||||
:param ignore_case: bool (default False), case insensitive
|
||||
"""
|
||||
:type equals: :obj:`str`
|
||||
|
||||
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
|
||||
:type contains: list[str] or tuple[str]
|
||||
|
||||
:param starts_with: string, True if object's text starts with passed string
|
||||
:type starts_with: :obj:`str`
|
||||
|
||||
:param ends_with: string, True if object's text starts with passed string
|
||||
:type ends_with: :obj:`str`
|
||||
|
||||
:param ignore_case: bool (default False), case insensitive
|
||||
:type ignore_case: :obj:`bool`
|
||||
|
||||
:raises ValueError: if incorrect value for a parameter was supplied
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
to_check = sum((pattern is not None for pattern in (equals, contains, starts_with, ends_with)))
|
||||
if to_check == 0:
|
||||
raise ValueError('None of the check modes was specified')
|
||||
|
@ -89,6 +141,9 @@ class TextFilter:
|
|||
return iterable
|
||||
|
||||
def check(self, obj: Union[types.Message, types.CallbackQuery, types.InlineQuery, types.Poll]):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
|
||||
if isinstance(obj, types.Poll):
|
||||
text = obj.question
|
||||
|
@ -142,15 +197,20 @@ class TextFilter:
|
|||
class TextMatchFilter(AdvancedCustomFilter):
|
||||
"""
|
||||
Filter to check Text message.
|
||||
key: text
|
||||
|
||||
Example:
|
||||
@bot.message_handler(text=['account'])
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(text=['account'])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'text'
|
||||
|
||||
def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(text, TextFilter):
|
||||
return text.check(message)
|
||||
elif type(text) is list:
|
||||
|
@ -164,14 +224,21 @@ class TextContainsFilter(AdvancedCustomFilter):
|
|||
Filter to check Text message.
|
||||
key: text
|
||||
|
||||
Example:
|
||||
# Will respond if any message.text contains word 'account'
|
||||
@bot.message_handler(text_contains=['account'])
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
# Will respond if any message.text contains word 'account'
|
||||
@bot.message_handler(text_contains=['account'])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'text_contains'
|
||||
|
||||
def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if not isinstance(text, str) and not isinstance(text, list) and not isinstance(text, tuple):
|
||||
raise ValueError("Incorrect text_contains value")
|
||||
elif isinstance(text, str):
|
||||
|
@ -186,14 +253,20 @@ class TextStartsFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Filter to check whether message starts with some text.
|
||||
|
||||
Example:
|
||||
# Will work if message.text starts with 'Sir'.
|
||||
@bot.message_handler(text_startswith='Sir')
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
# Will work if message.text starts with 'sir'.
|
||||
@bot.message_handler(text_startswith='sir')
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'text_startswith'
|
||||
|
||||
def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
return message.text.startswith(text)
|
||||
|
||||
|
||||
|
@ -201,13 +274,21 @@ class ChatFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Check whether chat_id corresponds to given chat_id.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(chat_id=[99999])
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(chat_id=[99999])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'chat_id'
|
||||
|
||||
def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(message, types.CallbackQuery):
|
||||
return message.message.chat.id in text
|
||||
return message.chat.id in text
|
||||
|
||||
|
||||
|
@ -215,29 +296,41 @@ class ForwardFilter(SimpleCustomFilter):
|
|||
"""
|
||||
Check whether message was forwarded from channel or group.
|
||||
|
||||
Example:
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(is_forwarded=True)
|
||||
@bot.message_handler(is_forwarded=True)
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'is_forwarded'
|
||||
|
||||
def check(self, message):
|
||||
return message.forward_from_chat is not None
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
return message.forward_date is not None
|
||||
|
||||
|
||||
class IsReplyFilter(SimpleCustomFilter):
|
||||
"""
|
||||
Check whether message is a reply.
|
||||
|
||||
Example:
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(is_reply=True)
|
||||
@bot.message_handler(is_reply=True)
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'is_reply'
|
||||
|
||||
def check(self, message):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(message, types.CallbackQuery):
|
||||
return message.message.reply_to_message is not None
|
||||
return message.reply_to_message is not None
|
||||
|
||||
|
||||
|
@ -245,14 +338,19 @@ class LanguageFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Check users language_code.
|
||||
|
||||
Example:
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(language_code=['ru'])
|
||||
@bot.message_handler(language_code=['ru'])
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'language_code'
|
||||
|
||||
def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if type(text) is list:
|
||||
return message.from_user.language_code in text
|
||||
else:
|
||||
|
@ -263,8 +361,11 @@ class IsAdminFilter(SimpleCustomFilter):
|
|||
"""
|
||||
Check whether the user is administrator / owner of the chat.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
|
||||
# your function
|
||||
"""
|
||||
|
||||
key = 'is_chat_admin'
|
||||
|
@ -273,6 +374,11 @@ class IsAdminFilter(SimpleCustomFilter):
|
|||
self._bot = bot
|
||||
|
||||
def check(self, message):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if isinstance(message, types.CallbackQuery):
|
||||
return self._bot.get_chat_member(message.message.chat.id, message.from_user.id).status in ['creator', 'administrator']
|
||||
return self._bot.get_chat_member(message.chat.id, message.from_user.id).status in ['creator', 'administrator']
|
||||
|
||||
|
||||
|
@ -280,8 +386,11 @@ class StateFilter(AdvancedCustomFilter):
|
|||
"""
|
||||
Filter to check state.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(state=1)
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(state=1)
|
||||
# your function
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
|
@ -290,6 +399,9 @@ class StateFilter(AdvancedCustomFilter):
|
|||
key = 'state'
|
||||
|
||||
def check(self, message, text):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if text == '*': return True
|
||||
|
||||
# needs to work with callbackquery
|
||||
|
@ -315,8 +427,8 @@ class StateFilter(AdvancedCustomFilter):
|
|||
elif isinstance(text, State):
|
||||
text = text.name
|
||||
|
||||
if message.chat.type == 'group':
|
||||
group_state = self.bot.current_states.get_state(user_id, chat_id)
|
||||
if message.chat.type in ['group', 'supergroup']:
|
||||
group_state = self.bot.current_states.get_state(chat_id, user_id)
|
||||
if group_state == text:
|
||||
return True
|
||||
elif type(text) is list and group_state in text:
|
||||
|
@ -324,7 +436,7 @@ class StateFilter(AdvancedCustomFilter):
|
|||
|
||||
|
||||
else:
|
||||
user_state = self.bot.current_states.get_state(user_id, chat_id)
|
||||
user_state = self.bot.current_states.get_state(chat_id, user_id)
|
||||
if user_state == text:
|
||||
return True
|
||||
elif type(text) is list and user_state in text:
|
||||
|
@ -335,10 +447,16 @@ class IsDigitFilter(SimpleCustomFilter):
|
|||
"""
|
||||
Filter to check whether the string is made up of only digits.
|
||||
|
||||
Example:
|
||||
@bot.message_handler(is_digit=True)
|
||||
.. code-block:: python3
|
||||
:caption: Example on using this filter:
|
||||
|
||||
@bot.message_handler(is_digit=True)
|
||||
# your function
|
||||
"""
|
||||
key = 'is_digit'
|
||||
|
||||
def check(self, message):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
return message.text.isdigit()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
A folder with asynchronous and synchronous extensions.
|
||||
"""
|
|
@ -0,0 +1,10 @@
|
|||
"""
|
||||
A folder with all the async extensions.
|
||||
"""
|
||||
|
||||
from .webhooks import AsyncWebhookListener
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AsyncWebhookListener"
|
||||
]
|
|
@ -0,0 +1,123 @@
|
|||
"""
|
||||
This file is used by AsyncTeleBot.run_webhooks() function.
|
||||
|
||||
Fastapi and starlette(0.20.2+) libraries are required to run this script.
|
||||
"""
|
||||
|
||||
# modules required for running this script
|
||||
fastapi_installed = True
|
||||
try:
|
||||
import fastapi
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.requests import Request
|
||||
from uvicorn import Server, Config
|
||||
except ImportError:
|
||||
fastapi_installed = False
|
||||
|
||||
import asyncio
|
||||
|
||||
|
||||
from telebot.types import Update
|
||||
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class AsyncWebhookListener:
|
||||
def __init__(self, bot,
|
||||
secret_token: str,
|
||||
host: Optional[str]="127.0.0.1",
|
||||
port: Optional[int]=443,
|
||||
ssl_context: Optional[tuple]=None,
|
||||
url_path: Optional[str]=None,
|
||||
) -> None:
|
||||
"""
|
||||
Aynchronous implementation of webhook listener
|
||||
for asynchronous version of telebot.
|
||||
Not supposed to be used manually by user.
|
||||
Use AsyncTeleBot.run_webhooks() instead.
|
||||
|
||||
:param bot: AsyncTeleBot instance.
|
||||
:type bot: telebot.async_telebot.AsyncTeleBot
|
||||
|
||||
:param secret_token: Telegram secret token
|
||||
:type secret_token: str
|
||||
|
||||
:param host: Webhook host
|
||||
:type host: str
|
||||
|
||||
:param port: Webhook port
|
||||
:type port: int
|
||||
|
||||
:param ssl_context: SSL context
|
||||
:type ssl_context: tuple
|
||||
|
||||
:param url_path: Webhook url path
|
||||
:type url_path: str
|
||||
|
||||
:raises ImportError: If FastAPI or uvicorn is not installed.
|
||||
:raises ImportError: If Starlette version is too old.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self._check_dependencies()
|
||||
|
||||
self.app = fastapi.FastAPI()
|
||||
self._secret_token = secret_token
|
||||
self._bot = bot
|
||||
self._port = port
|
||||
self._host = host
|
||||
self._ssl_context = ssl_context
|
||||
self._url_path = url_path
|
||||
self._prepare_endpoint_urls()
|
||||
|
||||
|
||||
def _check_dependencies(self):
|
||||
if not fastapi_installed:
|
||||
raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.')
|
||||
|
||||
import starlette
|
||||
if starlette.__version__ < '0.20.2':
|
||||
raise ImportError('Starlette version is too old. Please upgrade it: `pip3 install starlette -U`')
|
||||
return
|
||||
|
||||
|
||||
def _prepare_endpoint_urls(self):
|
||||
self.app.add_api_route(endpoint=self.process_update,path= self._url_path, methods=["POST"])
|
||||
|
||||
|
||||
async def process_update(self, request: Request, update: dict):
|
||||
"""
|
||||
Processes updates.
|
||||
|
||||
:meta private:
|
||||
"""
|
||||
# header containsX-Telegram-Bot-Api-Secret-Token
|
||||
if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token:
|
||||
# secret token didn't match
|
||||
return JSONResponse(status_code=403, content={"error": "Forbidden"})
|
||||
if request.headers.get('content-type') == 'application/json':
|
||||
json_string = update
|
||||
asyncio.create_task(self._bot.process_new_updates([Update.de_json(json_string)]))
|
||||
return JSONResponse('', status_code=200)
|
||||
|
||||
return JSONResponse(status_code=403, content={"error": "Forbidden"})
|
||||
|
||||
|
||||
async def run_app(self):
|
||||
"""
|
||||
Run app with the given parameters to init.
|
||||
Not supposed to be used manually by user.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
config = Config(app=self.app,
|
||||
host=self._host,
|
||||
port=self._port,
|
||||
ssl_certfile=self._ssl_context[0],
|
||||
ssl_keyfile=self._ssl_context[1]
|
||||
)
|
||||
server = Server(config)
|
||||
await server.serve()
|
||||
await self._bot.close_session()
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
from watchdog.events import FileSystemEvent
|
||||
import psutil
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger('TeleBot')
|
||||
|
||||
class EventHandler(FileSystemEventHandler):
|
||||
def on_any_event(self, event: FileSystemEvent):
|
||||
logger.info('* Detected changes in: %s, reloading', (event.src_path))
|
||||
restart_file()
|
||||
|
||||
def restart_file():
|
||||
try:
|
||||
p = psutil.Process(os.getpid())
|
||||
for handler in p.open_files() + p.connections():
|
||||
os.close(handler.fd)
|
||||
except OSError:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
python = sys.executable
|
||||
|
||||
if os.name == 'nt':
|
||||
os.execv(sys.executable, ['python'] + sys.argv)
|
||||
else:
|
||||
os.execl(python, python, *sys.argv)
|
|
@ -0,0 +1,10 @@
|
|||
"""
|
||||
A folder with all the sync extensions.
|
||||
"""
|
||||
|
||||
from .webhooks import SyncWebhookListener
|
||||
|
||||
|
||||
__all__ = [
|
||||
"SyncWebhookListener"
|
||||
]
|
|
@ -0,0 +1,116 @@
|
|||
"""
|
||||
This file is used by TeleBot.run_webhooks() function.
|
||||
Fastapi is required to run this script.
|
||||
"""
|
||||
|
||||
# modules required for running this script
|
||||
fastapi_installed = True
|
||||
|
||||
try:
|
||||
import fastapi
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.requests import Request
|
||||
import uvicorn
|
||||
except ImportError:
|
||||
fastapi_installed = False
|
||||
|
||||
from telebot.types import Update
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class SyncWebhookListener:
|
||||
def __init__(self, bot,
|
||||
secret_token: str,
|
||||
host: Optional[str]="127.0.0.1",
|
||||
port: Optional[int]=443,
|
||||
ssl_context: Optional[tuple]=None,
|
||||
url_path: Optional[str]=None,
|
||||
) -> None:
|
||||
"""
|
||||
Synchronous implementation of webhook listener
|
||||
for synchronous version of telebot.
|
||||
Not supposed to be used manually by user.
|
||||
Use TeleBot.run_webhooks() instead.
|
||||
|
||||
:param bot: TeleBot instance.
|
||||
:type bot: telebot.TeleBot
|
||||
|
||||
:param secret_token: Telegram secret token
|
||||
:type secret_token: str
|
||||
|
||||
:param host: Webhook host
|
||||
:type host: str
|
||||
|
||||
:param port: Webhook port
|
||||
:type port: int
|
||||
|
||||
:param ssl_context: SSL context
|
||||
:type ssl_context: tuple
|
||||
|
||||
:param url_path: Webhook url path
|
||||
:type url_path: str
|
||||
|
||||
:raises ImportError: If FastAPI or uvicorn is not installed.
|
||||
:raises ImportError: If Starlette version is too old.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self._check_dependencies()
|
||||
|
||||
self.app = fastapi.FastAPI()
|
||||
self._secret_token = secret_token
|
||||
self._bot = bot
|
||||
self._port = port
|
||||
self._host = host
|
||||
self._ssl_context = ssl_context
|
||||
self._url_path = url_path
|
||||
self._prepare_endpoint_urls()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _check_dependencies():
|
||||
if not fastapi_installed:
|
||||
raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.')
|
||||
|
||||
import starlette
|
||||
if starlette.__version__ < '0.20.2':
|
||||
raise ImportError('Starlette version is too old. Please upgrade it: `pip3 install starlette -U`')
|
||||
return
|
||||
|
||||
|
||||
def _prepare_endpoint_urls(self):
|
||||
self.app.add_api_route(endpoint=self.process_update,path= self._url_path, methods=["POST"])
|
||||
|
||||
|
||||
def process_update(self, request: Request, update: dict):
|
||||
"""
|
||||
Processes updates.
|
||||
|
||||
:meta private:
|
||||
"""
|
||||
# header containsX-Telegram-Bot-Api-Secret-Token
|
||||
if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token:
|
||||
# secret token didn't match
|
||||
return JSONResponse(status_code=403, content={"error": "Forbidden"})
|
||||
if request.headers.get('content-type') == 'application/json':
|
||||
self._bot.process_new_updates([Update.de_json(update)])
|
||||
return JSONResponse('', status_code=200)
|
||||
|
||||
return JSONResponse(status_code=403, content={"error": "Forbidden"})
|
||||
|
||||
|
||||
def run_app(self):
|
||||
"""
|
||||
Run app with the given parameters to init.
|
||||
Not supposed to be used manually by user.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
uvicorn.run(app=self.app,
|
||||
host=self._host,
|
||||
port=self._port,
|
||||
ssl_certfile=self._ssl_context[0],
|
||||
ssl_keyfile=self._ssl_context[1]
|
||||
)
|
|
@ -5,14 +5,17 @@ Markdown & HTML formatting functions.
|
|||
"""
|
||||
|
||||
import html
|
||||
|
||||
import re
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def format_text(*args, separator="\n"):
|
||||
"""
|
||||
Formats a list of strings into a single string.
|
||||
|
||||
.. code:: python
|
||||
.. code:: python3
|
||||
|
||||
format_text( # just an example
|
||||
mbold('Hello'),
|
||||
|
@ -20,7 +23,13 @@ def format_text(*args, separator="\n"):
|
|||
)
|
||||
|
||||
:param args: Strings to format.
|
||||
:type args: :obj:`str`
|
||||
|
||||
:param separator: The separator to use between each string.
|
||||
:type separator: :obj:`str`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return separator.join(args)
|
||||
|
||||
|
@ -31,6 +40,10 @@ def escape_html(content: str) -> str:
|
|||
Escapes HTML characters in a string of HTML.
|
||||
|
||||
:param content: The string of HTML to escape.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:return: The escaped string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return html.escape(content)
|
||||
|
||||
|
@ -39,164 +52,263 @@ def escape_markdown(content: str) -> str:
|
|||
"""
|
||||
Escapes Markdown characters in a string of Markdown.
|
||||
|
||||
Credits: simonsmh
|
||||
Credits to: simonsmh
|
||||
|
||||
:param content: The string of Markdown to escape.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:return: The escaped string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
|
||||
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!])", r"\\\1", content)
|
||||
reparse = re.sub(r"\\\\([_*\[\]()~`>\#\+\-=|\.!])", r"\1", parse)
|
||||
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!\{\}\\])", r"\\\1", content)
|
||||
reparse = re.sub(r"\\\\([_*\[\]()~`>\#\+\-=|\.!\{\}\\])", r"\1", parse)
|
||||
return reparse
|
||||
|
||||
|
||||
def mbold(content: str, escape: bool=True) -> str:
|
||||
def mbold(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted bold string.
|
||||
|
||||
:param content: The string to bold.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '*{}*'.format(escape_markdown(content) if escape else content)
|
||||
|
||||
|
||||
def hbold(content: str, escape: bool=True) -> str:
|
||||
def hbold(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted bold string.
|
||||
|
||||
:param content: The string to bold.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<b>{}</b>'.format(escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def mitalic(content: str, escape: bool=True) -> str:
|
||||
def mitalic(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted italic string.
|
||||
|
||||
:param content: The string to italicize.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '_{}_\r'.format(escape_markdown(content) if escape else content)
|
||||
|
||||
|
||||
def hitalic(content: str, escape: bool=True) -> str:
|
||||
def hitalic(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted italic string.
|
||||
|
||||
:param content: The string to italicize.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<i>{}</i>'.format(escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def munderline(content: str, escape: bool=True) -> str:
|
||||
def munderline(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted underline string.
|
||||
|
||||
:param content: The string to underline.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '__{}__'.format(escape_markdown(content) if escape else content)
|
||||
|
||||
|
||||
def hunderline(content: str, escape: bool=True) -> str:
|
||||
def hunderline(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted underline string.
|
||||
|
||||
:param content: The string to underline.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
|
||||
"""
|
||||
return '<u>{}</u>'.format(escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def mstrikethrough(content: str, escape: bool=True) -> str:
|
||||
def mstrikethrough(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted strikethrough string.
|
||||
|
||||
:param content: The string to strikethrough.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '~{}~'.format(escape_markdown(content) if escape else content)
|
||||
|
||||
|
||||
def hstrikethrough(content: str, escape: bool=True) -> str:
|
||||
def hstrikethrough(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted strikethrough string.
|
||||
|
||||
:param content: The string to strikethrough.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<s>{}</s>'.format(escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def mspoiler(content: str, escape: bool=True) -> str:
|
||||
def mspoiler(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted spoiler string.
|
||||
|
||||
:param content: The string to spoiler.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '||{}||'.format(escape_markdown(content) if escape else content)
|
||||
|
||||
|
||||
def hspoiler(content: str, escape: bool=True) -> str:
|
||||
def hspoiler(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted spoiler string.
|
||||
|
||||
:param content: The string to spoiler.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<tg-spoiler>{}</tg-spoiler>'.format(escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def mlink(content: str, url: str, escape: bool=True) -> str:
|
||||
def mlink(content: str, url: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted link string.
|
||||
|
||||
:param content: The string to link.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param url: The URL to link to.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type url: str
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '[{}]({})'.format(escape_markdown(content), escape_markdown(url) if escape else content)
|
||||
|
||||
|
||||
def hlink(content: str, url: str, escape: bool=True) -> str:
|
||||
def hlink(content: str, url: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted link string.
|
||||
|
||||
:param content: The string to link.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param url: The URL to link to.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type url: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<a href="{}">{}</a>'.format(escape_html(url), escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def mcode(content: str, language: str="", escape: bool=True) -> str:
|
||||
def mcode(content: str, language: str="", escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns a Markdown-formatted code string.
|
||||
|
||||
:param content: The string to code.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '```{}\n{}```'.format(language, escape_markdown(content) if escape else content)
|
||||
|
||||
|
||||
def hcode(content: str, escape: bool=True) -> str:
|
||||
def hcode(content: str, escape: Optional[bool]=True) -> str:
|
||||
"""
|
||||
Returns an HTML-formatted code string.
|
||||
|
||||
:param content: The string to code.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<code>{}</code>'.format(escape_html(content) if escape else content)
|
||||
|
||||
|
||||
def hpre(content: str, escape: bool=True, language: str="") -> str:
|
||||
def hpre(content: str, escape: Optional[bool]=True, language: str="") -> str:
|
||||
"""
|
||||
Returns an HTML-formatted preformatted string.
|
||||
|
||||
:param content: The string to preformatted.
|
||||
:param escape: True if you need to escape special characters.
|
||||
:type content: :obj:`str`
|
||||
|
||||
:param escape: True if you need to escape special characters. Defaults to True.
|
||||
:type escape: :obj:`bool`
|
||||
|
||||
:return: The formatted string.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return '<pre><code class="{}">{}</code></pre>'.format(language, escape_html(content) if escape else content)
|
||||
|
||||
|
@ -205,7 +317,10 @@ def hide_link(url: str) -> str:
|
|||
"""
|
||||
Hide url of an image.
|
||||
|
||||
:param url:
|
||||
:return: str
|
||||
:param url: The url of the image.
|
||||
:type url: :obj:`str`
|
||||
|
||||
:return: The hidden url.
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return f'<a href="{url}">⁠</a>'
|
||||
return f'<a href="{url}">⁠</a>'
|
||||
|
|
|
@ -12,7 +12,9 @@ except:
|
|||
|
||||
class HandlerBackend(object):
|
||||
"""
|
||||
Class for saving (next step|reply) handlers
|
||||
Class for saving (next step|reply) handlers.
|
||||
|
||||
:meta private:
|
||||
"""
|
||||
def __init__(self, handlers=None):
|
||||
if handlers is None:
|
||||
|
@ -30,6 +32,9 @@ class HandlerBackend(object):
|
|||
|
||||
|
||||
class MemoryHandlerBackend(HandlerBackend):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
def register_handler(self, handler_group_id, handler):
|
||||
if handler_group_id in self.handlers:
|
||||
self.handlers[handler_group_id].append(handler)
|
||||
|
@ -47,6 +52,9 @@ class MemoryHandlerBackend(HandlerBackend):
|
|||
|
||||
|
||||
class FileHandlerBackend(HandlerBackend):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
def __init__(self, handlers=None, filename='./.handler-saves/handlers.save', delay=120):
|
||||
super(FileHandlerBackend, self).__init__(handlers)
|
||||
self.filename = filename
|
||||
|
@ -119,6 +127,9 @@ class FileHandlerBackend(HandlerBackend):
|
|||
|
||||
|
||||
class RedisHandlerBackend(HandlerBackend):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
def __init__(self, handlers=None, host='localhost', port=6379, db=0, prefix='telebot', password=None):
|
||||
super(RedisHandlerBackend, self).__init__(handlers)
|
||||
if not redis_installed:
|
||||
|
@ -150,27 +161,83 @@ class RedisHandlerBackend(HandlerBackend):
|
|||
|
||||
|
||||
class State:
|
||||
"""
|
||||
Class representing a state.
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
class MyStates(StatesGroup):
|
||||
my_state = State() # returns my_state:State string.
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
self.name = None
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
class StatesGroup:
|
||||
"""
|
||||
Class representing common states.
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
class MyStates(StatesGroup):
|
||||
my_state = State() # returns my_state:State string.
|
||||
"""
|
||||
def __init_subclass__(cls) -> None:
|
||||
state_list = []
|
||||
for name, value in cls.__dict__.items():
|
||||
if not name.startswith('__') and not callable(value) and isinstance(value, State):
|
||||
# change value of that variable
|
||||
value.name = ':'.join((cls.__name__, name))
|
||||
value.group = cls
|
||||
state_list.append(value)
|
||||
cls._state_list = state_list
|
||||
|
||||
@property
|
||||
def state_list(self):
|
||||
return self._state_list
|
||||
|
||||
|
||||
|
||||
class BaseMiddleware:
|
||||
"""
|
||||
Base class for middleware.
|
||||
Your middlewares should be inherited from this class.
|
||||
|
||||
Set update_sensitive=True if you want to get different updates on
|
||||
different functions. For example, if you want to handle pre_process for
|
||||
message update, then you will have to create pre_process_message function, and
|
||||
so on. Same applies to post_process.
|
||||
|
||||
.. note::
|
||||
If you want to use middleware, you have to set use_class_middlewares=True in your
|
||||
TeleBot instance.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example of class-based middlewares.
|
||||
|
||||
class MyMiddleware(BaseMiddleware):
|
||||
def __init__(self):
|
||||
self.update_sensitive = True
|
||||
self.update_types = ['message', 'edited_message']
|
||||
|
||||
def pre_process_message(self, message, data):
|
||||
# only message update here
|
||||
pass
|
||||
|
||||
def post_process_message(self, message, data, exception):
|
||||
pass # only message update here for post_process
|
||||
|
||||
def pre_process_edited_message(self, message, data):
|
||||
# only edited_message update here
|
||||
pass
|
||||
|
||||
def post_process_edited_message(self, message, data, exception):
|
||||
pass # only edited_message update here for post_process
|
||||
"""
|
||||
|
||||
update_sensitive: bool = False
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
@ -189,10 +256,10 @@ class SkipHandler:
|
|||
Update will go to post_process,
|
||||
but will skip execution of handler.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class CancelUpdate:
|
||||
"""
|
||||
Class for canceling updates.
|
||||
|
@ -201,6 +268,28 @@ class CancelUpdate:
|
|||
Update will skip handler and execution
|
||||
of post_process in middlewares.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class ContinueHandling:
|
||||
"""
|
||||
Class for continue updates in handlers.
|
||||
Just return instance of this class
|
||||
in handlers to continue process.
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example of using ContinueHandling
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
bot.send_message(message.chat.id, 'Hello World!')
|
||||
return ContinueHandling()
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start2(message):
|
||||
bot.send_message(message.chat.id, 'Hello World2!')
|
||||
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import random
|
||||
import string
|
||||
from io import BytesIO
|
||||
|
||||
try:
|
||||
# noinspection PyPackageRequirements
|
||||
from PIL import Image
|
||||
pil_imported = True
|
||||
except ImportError:
|
||||
pil_imported = False
|
||||
|
||||
|
||||
def is_string(var) -> bool:
|
||||
"""
|
||||
Returns True if the given object is a string.
|
||||
"""
|
||||
return isinstance(var, str)
|
||||
|
||||
|
||||
def is_dict(var) -> bool:
|
||||
"""
|
||||
Returns True if the given object is a dictionary.
|
||||
|
||||
:param var: object to be checked
|
||||
:type var: :obj:`object`
|
||||
|
||||
:return: True if the given object is a dictionary.
|
||||
:rtype: :obj:`bool`
|
||||
"""
|
||||
return isinstance(var, dict)
|
||||
|
||||
|
||||
def is_bytes(var) -> bool:
|
||||
"""
|
||||
Returns True if the given object is a bytes object.
|
||||
|
||||
:param var: object to be checked
|
||||
:type var: :obj:`object`
|
||||
|
||||
:return: True if the given object is a bytes object.
|
||||
:rtype: :obj:`bool`
|
||||
"""
|
||||
return isinstance(var, bytes)
|
||||
|
||||
|
||||
def is_pil_image(var) -> bool:
|
||||
"""
|
||||
Returns True if the given object is a PIL.Image.Image object.
|
||||
|
||||
:param var: object to be checked
|
||||
:type var: :obj:`object`
|
||||
|
||||
:return: True if the given object is a PIL.Image.Image object.
|
||||
:rtype: :obj:`bool`
|
||||
"""
|
||||
return pil_imported and isinstance(var, Image.Image)
|
||||
|
||||
|
||||
def pil_image_to_file(image, extension='JPEG', quality='web_low'):
|
||||
if pil_imported:
|
||||
photoBuffer = BytesIO()
|
||||
image.convert('RGB').save(photoBuffer, extension, quality=quality)
|
||||
photoBuffer.seek(0)
|
||||
|
||||
return photoBuffer
|
||||
else:
|
||||
raise RuntimeError('PIL module is not imported')
|
||||
|
||||
|
||||
def chunks(lst, n):
|
||||
"""Yield successive n-sized chunks from lst."""
|
||||
# https://stackoverflow.com/a/312464/9935473
|
||||
for i in range(0, len(lst), n):
|
||||
yield lst[i:i + n]
|
||||
|
||||
|
||||
def generate_random_token() -> str:
|
||||
"""
|
||||
Generates a random token consisting of letters and digits, 16 characters long.
|
||||
|
||||
:return: a random token
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
return ''.join(random.sample(string.ascii_letters, 16))
|
|
@ -41,7 +41,10 @@ class StateStorageBase:
|
|||
|
||||
def get_state(self, chat_id, user_id):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def get_interactive_data(self, chat_id, user_id):
|
||||
raise NotImplementedError
|
||||
|
||||
def save(self, chat_id, user_id, data):
|
||||
raise NotImplementedError
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from telebot.storage.base_storage import StateStorageBase, StateContext
|
|||
|
||||
class StateMemoryStorage(StateStorageBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.data = {}
|
||||
#
|
||||
# {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...}
|
||||
|
|
|
@ -5,8 +5,8 @@ import pickle
|
|||
|
||||
|
||||
class StatePickleStorage(StateStorageBase):
|
||||
# noinspection PyMissingConstructor
|
||||
def __init__(self, file_path="./.state-save/states.pkl") -> None:
|
||||
super().__init__()
|
||||
self.file_path = file_path
|
||||
self.create_dir()
|
||||
self.data = self.read()
|
||||
|
@ -34,7 +34,7 @@ class StatePickleStorage(StateStorageBase):
|
|||
"""
|
||||
Create directory .save-handlers.
|
||||
"""
|
||||
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
|
||||
dirs, filename = os.path.split(self.file_path)
|
||||
os.makedirs(dirs, exist_ok=True)
|
||||
if not os.path.isfile(self.file_path):
|
||||
with open(self.file_path,'wb') as file:
|
||||
|
|
|
@ -16,6 +16,7 @@ class StateRedisStorage(StateStorageBase):
|
|||
TeleBot(storage=StateRedisStorage())
|
||||
"""
|
||||
def __init__(self, host='localhost', port=6379, db=0, password=None, prefix='telebot_'):
|
||||
super().__init__()
|
||||
self.redis = ConnectionPool(host=host, port=port, db=db, password=password)
|
||||
#self.con = Redis(connection_pool=self.redis) -> use this when necessary
|
||||
#
|
||||
|
@ -173,7 +174,7 @@ class StateRedisStorage(StateStorageBase):
|
|||
user_id = str(user_id)
|
||||
if response:
|
||||
if user_id in response:
|
||||
response[user_id]['data'] = dict(data, **response[user_id]['data'])
|
||||
response[user_id]['data'] = data
|
||||
self.set_record(chat_id, response)
|
||||
return True
|
||||
|
||||
|
|
5311
telebot/types.py
5311
telebot/types.py
File diff suppressed because it is too large
Load Diff
354
telebot/util.py
354
telebot/util.py
|
@ -1,12 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import threading
|
||||
import traceback
|
||||
from typing import Any, Callable, List, Dict, Optional, Union
|
||||
import hmac
|
||||
import json
|
||||
from hashlib import sha256
|
||||
from urllib.parse import parse_qsl
|
||||
|
||||
|
@ -15,47 +12,47 @@ import queue as Queue
|
|||
import logging
|
||||
|
||||
from telebot import types
|
||||
from telebot.service_utils import is_pil_image, is_dict, is_string, is_bytes, chunks, generate_random_token, pil_image_to_file
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
try:
|
||||
# noinspection PyPackageRequirements
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
||||
pil_imported = True
|
||||
except:
|
||||
pil_imported = False
|
||||
|
||||
MAX_MESSAGE_LENGTH = 4096
|
||||
|
||||
logger = logging.getLogger('TeleBot')
|
||||
|
||||
thread_local = threading.local()
|
||||
|
||||
#: Contains all media content types.
|
||||
content_type_media = [
|
||||
'text', 'audio', 'animation', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact', 'dice', 'poll',
|
||||
'venue', 'location'
|
||||
'text', 'audio', 'document', 'animation', 'game', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact',
|
||||
'location', 'venue', 'dice', 'invoice', 'successful_payment', 'connected_website', 'poll', 'passport_data',
|
||||
'web_app_data',
|
||||
]
|
||||
|
||||
#: Contains all service content types such as `User joined the group`.
|
||||
content_type_service = [
|
||||
'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created',
|
||||
'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message',
|
||||
'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended',
|
||||
'video_chat_participants_invited', 'message_auto_delete_timer_changed'
|
||||
'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo',
|
||||
'group_chat_created', 'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id',
|
||||
'migrate_from_chat_id', 'pinned_message', 'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started',
|
||||
'video_chat_ended', 'video_chat_participants_invited', 'message_auto_delete_timer_changed', 'forum_topic_created',
|
||||
'forum_topic_closed', 'forum_topic_reopened', 'user_shared', 'chat_shared',
|
||||
]
|
||||
|
||||
#: All update types, should be used for allowed_updates parameter in polling.
|
||||
update_types = [
|
||||
"update_id", "message", "edited_message", "channel_post", "edited_channel_post", "inline_query",
|
||||
"chosen_inline_result", "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer",
|
||||
"my_chat_member", "chat_member", "chat_join_request"
|
||||
"message", "edited_message", "channel_post", "edited_channel_post", "inline_query", "chosen_inline_result",
|
||||
"callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer", "my_chat_member", "chat_member",
|
||||
"chat_join_request",
|
||||
]
|
||||
|
||||
|
||||
class WorkerThread(threading.Thread):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
count = 0
|
||||
|
||||
def __init__(self, exception_callback=None, queue=None, name=None):
|
||||
|
@ -119,6 +116,9 @@ class WorkerThread(threading.Thread):
|
|||
|
||||
|
||||
class ThreadPool:
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
|
||||
def __init__(self, telebot, num_threads=2):
|
||||
self.telebot = telebot
|
||||
|
@ -153,10 +153,15 @@ class ThreadPool:
|
|||
for worker in self.workers:
|
||||
worker.stop()
|
||||
for worker in self.workers:
|
||||
worker.join()
|
||||
if worker != threading.current_thread():
|
||||
worker.join()
|
||||
|
||||
|
||||
class AsyncTask:
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
|
||||
def __init__(self, target, *args, **kwargs):
|
||||
self.target = target
|
||||
self.args = args
|
||||
|
@ -183,7 +188,11 @@ class AsyncTask:
|
|||
|
||||
|
||||
class CustomRequestResponse():
|
||||
def __init__(self, json_text, status_code = 200, reason = ""):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
|
||||
def __init__(self, json_text, status_code=200, reason=""):
|
||||
self.status_code = status_code
|
||||
self.text = json_text
|
||||
self.reason = reason
|
||||
|
@ -193,6 +202,10 @@ class CustomRequestResponse():
|
|||
|
||||
|
||||
def async_dec():
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
|
||||
def decorator(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
return AsyncTask(fn, *args, **kwargs)
|
||||
|
@ -202,39 +215,15 @@ def async_dec():
|
|||
return decorator
|
||||
|
||||
|
||||
def is_string(var):
|
||||
return isinstance(var, str)
|
||||
|
||||
|
||||
def is_dict(var):
|
||||
return isinstance(var, dict)
|
||||
|
||||
|
||||
def is_bytes(var):
|
||||
return isinstance(var, bytes)
|
||||
|
||||
|
||||
def is_pil_image(var):
|
||||
return pil_imported and isinstance(var, Image.Image)
|
||||
|
||||
|
||||
def pil_image_to_file(image, extension='JPEG', quality='web_low'):
|
||||
if pil_imported:
|
||||
photoBuffer = BytesIO()
|
||||
image.convert('RGB').save(photoBuffer, extension, quality=quality)
|
||||
photoBuffer.seek(0)
|
||||
|
||||
return photoBuffer
|
||||
else:
|
||||
raise RuntimeError('PIL module is not imported')
|
||||
|
||||
|
||||
def is_command(text: str) -> bool:
|
||||
r"""
|
||||
Checks if `text` is a command. Telegram chat commands start with the '/' character.
|
||||
|
||||
:param text: Text to check.
|
||||
:type text: :obj:`str`
|
||||
|
||||
:return: True if `text` is a command, else False.
|
||||
:rtype: :obj:`bool`
|
||||
"""
|
||||
if text is None: return False
|
||||
return text.startswith('/')
|
||||
|
@ -245,35 +234,78 @@ def extract_command(text: str) -> Union[str, None]:
|
|||
Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
|
||||
If `text` is not a command, this function returns None.
|
||||
|
||||
Examples:
|
||||
extract_command('/help'): 'help'
|
||||
extract_command('/help@BotName'): 'help'
|
||||
extract_command('/search black eyed peas'): 'search'
|
||||
extract_command('Good day to you'): None
|
||||
.. code-block:: python3
|
||||
:caption: Examples:
|
||||
|
||||
extract_command('/help'): 'help'
|
||||
extract_command('/help@BotName'): 'help'
|
||||
extract_command('/search black eyed peas'): 'search'
|
||||
extract_command('Good day to you'): None
|
||||
|
||||
:param text: String to extract the command from
|
||||
:type text: :obj:`str`
|
||||
|
||||
:return: the command if `text` is a command (according to is_command), else None.
|
||||
:rtype: :obj:`str` or :obj:`None`
|
||||
"""
|
||||
if text is None: return None
|
||||
return text.split()[0].split('@')[0][1:] if is_command(text) else None
|
||||
|
||||
|
||||
def extract_arguments(text: str) -> str:
|
||||
def extract_arguments(text: str) -> str or None:
|
||||
"""
|
||||
Returns the argument after the command.
|
||||
|
||||
Examples:
|
||||
extract_arguments("/get name"): 'name'
|
||||
extract_arguments("/get"): ''
|
||||
extract_arguments("/get@botName name"): 'name'
|
||||
.. code-block:: python3
|
||||
:caption: Examples:
|
||||
|
||||
extract_arguments("/get name"): 'name'
|
||||
extract_arguments("/get"): ''
|
||||
extract_arguments("/get@botName name"): 'name'
|
||||
|
||||
:param text: String to extract the arguments from a command
|
||||
:type text: :obj:`str`
|
||||
|
||||
:return: the arguments if `text` is a command (according to is_command), else None.
|
||||
:rtype: :obj:`str` or :obj:`None`
|
||||
"""
|
||||
regexp = re.compile(r"/\w*(@\w*)*\s*([\s\S]*)", re.IGNORECASE)
|
||||
result = regexp.match(text)
|
||||
return result.group(2) if is_command(text) else None
|
||||
|
||||
def extract_entity(text: str, e: types.MessageEntity) -> str:
|
||||
"""
|
||||
Returns the content of the entity.
|
||||
|
||||
:param text: The text of the message the entity belongs to
|
||||
:type text: :obj:`str`
|
||||
|
||||
:param e: The entity to extract
|
||||
:type e: :obj:`MessageEntity`
|
||||
|
||||
:return: The content of the entity
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
offset = 0
|
||||
start = 0
|
||||
encoded_text = text.encode()
|
||||
end = len(encoded_text)
|
||||
i = 0
|
||||
|
||||
for byte in encoded_text:
|
||||
if (byte & 0xc0) != 0x80:
|
||||
if offset == e.offset:
|
||||
start = i
|
||||
elif offset - e.offset == e.length:
|
||||
end = i
|
||||
break
|
||||
if byte >= 0xf0:
|
||||
offset += 2
|
||||
else:
|
||||
offset += 1
|
||||
i += 1
|
||||
|
||||
return encoded_text[start:end].decode()
|
||||
|
||||
def split_string(text: str, chars_per_string: int) -> List[str]:
|
||||
"""
|
||||
|
@ -281,13 +313,18 @@ def split_string(text: str, chars_per_string: int) -> List[str]:
|
|||
This is very useful for splitting one giant message into multiples.
|
||||
|
||||
:param text: The text to split
|
||||
:type text: :obj:`str`
|
||||
|
||||
:param chars_per_string: The number of characters per line the text is split into.
|
||||
:type chars_per_string: :obj:`int`
|
||||
|
||||
:return: The splitted text as a list of strings.
|
||||
:rtype: :obj:`list` of :obj:`str`
|
||||
"""
|
||||
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
|
||||
|
||||
|
||||
def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str]:
|
||||
def smart_split(text: str, chars_per_string: int = MAX_MESSAGE_LENGTH) -> List[str]:
|
||||
r"""
|
||||
Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
|
||||
This is very useful for splitting one giant message into multiples.
|
||||
|
@ -295,8 +332,13 @@ def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str
|
|||
Splits by '\n', '. ' or ' ' in exactly this priority.
|
||||
|
||||
:param text: The text to split
|
||||
:type text: :obj:`str`
|
||||
|
||||
:param chars_per_string: The number of maximum characters per part the text is split to.
|
||||
:type chars_per_string: :obj:`int`
|
||||
|
||||
:return: The splitted text as a list of strings.
|
||||
:rtype: :obj:`list` of :obj:`str`
|
||||
"""
|
||||
|
||||
def _text_before_last(substr: str) -> str:
|
||||
|
@ -312,9 +354,12 @@ def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str
|
|||
|
||||
part = text[:chars_per_string]
|
||||
|
||||
if "\n" in part: part = _text_before_last("\n")
|
||||
elif ". " in part: part = _text_before_last(". ")
|
||||
elif " " in part: part = _text_before_last(" ")
|
||||
if "\n" in part:
|
||||
part = _text_before_last("\n")
|
||||
elif ". " in part:
|
||||
part = _text_before_last(". ")
|
||||
elif " " in part:
|
||||
part = _text_before_last(" ")
|
||||
|
||||
parts.append(part)
|
||||
text = text[len(part):]
|
||||
|
@ -328,43 +373,62 @@ def escape(text: str) -> str:
|
|||
:return: the escaped text
|
||||
"""
|
||||
chars = {"&": "&", "<": "<", ">": ">"}
|
||||
for old, new in chars.items(): text = text.replace(old, new)
|
||||
if text is None:
|
||||
return None
|
||||
for old, new in chars.items():
|
||||
text = text.replace(old, new)
|
||||
return text
|
||||
|
||||
|
||||
def user_link(user: types.User, include_id: bool=False) -> str:
|
||||
def user_link(user: types.User, include_id: bool = False) -> str:
|
||||
"""
|
||||
Returns an HTML user link. This is useful for reports.
|
||||
Attention: Don't forget to set parse_mode to 'HTML'!
|
||||
|
||||
Example:
|
||||
bot.send_message(your_user_id, user_link(message.from_user) + ' started the bot!', parse_mode='HTML')
|
||||
|
||||
.. code-block:: python3
|
||||
:caption: Example:
|
||||
|
||||
bot.send_message(your_user_id, user_link(message.from_user) + ' started the bot!', parse_mode='HTML')
|
||||
|
||||
.. note::
|
||||
You can use formatting.* for all other formatting options(bold, italic, links, and etc.)
|
||||
This method is kept for backward compatibility, and it is recommended to use formatting.* for
|
||||
more options.
|
||||
|
||||
:param user: the user (not the user_id)
|
||||
:type user: :obj:`telebot.types.User`
|
||||
|
||||
:param include_id: include the user_id
|
||||
:type include_id: :obj:`bool`
|
||||
|
||||
:return: HTML user link
|
||||
:rtype: :obj:`str`
|
||||
"""
|
||||
name = escape(user.first_name)
|
||||
return (f"<a href='tg://user?id={user.id}'>{name}</a>"
|
||||
+ (f" (<pre>{user.id}</pre>)" if include_id else ""))
|
||||
+ (f" (<pre>{user.id}</pre>)" if include_id else ""))
|
||||
|
||||
|
||||
def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.InlineKeyboardMarkup:
|
||||
def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int = 2) -> types.InlineKeyboardMarkup:
|
||||
"""
|
||||
Returns a reply markup from a dict in this format: {'text': kwargs}
|
||||
This is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)'
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python3
|
||||
:caption: Using quick_markup:
|
||||
|
||||
quick_markup({
|
||||
from telebot.util import quick_markup
|
||||
|
||||
markup = quick_markup({
|
||||
'Twitter': {'url': 'https://twitter.com'},
|
||||
'Facebook': {'url': 'https://facebook.com'},
|
||||
'Back': {'callback_data': 'whatever'}
|
||||
}, row_width=2):
|
||||
# returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook
|
||||
# and a back button below
|
||||
}, row_width=2)
|
||||
# returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook
|
||||
# and a back button below
|
||||
|
||||
# kwargs can be:
|
||||
{
|
||||
|
@ -379,8 +443,13 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
|
|||
}
|
||||
|
||||
:param values: a dict containing all buttons to create in this format: {text: kwargs} {str:}
|
||||
:param row_width: int row width
|
||||
:type values: :obj:`dict`
|
||||
|
||||
:param row_width: number of :class:`telebot.types.InlineKeyboardButton` objects on each row
|
||||
:type row_width: :obj:`int`
|
||||
|
||||
:return: InlineKeyboardMarkup
|
||||
:rtype: :obj:`types.InlineKeyboardMarkup`
|
||||
"""
|
||||
markup = types.InlineKeyboardMarkup(row_width=row_width)
|
||||
buttons = [
|
||||
|
@ -393,16 +462,25 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
|
|||
|
||||
# CREDITS TO http://stackoverflow.com/questions/12317940#answer-12320352
|
||||
def or_set(self):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
self._set()
|
||||
self.changed()
|
||||
|
||||
|
||||
def or_clear(self):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
self._clear()
|
||||
self.changed()
|
||||
|
||||
|
||||
def orify(e, changed_callback):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if not hasattr(e, "_set"):
|
||||
e._set = e.set
|
||||
if not hasattr(e, "_clear"):
|
||||
|
@ -413,6 +491,9 @@ def orify(e, changed_callback):
|
|||
|
||||
|
||||
def OrEvent(*events):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
or_event = threading.Event()
|
||||
|
||||
def changed():
|
||||
|
@ -436,6 +517,9 @@ def OrEvent(*events):
|
|||
|
||||
|
||||
def per_thread(key, construct_value, reset=False):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
if reset or not hasattr(thread_local, key):
|
||||
value = construct_value()
|
||||
setattr(thread_local, key, value)
|
||||
|
@ -443,26 +527,25 @@ def per_thread(key, construct_value, reset=False):
|
|||
return getattr(thread_local, key)
|
||||
|
||||
|
||||
def chunks(lst, n):
|
||||
"""Yield successive n-sized chunks from lst."""
|
||||
# https://stackoverflow.com/a/312464/9935473
|
||||
for i in range(0, len(lst), n):
|
||||
yield lst[i:i + n]
|
||||
|
||||
|
||||
def generate_random_token():
|
||||
return ''.join(random.sample(string.ascii_letters, 16))
|
||||
|
||||
|
||||
def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecation_text=None):
|
||||
def deprecated(warn: bool = True, alternative: Optional[Callable] = None, deprecation_text=None):
|
||||
"""
|
||||
Use this decorator to mark functions as deprecated.
|
||||
When the function is used, an info (or warning if `warn` is True) is logged.
|
||||
|
||||
:meta private:
|
||||
|
||||
:param warn: If True a warning is logged else an info
|
||||
:type warn: :obj:`bool`
|
||||
|
||||
:param alternative: The new function to use instead
|
||||
:type alternative: :obj:`Callable`
|
||||
|
||||
:param deprecation_text: Custom deprecation text
|
||||
:type deprecation_text: :obj:`str`
|
||||
|
||||
:return: The decorated function
|
||||
"""
|
||||
|
||||
def decorator(function):
|
||||
def wrapper(*args, **kwargs):
|
||||
info = f"`{function.__name__}` is deprecated."
|
||||
|
@ -475,13 +558,25 @@ def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecatio
|
|||
else:
|
||||
logger.warning(info)
|
||||
return function(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
# Cloud helpers
|
||||
def webhook_google_functions(bot, request):
|
||||
"""A webhook endpoint for Google Cloud Functions FaaS."""
|
||||
"""
|
||||
A webhook endpoint for Google Cloud Functions FaaS.
|
||||
|
||||
:param bot: The bot instance
|
||||
:type bot: :obj:`telebot.TeleBot` or :obj:`telebot.async_telebot.AsyncTeleBot`
|
||||
|
||||
:param request: The request object
|
||||
:type request: :obj:`flask.Request`
|
||||
|
||||
:return: The response object
|
||||
"""
|
||||
if request.is_json:
|
||||
try:
|
||||
request_json = request.get_json()
|
||||
|
@ -495,7 +590,7 @@ def webhook_google_functions(bot, request):
|
|||
return 'Bot ON'
|
||||
|
||||
|
||||
def antiflood(function, *args, **kwargs):
|
||||
def antiflood(function: Callable, *args, number_retries=5, **kwargs):
|
||||
"""
|
||||
Use this function inside loops in order to avoid getting TooManyRequests error.
|
||||
Example:
|
||||
|
@ -506,26 +601,48 @@ def antiflood(function, *args, **kwargs):
|
|||
for chat_id in chat_id_list:
|
||||
msg = antiflood(bot.send_message, chat_id, text)
|
||||
|
||||
:param function:
|
||||
:param args:
|
||||
:param kwargs:
|
||||
:param function: The function to call
|
||||
:type function: :obj:`Callable`
|
||||
|
||||
:param number_retries: Number of retries to send
|
||||
:type function: :obj:int
|
||||
|
||||
:param args: The arguments to pass to the function
|
||||
:type args: :obj:`tuple`
|
||||
|
||||
:param kwargs: The keyword arguments to pass to the function
|
||||
:type kwargs: :obj:`dict`
|
||||
|
||||
:return: None
|
||||
"""
|
||||
from telebot.apihelper import ApiTelegramException
|
||||
from time import sleep
|
||||
msg = None
|
||||
try:
|
||||
msg = function(*args, **kwargs)
|
||||
except ApiTelegramException as ex:
|
||||
if ex.error_code == 429:
|
||||
sleep(ex.result_json['parameters']['retry_after'])
|
||||
msg = function(*args, **kwargs)
|
||||
finally:
|
||||
return msg
|
||||
|
||||
|
||||
|
||||
for _ in range(number_retries - 1):
|
||||
try:
|
||||
return function(*args, **kwargs)
|
||||
except ApiTelegramException as ex:
|
||||
if ex.error_code == 429:
|
||||
sleep(ex.result_json['parameters']['retry_after'])
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
return function(*args, **kwargs)
|
||||
|
||||
|
||||
def parse_web_app_data(token: str, raw_init_data: str):
|
||||
is_valid = validate_WebApp_data(token, raw_init_data)
|
||||
"""
|
||||
Parses web app data.
|
||||
|
||||
:param token: The bot token
|
||||
:type token: :obj:`str`
|
||||
|
||||
:param raw_init_data: The raw init data
|
||||
:type raw_init_data: :obj:`str`
|
||||
|
||||
:return: The parsed init data
|
||||
"""
|
||||
is_valid = validate_web_app_data(token, raw_init_data)
|
||||
if not is_valid:
|
||||
return False
|
||||
|
||||
|
@ -540,7 +657,18 @@ def parse_web_app_data(token: str, raw_init_data: str):
|
|||
return result
|
||||
|
||||
|
||||
def validate_web_app_data(token, raw_init_data):
|
||||
def validate_web_app_data(token: str, raw_init_data: str):
|
||||
"""
|
||||
Validates web app data.
|
||||
|
||||
:param token: The bot token
|
||||
:type token: :obj:`str`
|
||||
|
||||
:param raw_init_data: The raw init data
|
||||
:type raw_init_data: :obj:`str`
|
||||
|
||||
:return: The parsed init data
|
||||
"""
|
||||
try:
|
||||
parsed_data = dict(parse_qsl(raw_init_data))
|
||||
except ValueError:
|
||||
|
@ -554,4 +682,16 @@ def validate_web_app_data(token, raw_init_data):
|
|||
|
||||
return hmac.new(secret_key.digest(), data_check_string.encode(), sha256).hexdigest() == init_data_hash
|
||||
|
||||
|
||||
|
||||
__all__ = (
|
||||
"content_type_media", "content_type_service", "update_types",
|
||||
"WorkerThread", "AsyncTask", "CustomRequestResponse",
|
||||
"async_dec", "deprecated",
|
||||
"is_bytes", "is_string", "is_dict", "is_pil_image",
|
||||
"chunks", "generate_random_token", "pil_image_to_file",
|
||||
"is_command", "extract_command", "extract_arguments",
|
||||
"split_string", "smart_split", "escape", "user_link", "quick_markup",
|
||||
"antiflood", "parse_web_app_data", "validate_web_app_data",
|
||||
"or_set", "or_clear", "orify", "OrEvent", "per_thread",
|
||||
"webhook_google_functions"
|
||||
)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Versions should comply with PEP440.
|
||||
# This line is parsed in setup.py:
|
||||
__version__ = '4.6.0'
|
||||
__version__ = '4.12.0'
|
||||
|
|
|
@ -470,6 +470,53 @@ class TestTeleBot:
|
|||
for i in range(0,200):
|
||||
util.antiflood(tb.send_message, CHAT_ID, text)
|
||||
assert i == 199
|
||||
|
||||
def test_extract_entity(self):
|
||||
entities_map = {"https://core.telegram.org/api/entities": "https://core.telegram.org/api/entities",
|
||||
"https://github.com/eternnoir/pyTelegramBotAPI": "https://github.com/eternnoir/pyTelegramBotAPI",
|
||||
"*粗 bold text体*": "粗 bold text体",
|
||||
"_斜体 italic text_": "斜体 italic text",
|
||||
"[谷歌](http://www.google.com/)": "谷歌",
|
||||
'`std::cout<<"test"<<std::endl;`': 'std::cout<<"test"<<std::endl;',
|
||||
'''```rust
|
||||
let number = loop {
|
||||
println!("Pick a pattern from 0-2:");
|
||||
stdin.read_line(&mut option).unwrap();
|
||||
match option.lines().next().unwrap().parse::<usize>() {
|
||||
Ok(number @ 0..=2) => break number,
|
||||
_ => {
|
||||
println!("invalid input!");
|
||||
option = String::new();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
};```''': '''let number = loop {
|
||||
println!("Pick a pattern from 0-2:");
|
||||
stdin.read_line(&mut option).unwrap();
|
||||
match option.lines().next().unwrap().parse::<usize>() {
|
||||
Ok(number @ 0..=2) => break number,
|
||||
_ => {
|
||||
println!("invalid input!");
|
||||
option = String::new();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
};''',
|
||||
"@username": "@username",
|
||||
"#hashtag索引标签": "#hashtag索引标签",
|
||||
"do-not-reply@telegram.org": "do-not-reply@telegram.org",
|
||||
"+12125550123": "+12125550123"}
|
||||
entites = list(entities_map.keys())
|
||||
contents = list(entities_map.values())
|
||||
contents.sort()
|
||||
text = '\n'.join(entites)
|
||||
|
||||
bot = telebot.TeleBot(TOKEN)
|
||||
message = bot.send_message(CHAT_ID, text, parse_mode="Markdown")
|
||||
extracted_contents = [util.extract_entity(
|
||||
message.text, e) for e in message.entities]
|
||||
extracted_contents.sort()
|
||||
assert contents == extracted_contents
|
||||
|
||||
@staticmethod
|
||||
def create_text_message(text):
|
||||
|
|
|
@ -67,9 +67,9 @@ def test_json_GroupChat():
|
|||
|
||||
|
||||
def test_json_Document():
|
||||
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
|
||||
json_string = r'{"file_name":"Text File","thumbnail":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
|
||||
doc = types.Document.de_json(json_string)
|
||||
assert doc.thumb is None
|
||||
assert doc.thumbnail is None
|
||||
assert doc.file_name == 'Text File'
|
||||
|
||||
|
||||
|
@ -83,23 +83,23 @@ def test_json_Message_Audio():
|
|||
|
||||
|
||||
def test_json_Message_Sticker():
|
||||
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumb": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
|
||||
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumbnail": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.sticker.height == 368
|
||||
assert msg.sticker.thumb.height == 60
|
||||
assert msg.sticker.thumbnail.height == 60
|
||||
assert msg.content_type == 'sticker'
|
||||
|
||||
|
||||
def test_json_Message_Sticker_without_thumb():
|
||||
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
|
||||
def test_json_Message_Sticker_without_thumbnail():
|
||||
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.sticker.height == 368
|
||||
assert msg.sticker.thumb is None
|
||||
assert msg.sticker.thumbnail is None
|
||||
assert msg.content_type == 'sticker'
|
||||
|
||||
|
||||
def test_json_Message_Document():
|
||||
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}'
|
||||
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumbnail":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.document.file_name == 'Text File'
|
||||
assert msg.content_type == 'document'
|
||||
|
@ -113,11 +113,11 @@ def test_json_Message_Photo():
|
|||
|
||||
|
||||
def test_json_Message_Video():
|
||||
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}'
|
||||
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumbnail":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.video
|
||||
assert msg.video.duration == 3
|
||||
assert msg.video.thumb.width == 50
|
||||
assert msg.video.thumbnail.width == 50
|
||||
assert msg.content_type == 'video'
|
||||
|
||||
|
||||
|
@ -271,5 +271,33 @@ def test_sent_web_app_message():
|
|||
assert sent_web_app_message.inline_message_id == '29430'
|
||||
|
||||
|
||||
def test_message_entity():
|
||||
# TODO: Add support for nesting entities
|
||||
|
||||
|
||||
sample_string_1 = r'{"update_id":934522126,"message":{"message_id":1374510,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682177590,"text":"b b b","entities":[{"offset":0,"length":2,"type":"bold"},{"offset":0,"length":1,"type":"italic"},{"offset":2,"length":2,"type":"bold"},{"offset":2,"length":1,"type":"italic"},{"offset":4,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
|
||||
update = types.Update.de_json(sample_string_1)
|
||||
message: types.Message = update.message
|
||||
assert message.html_text == "<i><b>b </b></i><i><b>b </b></i><i><b>b</b></i>"
|
||||
|
||||
sample_string_2 = r'{"update_id":934522166,"message":{"message_id":1374526,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179716,"text":"b b b","entities":[{"offset":0,"length":1,"type":"bold"},{"offset":2,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
|
||||
message_2 = types.Update.de_json(sample_string_2).message
|
||||
assert message_2.html_text == "<b>b</b> <b>b</b> <i>b</i>"
|
||||
|
||||
|
||||
|
||||
sample_string_3 = r'{"update_id":934522172,"message":{"message_id":1374530,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179968,"text":"This is a bold text with a nested italic and bold text.","entities":[{"offset":10,"length":4,"type":"bold"},{"offset":27,"length":7,"type":"italic"},{"offset":34,"length":15,"type":"bold"},{"offset":34,"length":15,"type":"italic"}]}}'
|
||||
message_3 = types.Update.de_json(sample_string_3).message
|
||||
assert message_3.html_text == "This is a <b>bold</b> text with a <i>nested </i><i><b>italic and bold</b></i> text."
|
||||
|
||||
|
||||
sample_string_4 = r'{"update_id":934522437,"message":{"message_id":1374619,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682189507,"forward_from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"forward_date":1682189124,"text":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa😋😋","entities":[{"offset":0,"length":76,"type":"bold"},{"offset":0,"length":76,"type":"italic"},{"offset":0,"length":76,"type":"underline"},{"offset":0,"length":76,"type":"strikethrough"},{"offset":76,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"},{"offset":78,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"}]}}'
|
||||
message_4 = types.Update.de_json(sample_string_4).message
|
||||
assert message_4.html_text == '<s><u><i><b>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</b></i></u></s><tg-emoji emoji-id="5456188142006575553">😋</tg-emoji><tg-emoji emoji-id="5456188142006575553">😋</tg-emoji>'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue