pyrobale 0.3.9__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyrobale/client/__init__.py +338 -749
- pyrobale/objects/enums.py +1 -0
- {pyrobale-0.3.9.dist-info → pyrobale-0.4.0.dist-info}/METADATA +1 -1
- {pyrobale-0.3.9.dist-info → pyrobale-0.4.0.dist-info}/RECORD +6 -6
- {pyrobale-0.3.9.dist-info → pyrobale-0.4.0.dist-info}/WHEEL +0 -0
- {pyrobale-0.3.9.dist-info → pyrobale-0.4.0.dist-info}/licenses/LICENSE +0 -0
pyrobale/client/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional, Union, List, Dict, Any, Callable, Awaitable
|
1
|
+
from typing import Optional, Union, List, Dict, Any, Callable, Awaitable
|
2
2
|
from ..objects.animation import Animation
|
3
3
|
from ..objects.audio import Audio
|
4
4
|
from ..objects.callbackquery import CallbackQuery
|
@@ -39,7 +39,7 @@ from ..objects.webappinfo import WebAppInfo
|
|
39
39
|
from ..objects.utils import *
|
40
40
|
from ..objects.enums import UpdatesTypes, ChatAction, ChatType
|
41
41
|
from ..objects.peerdata import PeerData
|
42
|
-
from ..filters import Filters
|
42
|
+
from ..filters import Filters
|
43
43
|
from ..StateMachine import StateMachine
|
44
44
|
from ..exceptions import NotFoundException, InvalidTokenException, PyroBaleException
|
45
45
|
|
@@ -47,6 +47,8 @@ from enum import Enum
|
|
47
47
|
import asyncio
|
48
48
|
from bs4 import BeautifulSoup
|
49
49
|
from json import loads, JSONDecodeError
|
50
|
+
import aiohttp
|
51
|
+
|
50
52
|
|
51
53
|
class Client:
|
52
54
|
"""A client for interacting with the Bale messenger API.
|
@@ -71,95 +73,56 @@ class Client:
|
|
71
73
|
self.defined_messages = {}
|
72
74
|
|
73
75
|
async def get_updates(
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
self,
|
77
|
+
offset: Optional[int] = None,
|
78
|
+
limit: Optional[int] = None,
|
79
|
+
timeout: Optional[int] = None,
|
78
80
|
) -> List[Dict]:
|
79
|
-
"""Get updates from the Bale API.
|
80
|
-
|
81
|
-
Args:
|
82
|
-
offset (int, optional): The offset of the updates to get. Defaults to None.
|
83
|
-
limit (int, optional): The maximum number of updates to get. Defaults to None.
|
84
|
-
timeout (int, optional): The timeout for the request. Defaults to None.
|
85
|
-
Returns:
|
86
|
-
List[Dict]: The updates.
|
87
|
-
"""
|
81
|
+
"""Get updates from the Bale API."""
|
88
82
|
data = await make_get(
|
89
|
-
self.requests_base
|
90
|
-
+ f"/getUpdates?offset={offset}&limit={limit}&timeout={timeout}"
|
83
|
+
self.requests_base + f"/getUpdates?offset={offset}&limit={limit}&timeout={timeout}"
|
91
84
|
)
|
92
85
|
if data['ok']:
|
93
|
-
if 'result' in data
|
86
|
+
if 'result' in data:
|
94
87
|
return data["result"]
|
95
88
|
else:
|
96
|
-
if data
|
89
|
+
if data.get('error_code') == 403:
|
97
90
|
raise InvalidTokenException("Forbidden 403 : --ENTERED TOKEN IS NOT VALID--")
|
91
|
+
return []
|
98
92
|
|
99
93
|
async def set_webhook(self, url: str) -> bool:
|
100
|
-
"""Set the webhook for the bot.
|
101
|
-
|
102
|
-
Args:
|
103
|
-
url (str): The URL to set the webhook to.
|
104
|
-
Returns:
|
105
|
-
bool: True if the webhook was set successfully, False otherwise.
|
106
|
-
"""
|
94
|
+
"""Set the webhook for the bot."""
|
107
95
|
data = await make_post(self.requests_base + "/setWebhook", data={"url": url})
|
108
|
-
return data
|
96
|
+
return data.get("ok", False)
|
109
97
|
|
110
98
|
async def get_webhook_info(self) -> Dict:
|
111
|
-
"""Get the webhook information for the bot.
|
112
|
-
|
113
|
-
Returns:
|
114
|
-
Dict: The webhook information.
|
115
|
-
"""
|
99
|
+
"""Get the webhook information for the bot."""
|
116
100
|
data = await make_get(self.requests_base + "/getWebhookInfo")
|
117
|
-
return data
|
101
|
+
return data.get("result", {})
|
118
102
|
|
119
103
|
async def get_me(self) -> User:
|
120
|
-
"""Get information about the bot.
|
121
|
-
|
122
|
-
Returns:
|
123
|
-
User: The information about the bot.
|
124
|
-
"""
|
104
|
+
"""Get information about the bot."""
|
125
105
|
data = await make_get(self.requests_base + "/getMe")
|
126
106
|
return User(**data["result"])
|
127
107
|
|
128
108
|
async def logout(self) -> bool:
|
129
|
-
"""Log out the bot.
|
130
|
-
|
131
|
-
Returns:
|
132
|
-
bool: True if the bot was logged out successfully, False otherwise.
|
133
|
-
"""
|
109
|
+
"""Log out the bot."""
|
134
110
|
data = await make_get(self.requests_base + "/logOut")
|
135
|
-
return data
|
111
|
+
return data.get("ok", False)
|
136
112
|
|
137
113
|
async def close(self) -> bool:
|
138
|
-
"""Close the bot.
|
139
|
-
|
140
|
-
Returns:
|
141
|
-
bool: True if the bot was closed successfully, False otherwise.
|
142
|
-
"""
|
114
|
+
"""Close the bot."""
|
143
115
|
data = await make_get(self.requests_base + "/close")
|
144
|
-
return data
|
116
|
+
return data.get("ok", False)
|
145
117
|
|
146
118
|
async def send_message(
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
119
|
+
self,
|
120
|
+
chat_id: int,
|
121
|
+
text: str,
|
122
|
+
reply_to_message_id: Optional[int] = None,
|
123
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
152
124
|
) -> Message:
|
153
|
-
"""Send a message to a chat.
|
154
|
-
|
155
|
-
Args:
|
156
|
-
chat_id (int): The ID of the chat to send the message to.
|
157
|
-
text (str): The text of the message.
|
158
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
159
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
160
|
-
Returns:
|
161
|
-
Message: The message that was sent.
|
162
|
-
"""
|
125
|
+
"""Send a message to a chat."""
|
163
126
|
data = await make_post(
|
164
127
|
self.requests_base + "/sendMessage",
|
165
128
|
data={
|
@@ -172,17 +135,9 @@ class Client:
|
|
172
135
|
return Message(**pythonize(data["result"]))
|
173
136
|
|
174
137
|
async def forward_message(
|
175
|
-
|
138
|
+
self, chat_id: int, from_chat_id: int, message_id: int
|
176
139
|
) -> Message:
|
177
|
-
"""Forward a message to a chat.
|
178
|
-
|
179
|
-
Args:
|
180
|
-
chat_id (int): The ID of the chat to forward the message to.
|
181
|
-
from_chat_id (int): The ID of the chat to forward the message from.
|
182
|
-
message_id (int): The ID of the message to forward.
|
183
|
-
Returns:
|
184
|
-
Message: The message that was forwarded.
|
185
|
-
"""
|
140
|
+
"""Forward a message to a chat."""
|
186
141
|
data = await make_post(
|
187
142
|
self.requests_base + "/forwardMessage",
|
188
143
|
data={
|
@@ -194,17 +149,9 @@ class Client:
|
|
194
149
|
return Message(**pythonize(data["result"]))
|
195
150
|
|
196
151
|
async def copy_message(
|
197
|
-
|
152
|
+
self, chat_id: int, from_chat_id: int, message_id: int
|
198
153
|
) -> Message:
|
199
|
-
"""Copy a message to a chat.
|
200
|
-
|
201
|
-
Args:
|
202
|
-
chat_id (int): The ID of the chat to copy the message to.
|
203
|
-
from_chat_id (int): The ID of the chat to copy the message from.
|
204
|
-
message_id (int): The ID of the message to copy.
|
205
|
-
Returns:
|
206
|
-
Message: The message that was copied.
|
207
|
-
"""
|
154
|
+
"""Copy a message to a chat."""
|
208
155
|
data = await make_post(
|
209
156
|
self.requests_base + "/copyMessage",
|
210
157
|
data={
|
@@ -216,24 +163,14 @@ class Client:
|
|
216
163
|
return Message(**pythonize(data["result"]))
|
217
164
|
|
218
165
|
async def send_photo(
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
166
|
+
self,
|
167
|
+
chat_id: Union[int, str],
|
168
|
+
photo: Union[InputFile, str],
|
169
|
+
caption: Optional[str] = None,
|
170
|
+
reply_to_message_id: Optional[int] = None,
|
171
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
225
172
|
) -> Message:
|
226
|
-
"""Send a photo to a chat.
|
227
|
-
|
228
|
-
Args:
|
229
|
-
chat_id (Union[int, str]): The ID of the chat to send the photo to.
|
230
|
-
photo (Union[InputFile, str]): The photo to send.
|
231
|
-
caption (str, optional): The caption of the photo. Defaults to None.
|
232
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
233
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
234
|
-
Returns:
|
235
|
-
Message: The message that was sent.
|
236
|
-
"""
|
173
|
+
"""Send a photo to a chat."""
|
237
174
|
data = await make_post(
|
238
175
|
self.requests_base + "/sendPhoto",
|
239
176
|
data={
|
@@ -247,24 +184,14 @@ class Client:
|
|
247
184
|
return Message(**pythonize(data["result"]))
|
248
185
|
|
249
186
|
async def send_audio(
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
187
|
+
self,
|
188
|
+
chat_id: int,
|
189
|
+
audio: Union[InputFile, str],
|
190
|
+
caption: Optional[str] = None,
|
191
|
+
reply_to_message_id: Optional[int] = None,
|
192
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
256
193
|
) -> Message:
|
257
|
-
"""Send an audio to a chat.
|
258
|
-
|
259
|
-
Args:
|
260
|
-
chat_id (int): The ID of the chat to send the audio to.
|
261
|
-
audio (Union[InputFile, str]): The audio to send.
|
262
|
-
caption (str, optional): The caption of the audio. Defaults to None.
|
263
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
264
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
265
|
-
Returns:
|
266
|
-
Message: The message that was sent.
|
267
|
-
"""
|
194
|
+
"""Send an audio to a chat."""
|
268
195
|
data = await make_post(
|
269
196
|
self.requests_base + "/sendAudio",
|
270
197
|
data={
|
@@ -278,24 +205,14 @@ class Client:
|
|
278
205
|
return Message(**pythonize(data["result"]))
|
279
206
|
|
280
207
|
async def send_document(
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
208
|
+
self,
|
209
|
+
chat_id: int,
|
210
|
+
document: Union[InputFile, str],
|
211
|
+
caption: Optional[str] = None,
|
212
|
+
reply_to_message_id: Optional[int] = None,
|
213
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
287
214
|
) -> Message:
|
288
|
-
"""Send a document to a chat.
|
289
|
-
|
290
|
-
Args:
|
291
|
-
chat_id (int): The ID of the chat to send the document to.
|
292
|
-
document (Union[InputFile, str]): The document to send.
|
293
|
-
caption (str, optional): The caption of the document. Defaults to None.
|
294
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
295
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
296
|
-
Returns:
|
297
|
-
Message: The message that was sent.
|
298
|
-
"""
|
215
|
+
"""Send a document to a chat."""
|
299
216
|
data = await make_post(
|
300
217
|
self.requests_base + "/sendDocument",
|
301
218
|
data={
|
@@ -309,24 +226,14 @@ class Client:
|
|
309
226
|
return Message(**pythonize(data["result"]))
|
310
227
|
|
311
228
|
async def send_video(
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
229
|
+
self,
|
230
|
+
chat_id: int,
|
231
|
+
video: Union[InputFile, str],
|
232
|
+
caption: Optional[str] = None,
|
233
|
+
reply_to_message_id: Optional[int] = None,
|
234
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
318
235
|
) -> Message:
|
319
|
-
"""Send a video to a chat.
|
320
|
-
|
321
|
-
Args:
|
322
|
-
chat_id (int): The ID of the chat to send the video to.
|
323
|
-
video (Union[InputFile, str]): The video to send.
|
324
|
-
caption (str, optional): The caption of the video. Defaults to None.
|
325
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
326
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
327
|
-
Returns:
|
328
|
-
Message: The message that was sent.
|
329
|
-
"""
|
236
|
+
"""Send a video to a chat."""
|
330
237
|
data = await make_post(
|
331
238
|
self.requests_base + "/sendVideo",
|
332
239
|
data={
|
@@ -340,24 +247,14 @@ class Client:
|
|
340
247
|
return Message(**pythonize(data["result"]))
|
341
248
|
|
342
249
|
async def send_animation(
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
250
|
+
self,
|
251
|
+
chat_id: int,
|
252
|
+
animation: Union[InputFile, str],
|
253
|
+
caption: Optional[str] = None,
|
254
|
+
reply_to_message_id: Optional[int] = None,
|
255
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
349
256
|
) -> Message:
|
350
|
-
"""Send an animation to a chat.
|
351
|
-
|
352
|
-
Args:
|
353
|
-
chat_id (int): The ID of the chat to send the animation to.
|
354
|
-
animation (Union[InputFile, str]): The animation to send.
|
355
|
-
caption (str, optional): The caption of the animation. Defaults to None.
|
356
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
357
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
358
|
-
Returns:
|
359
|
-
Message: The message that was sent.
|
360
|
-
"""
|
257
|
+
"""Send an animation to a chat."""
|
361
258
|
data = await make_post(
|
362
259
|
self.requests_base + "/sendAnimation",
|
363
260
|
data={
|
@@ -371,24 +268,14 @@ class Client:
|
|
371
268
|
return Message(**pythonize(data["result"]))
|
372
269
|
|
373
270
|
async def send_voice(
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
271
|
+
self,
|
272
|
+
chat_id: int,
|
273
|
+
voice: Union[InputFile, str],
|
274
|
+
caption: Optional[str] = None,
|
275
|
+
reply_to_message_id: Optional[int] = None,
|
276
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
380
277
|
) -> Message:
|
381
|
-
"""Send a voice message to a chat.
|
382
|
-
|
383
|
-
Args:
|
384
|
-
chat_id (int): The ID of the chat to send the voice message to.
|
385
|
-
voice (Union[InputFile, str]): The voice message to send.
|
386
|
-
caption (str, optional): The caption of the voice message. Defaults to None.
|
387
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
388
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
389
|
-
Returns:
|
390
|
-
Message: The message that was sent.
|
391
|
-
"""
|
278
|
+
"""Send a voice message to a chat."""
|
392
279
|
data = await make_post(
|
393
280
|
self.requests_base + "/sendVoice",
|
394
281
|
data={
|
@@ -402,22 +289,13 @@ class Client:
|
|
402
289
|
return Message(**pythonize(data["result"]))
|
403
290
|
|
404
291
|
async def send_media_group(
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
292
|
+
self,
|
293
|
+
chat_id: int,
|
294
|
+
media: List[Union[InputMediaPhoto, InputMediaVideo, InputMediaAudio]],
|
295
|
+
reply_to_message_id: Optional[int] = None,
|
296
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
410
297
|
) -> List[Message]:
|
411
|
-
"""Send a media group to a chat.
|
412
|
-
|
413
|
-
Args:
|
414
|
-
chat_id (int): The ID of the chat to send the media group to.
|
415
|
-
media (List[Union[InputMediaPhoto, InputMediaVideo, InputMediaAudio]]): The media group to send.
|
416
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
417
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
418
|
-
Returns:
|
419
|
-
List[Message]: The messages that were sent.
|
420
|
-
"""
|
298
|
+
"""Send a media group to a chat."""
|
421
299
|
data = await make_post(
|
422
300
|
self.requests_base + "/sendMediaGroup",
|
423
301
|
data={
|
@@ -427,28 +305,18 @@ class Client:
|
|
427
305
|
"reply_markup": reply_markup.to_dict() if reply_markup else None,
|
428
306
|
},
|
429
307
|
)
|
430
|
-
return Message(**pythonize(data["result"]
|
308
|
+
return [Message(**pythonize(msg)) for msg in data["result"]]
|
431
309
|
|
432
310
|
async def send_location(
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
311
|
+
self,
|
312
|
+
chat_id: int,
|
313
|
+
latitude: float,
|
314
|
+
longitude: float,
|
315
|
+
horizontal_accuracy: Optional[float] = None,
|
316
|
+
reply_to_message_id: Optional[int] = None,
|
317
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
440
318
|
) -> Message:
|
441
|
-
"""Send a location to a chat.
|
442
|
-
|
443
|
-
Args:
|
444
|
-
chat_id (int): The ID of the chat to send the location to.
|
445
|
-
latitude (float): The latitude of the location.
|
446
|
-
longitude (float): The longitude of the location.
|
447
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
448
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
449
|
-
Returns:
|
450
|
-
Message: The message that was sent.
|
451
|
-
"""
|
319
|
+
"""Send a location to a chat."""
|
452
320
|
data = await make_post(
|
453
321
|
self.requests_base + "/sendLocation",
|
454
322
|
data={
|
@@ -463,26 +331,15 @@ class Client:
|
|
463
331
|
return Message(**pythonize(data["result"]))
|
464
332
|
|
465
333
|
async def send_contact(
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
334
|
+
self,
|
335
|
+
chat_id: int,
|
336
|
+
phone_number: str,
|
337
|
+
first_name: str,
|
338
|
+
last_name: Optional[str] = None,
|
339
|
+
reply_to_message_id: Optional[int] = None,
|
340
|
+
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
473
341
|
) -> Message:
|
474
|
-
"""Send a contact to a chat.
|
475
|
-
|
476
|
-
Args:
|
477
|
-
chat_id (int): The ID of the chat to send the contact to.
|
478
|
-
phone_number (str): The phone number of the contact.
|
479
|
-
first_name (str): The first name of the contact.
|
480
|
-
last_name (str, optional): The last name of the contact. Defaults to None.
|
481
|
-
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
482
|
-
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
483
|
-
Returns:
|
484
|
-
Message: The message that was sent.
|
485
|
-
"""
|
342
|
+
"""Send a contact to a chat."""
|
486
343
|
data = await make_post(
|
487
344
|
self.requests_base + "/sendContact",
|
488
345
|
data={
|
@@ -497,34 +354,18 @@ class Client:
|
|
497
354
|
return Message(**pythonize(data["result"]))
|
498
355
|
|
499
356
|
async def send_invoice(
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
357
|
+
self,
|
358
|
+
chat_id: Union[str, int],
|
359
|
+
title: str,
|
360
|
+
description: str,
|
361
|
+
payload: str,
|
362
|
+
provider_token: str,
|
363
|
+
prices: list[LabeledPrice],
|
364
|
+
photo_url: Optional[str] = None,
|
365
|
+
reply_to_message_id: Optional[int] = None,
|
509
366
|
) -> Message:
|
510
|
-
"""Sends a message including a invoice for user to pay.
|
511
|
-
|
512
|
-
Args:
|
513
|
-
chat_id (string OR integer): unique chat id to send the invoice
|
514
|
-
title (string): the title of invoice
|
515
|
-
description (string): desciption of invoice, you can explain the invoice here
|
516
|
-
payload (string): payload of invoice, user will not see this, it'll be returned after successful payment
|
517
|
-
provider_token (string): Wallet token or card number of receiver
|
518
|
-
prices (list of LabledPrice): a list of prices that user must pay
|
519
|
-
photo_url (Optional: string): url of a photo that will be sent with invoice
|
520
|
-
reply_to_message_id (Optional: int): message id to reply that
|
521
|
-
|
522
|
-
Returns:
|
523
|
-
Message: returns the sent message with invoice
|
524
|
-
"""
|
525
|
-
new_prices = []
|
526
|
-
for price in prices:
|
527
|
-
new_prices.append(price.json)
|
367
|
+
"""Sends a message including a invoice for user to pay."""
|
368
|
+
new_prices = [price.json for price in prices]
|
528
369
|
data = await make_post(
|
529
370
|
self.requests_base + "/sendInvoice",
|
530
371
|
data={
|
@@ -541,33 +382,19 @@ class Client:
|
|
541
382
|
return Message(**pythonize(data["result"]))
|
542
383
|
|
543
384
|
async def get_file(self, file_id: str) -> File:
|
544
|
-
"""Get a file from the Bale servers.
|
545
|
-
|
546
|
-
Args:
|
547
|
-
file_id (str): The ID of the file to get.
|
548
|
-
Returns:
|
549
|
-
File: The file that was retrieved.
|
550
|
-
"""
|
385
|
+
"""Get a file from the Bale servers."""
|
551
386
|
data = await make_post(
|
552
387
|
self.requests_base + "/getFile", data={"file_id": file_id}
|
553
388
|
)
|
554
389
|
return File(**pythonize(data["result"]))
|
555
390
|
|
556
391
|
async def answer_callback_query(
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
):
|
562
|
-
"""Answer a callback query.
|
563
|
-
|
564
|
-
Args:
|
565
|
-
callback_query_id (str): The ID of the callback query to answer.
|
566
|
-
text (str, optional): The text to show to the user. Defaults to None.
|
567
|
-
show_alert (bool, optional): Whether to show an alert to the user. Defaults to None.
|
568
|
-
Returns:
|
569
|
-
bool: Whether the callback query was answered successfully.
|
570
|
-
"""
|
392
|
+
self,
|
393
|
+
callback_query_id: str,
|
394
|
+
text: Optional[str] = None,
|
395
|
+
show_alert: Optional[bool] = None,
|
396
|
+
) -> bool:
|
397
|
+
"""Answer a callback query."""
|
571
398
|
data = await make_post(
|
572
399
|
self.requests_base + "/answerCallbackQuery",
|
573
400
|
data={
|
@@ -579,15 +406,7 @@ class Client:
|
|
579
406
|
return data.get("ok", False)
|
580
407
|
|
581
408
|
async def ban_chat_member(self, chat_id: int, user_id: int) -> bool:
|
582
|
-
"""Ban a user from a chat.
|
583
|
-
|
584
|
-
Args:
|
585
|
-
chat_id (int): The ID of the chat to ban the user from.
|
586
|
-
user_id (int): The ID of the user to ban.
|
587
|
-
Returns:
|
588
|
-
bool: Whether the user was banned successfully
|
589
|
-
"""
|
590
|
-
|
409
|
+
"""Ban a user from a chat."""
|
591
410
|
data = await make_post(
|
592
411
|
self.requests_base + "/banChatMember",
|
593
412
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -595,14 +414,7 @@ class Client:
|
|
595
414
|
return data.get("ok", False)
|
596
415
|
|
597
416
|
async def unban_chat_member(self, chat_id: int, user_id: int) -> bool:
|
598
|
-
"""Unban a user from a chat.
|
599
|
-
|
600
|
-
Args:
|
601
|
-
chat_id (int): The ID of the chat to unban the user from.
|
602
|
-
user_id (int): The ID of the user to unban.
|
603
|
-
Returns:
|
604
|
-
bool: Whether the user was unbanned successfully.
|
605
|
-
"""
|
417
|
+
"""Unban a user from a chat."""
|
606
418
|
data = await make_post(
|
607
419
|
self.requests_base + "/unbanChatMember",
|
608
420
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -610,14 +422,7 @@ class Client:
|
|
610
422
|
return data.get("ok", False)
|
611
423
|
|
612
424
|
async def get_chat_member(self, chat_id: int, user_id: int) -> ChatMember:
|
613
|
-
"""Get a chat member.
|
614
|
-
|
615
|
-
Args:
|
616
|
-
chat_id (int): The ID of the chat to get the member from.
|
617
|
-
user_id (int): The ID of the user to get.
|
618
|
-
Returns:
|
619
|
-
ChatMember: The chat member that was retrieved.
|
620
|
-
"""
|
425
|
+
"""Get a chat member."""
|
621
426
|
data = await make_post(
|
622
427
|
self.requests_base + "/getChatMember",
|
623
428
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -627,34 +432,19 @@ class Client:
|
|
627
432
|
)
|
628
433
|
|
629
434
|
async def promote_chat_member(
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
):
|
642
|
-
"""Promote a user in a chat.
|
643
|
-
|
644
|
-
Args:
|
645
|
-
chat_id (int): The ID of the chat to promote the user in.
|
646
|
-
user_id (int): The ID of the user to promote.
|
647
|
-
can_change_info (bool, optional): Whether the user can change the chat info. Defaults to None.
|
648
|
-
can_post_messages (bool, optional): Whether the user can post messages. Defaults to None.
|
649
|
-
can_edit_messages (bool, optional): Whether the user can edit messages. Defaults to None.
|
650
|
-
can_delete_messages (bool, optional): Whether the user can delete messages. Defaults to None.
|
651
|
-
can_invite_users (bool, optional): Whether the user can invite users. Defaults to None.
|
652
|
-
can_restrict_members (bool, optional): Whether the user can restrict members. Defaults to None.
|
653
|
-
can_pin_messages (bool, optional): Whether the user can pin messages. Defaults to None.
|
654
|
-
can_promote_members (bool, optional): Whether the user can promote members. Defaults to None.
|
655
|
-
Returns:
|
656
|
-
bool: Whether the user was promoted successfully.
|
657
|
-
"""
|
435
|
+
self,
|
436
|
+
chat_id: int,
|
437
|
+
user_id: int,
|
438
|
+
can_change_info: Optional[bool] = None,
|
439
|
+
can_post_messages: Optional[bool] = None,
|
440
|
+
can_edit_messages: Optional[bool] = None,
|
441
|
+
can_delete_messages: Optional[bool] = None,
|
442
|
+
can_invite_users: Optional[bool] = None,
|
443
|
+
can_restrict_members: Optional[bool] = None,
|
444
|
+
can_pin_messages: Optional[bool] = None,
|
445
|
+
can_promote_members: Optional[bool] = None,
|
446
|
+
) -> bool:
|
447
|
+
"""Promote a user in a chat."""
|
658
448
|
data = await make_post(
|
659
449
|
self.requests_base + "/promoteChatMember",
|
660
450
|
data={
|
@@ -673,15 +463,7 @@ class Client:
|
|
673
463
|
return data.get("ok", False)
|
674
464
|
|
675
465
|
async def set_chat_photo(self, chat_id: int, photo: InputFile) -> bool:
|
676
|
-
"""Set a new profile photo for the chat.
|
677
|
-
|
678
|
-
Args:
|
679
|
-
chat_id (int): Unique identifier for the target chat
|
680
|
-
photo (InputFile): New chat photo
|
681
|
-
|
682
|
-
Returns:
|
683
|
-
bool: True on success
|
684
|
-
"""
|
466
|
+
"""Set a new profile photo for the chat."""
|
685
467
|
data = await make_post(
|
686
468
|
self.requests_base + "/setChatPhoto",
|
687
469
|
data={"chat_id": chat_id, "photo": photo},
|
@@ -689,29 +471,14 @@ class Client:
|
|
689
471
|
return data.get("ok", False)
|
690
472
|
|
691
473
|
async def leave_chat(self, chat_id: int) -> bool:
|
692
|
-
"""Leave a group, supergroup or channel.
|
693
|
-
|
694
|
-
Args:
|
695
|
-
chat_id (int): Unique identifier for the target chat
|
696
|
-
|
697
|
-
Returns:
|
698
|
-
bool: True on success
|
699
|
-
"""
|
474
|
+
"""Leave a group, supergroup or channel."""
|
700
475
|
data = await make_post(
|
701
476
|
self.requests_base + "/leaveChat", data={"chat_id": chat_id}
|
702
477
|
)
|
703
478
|
return data.get("ok", False)
|
704
|
-
|
479
|
+
|
705
480
|
async def is_joined(self, user_id: int, chat_id: int) -> bool:
|
706
|
-
"""Check if a user is joined to a chat.
|
707
|
-
|
708
|
-
Args:
|
709
|
-
user_id (int): Unique identifier for the target chat
|
710
|
-
chat_id (int): Unique identifier for the target chat
|
711
|
-
|
712
|
-
Returns:
|
713
|
-
bool: True if the user is joined to the chat, False otherwise
|
714
|
-
"""
|
481
|
+
"""Check if a user is joined to a chat."""
|
715
482
|
data = await make_post(
|
716
483
|
self.requests_base + "/getChatMember",
|
717
484
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -719,53 +486,39 @@ class Client:
|
|
719
486
|
return data.get("result", {}).get("status") in ["member", "creator", "administrator"]
|
720
487
|
|
721
488
|
async def get_chat(self, chat_id: int) -> Chat:
|
722
|
-
"""Get up to date information about the chat.
|
723
|
-
|
724
|
-
Args:
|
725
|
-
chat_id (int): Unique identifier for the target chat
|
726
|
-
|
727
|
-
Returns:
|
728
|
-
Chat: Chat object with information about the chat
|
729
|
-
"""
|
489
|
+
"""Get up to date information about the chat."""
|
730
490
|
data = await make_post(
|
731
491
|
self.requests_base + "/getChat", data={"chat_id": chat_id}
|
732
492
|
)
|
733
493
|
return Chat(**pythonize(data["result"]))
|
734
|
-
|
494
|
+
|
735
495
|
@staticmethod
|
736
|
-
async def get_ble_ir_page(username_or_phone_number: str) ->
|
737
|
-
"""Get BleIR user/group information.
|
738
|
-
|
739
|
-
Args:
|
740
|
-
username_or_phone_number (str): Username or phone number
|
741
|
-
|
742
|
-
Returns:
|
743
|
-
Union[dict, PeerData]: User/group information or error dict
|
744
|
-
"""
|
496
|
+
async def get_ble_ir_page(username_or_phone_number: str) -> PeerData:
|
497
|
+
"""Get BleIR user/group information."""
|
745
498
|
url = f"https://ble.ir/{username_or_phone_number}"
|
746
|
-
|
499
|
+
|
747
500
|
async with aiohttp.ClientSession() as session:
|
748
501
|
async with session.get(url) as response:
|
749
502
|
req = await response.text()
|
750
|
-
|
503
|
+
|
751
504
|
if """<p class="__404_title__lxIKL">گفتگوی مورد نظر وجود ندارد.</p>""" in req:
|
752
505
|
return PeerData(
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
506
|
+
is_ok=False,
|
507
|
+
avatar=None,
|
508
|
+
description=None,
|
509
|
+
name=None,
|
510
|
+
is_bot=None,
|
511
|
+
is_verified=None,
|
512
|
+
is_private=None,
|
513
|
+
members=None,
|
514
|
+
last_message=None,
|
515
|
+
user_id=None,
|
516
|
+
username=None,
|
517
|
+
)
|
518
|
+
|
766
519
|
soup = BeautifulSoup(req, "html.parser")
|
767
520
|
json_data = {}
|
768
|
-
|
521
|
+
|
769
522
|
try:
|
770
523
|
json_script = soup.find("script", id="__NEXT_DATA__").text
|
771
524
|
json_data = loads(json_script)
|
@@ -803,8 +556,8 @@ class Client:
|
|
803
556
|
try:
|
804
557
|
last_msg = messages[-1]["message"]
|
805
558
|
last_message = (
|
806
|
-
|
807
|
-
|
559
|
+
last_msg.get("documentMessage", {}).get("caption", {}).get("text")
|
560
|
+
or last_msg.get("textMessage", {}).get("text")
|
808
561
|
)
|
809
562
|
if last_message:
|
810
563
|
last_message = last_message.replace("‌", "")
|
@@ -824,31 +577,16 @@ class Client:
|
|
824
577
|
user_id,
|
825
578
|
username
|
826
579
|
)
|
827
|
-
|
828
|
-
async def get_chat_members_count(self, chat_id: int) -> int:
|
829
|
-
"""Get the number of members in a chat.
|
830
580
|
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
Returns:
|
835
|
-
int: Number of members in the chat
|
836
|
-
"""
|
581
|
+
async def get_chat_members_count(self, chat_id: int) -> int:
|
582
|
+
"""Get the number of members in a chat."""
|
837
583
|
data = await make_post(
|
838
584
|
self.requests_base + "/getChatMembersCount", data={"chat_id": chat_id}
|
839
585
|
)
|
840
586
|
return data.get("result", 0)
|
841
587
|
|
842
588
|
async def pin_chat_message(self, chat_id: int, message_id: int) -> bool:
|
843
|
-
"""Pin a message in a chat.
|
844
|
-
|
845
|
-
Args:
|
846
|
-
chat_id (int): Unique identifier for the target chat
|
847
|
-
message_id (int): Identifier of a message to pin
|
848
|
-
|
849
|
-
Returns:
|
850
|
-
bool: True on success
|
851
|
-
"""
|
589
|
+
"""Pin a message in a chat."""
|
852
590
|
data = await make_post(
|
853
591
|
self.requests_base + "/pinChatMessage",
|
854
592
|
data={"chat_id": chat_id, "message_id": message_id},
|
@@ -856,43 +594,21 @@ class Client:
|
|
856
594
|
return data.get("ok", False)
|
857
595
|
|
858
596
|
async def unpin_chat_message(self, chat_id: int) -> bool:
|
859
|
-
"""Unpin a message in a chat.
|
860
|
-
|
861
|
-
Args:
|
862
|
-
chat_id (int): Unique identifier for the target chat
|
863
|
-
|
864
|
-
Returns:
|
865
|
-
bool: True on success
|
866
|
-
"""
|
597
|
+
"""Unpin a message in a chat."""
|
867
598
|
data = await make_post(
|
868
599
|
self.requests_base + "/unpinChatMessage", data={"chat_id": chat_id}
|
869
600
|
)
|
870
601
|
return data.get("ok", False)
|
871
602
|
|
872
603
|
async def unpin_all_chat_messages(self, chat_id: int) -> bool:
|
873
|
-
"""Unpin all messages in a chat.
|
874
|
-
|
875
|
-
Args:
|
876
|
-
chat_id (int): Unique identifier for the target chat
|
877
|
-
|
878
|
-
Returns:
|
879
|
-
bool: True on success
|
880
|
-
"""
|
604
|
+
"""Unpin all messages in a chat."""
|
881
605
|
data = await make_post(
|
882
606
|
self.requests_base + "/unpinAllChatMessages", data={"chat_id": chat_id}
|
883
607
|
)
|
884
608
|
return data.get("ok", False)
|
885
609
|
|
886
610
|
async def set_chat_title(self, chat_id: int, title: str) -> bool:
|
887
|
-
"""Change the title of a chat.
|
888
|
-
|
889
|
-
Args:
|
890
|
-
chat_id (int): Unique identifier for the target chat
|
891
|
-
title (str): New chat title, 1-255 characters
|
892
|
-
|
893
|
-
Returns:
|
894
|
-
bool: True on success
|
895
|
-
"""
|
611
|
+
"""Change the title of a chat."""
|
896
612
|
data = await make_post(
|
897
613
|
self.requests_base + "/setChatTitle",
|
898
614
|
data={"chat_id": chat_id, "title": title},
|
@@ -900,15 +616,7 @@ class Client:
|
|
900
616
|
return data.get("ok", False)
|
901
617
|
|
902
618
|
async def set_chat_description(self, chat_id: int, description: str) -> bool:
|
903
|
-
"""Change the description of a chat.
|
904
|
-
|
905
|
-
Args:
|
906
|
-
chat_id (int): Unique identifier for the target chat
|
907
|
-
description (str): New chat description, 0-255 characters
|
908
|
-
|
909
|
-
Returns:
|
910
|
-
bool: True on success
|
911
|
-
"""
|
619
|
+
"""Change the description of a chat."""
|
912
620
|
data = await make_post(
|
913
621
|
self.requests_base + "/setChatDescription",
|
914
622
|
data={"chat_id": chat_id, "description": description},
|
@@ -916,38 +624,20 @@ class Client:
|
|
916
624
|
return data.get("ok", False)
|
917
625
|
|
918
626
|
async def delete_chat_photo(self, chat_id: int) -> bool:
|
919
|
-
"""Delete a chat photo.
|
920
|
-
|
921
|
-
Args:
|
922
|
-
chat_id (int): Unique identifier for the target chat
|
923
|
-
|
924
|
-
Returns:
|
925
|
-
bool: True on success
|
926
|
-
"""
|
627
|
+
"""Delete a chat photo."""
|
927
628
|
data = await make_post(
|
928
629
|
self.requests_base + "/deleteChatPhoto", data={"chat_id": chat_id}
|
929
630
|
)
|
930
631
|
return data.get("ok", False)
|
931
632
|
|
932
633
|
async def edit_message(
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
634
|
+
self,
|
635
|
+
chat_id: Union[int, str],
|
636
|
+
message_id: int,
|
637
|
+
text: str,
|
638
|
+
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
938
639
|
) -> Message:
|
939
|
-
"""Edits a message in a specified chat
|
940
|
-
|
941
|
-
Args:
|
942
|
-
chat_id (int OR str): Unique identifier for the target chat
|
943
|
-
message_id (int): Unique indentifier for the message you want to edit
|
944
|
-
text (str): New text of message
|
945
|
-
reply_markup (InlineKeyboardMarkup): Inline markup you can add or change in message
|
946
|
-
|
947
|
-
Returns:
|
948
|
-
Message: The object of edited message
|
949
|
-
"""
|
950
|
-
|
640
|
+
"""Edits a message in a specified chat"""
|
951
641
|
data = await make_post(
|
952
642
|
self.requests_base + "/editMessageText",
|
953
643
|
data={
|
@@ -960,29 +650,14 @@ class Client:
|
|
960
650
|
return Message(**pythonize(data["result"]))
|
961
651
|
|
962
652
|
async def create_chat_invite_link(self, chat_id: int) -> str:
|
963
|
-
"""Create an additional invite link for a chat.
|
964
|
-
|
965
|
-
Args:
|
966
|
-
chat_id (int): Unique identifier for the target chat
|
967
|
-
|
968
|
-
Returns:
|
969
|
-
str: The new invite link
|
970
|
-
"""
|
653
|
+
"""Create an additional invite link for a chat."""
|
971
654
|
data = await make_post(
|
972
655
|
self.requests_base + "/createChatInviteLink", data={"chat_id": chat_id}
|
973
656
|
)
|
974
657
|
return data.get("result", "")
|
975
658
|
|
976
659
|
async def revoke_chat_invite_link(self, chat_id: int, invite_link: str) -> str:
|
977
|
-
"""Revoke an invite link created by the bot.
|
978
|
-
|
979
|
-
Args:
|
980
|
-
chat_id (int): Unique identifier for the target chat
|
981
|
-
invite_link (str): The invite link to revoke
|
982
|
-
|
983
|
-
Returns:
|
984
|
-
str: The revoked invite link
|
985
|
-
"""
|
660
|
+
"""Revoke an invite link created by the bot."""
|
986
661
|
data = await make_post(
|
987
662
|
self.requests_base + "/revokeChatInviteLink",
|
988
663
|
data={"chat_id": chat_id, "invite_link": invite_link},
|
@@ -990,29 +665,14 @@ class Client:
|
|
990
665
|
return data.get("result", "")
|
991
666
|
|
992
667
|
async def export_chat_invite_link(self, chat_id: int) -> str:
|
993
|
-
"""Generate a new primary invite link for a chat.
|
994
|
-
|
995
|
-
Args:
|
996
|
-
chat_id (int): Unique identifier for the target chat
|
997
|
-
|
998
|
-
Returns:
|
999
|
-
str: The new invite link
|
1000
|
-
"""
|
668
|
+
"""Generate a new primary invite link for a chat."""
|
1001
669
|
data = await make_post(
|
1002
670
|
self.requests_base + "/exportChatInviteLink", data={"chat_id": chat_id}
|
1003
671
|
)
|
1004
672
|
return data.get("result", "")
|
1005
673
|
|
1006
674
|
async def send_chat_action(self, chat_id: int, action: ChatAction) -> bool:
|
1007
|
-
"""Tell the user that something is happening on the bot's side.
|
1008
|
-
|
1009
|
-
Args:
|
1010
|
-
chat_id (int): Unique identifier for the target chat
|
1011
|
-
action (ChatAction): Type of action to broadcast
|
1012
|
-
|
1013
|
-
Returns:
|
1014
|
-
bool: True on success
|
1015
|
-
"""
|
675
|
+
"""Tell the user that something is happening on the bot's side."""
|
1016
676
|
data = await make_post(
|
1017
677
|
self.requests_base + "/sendChatAction",
|
1018
678
|
data={"chat_id": str(chat_id), "action": action.value},
|
@@ -1020,264 +680,208 @@ class Client:
|
|
1020
680
|
return data.get("ok", False)
|
1021
681
|
|
1022
682
|
async def wait_for(self, update_type: UpdatesTypes, check=None):
|
1023
|
-
"""Wait until a specified update
|
1024
|
-
|
1025
|
-
Args:
|
1026
|
-
update_type (UpdatesTypes): The type of update you're waiting for it.
|
1027
|
-
check: a condition that will be checked before passing.
|
1028
|
-
"""
|
683
|
+
"""Wait until a specified update"""
|
1029
684
|
future = asyncio.get_running_loop().create_future()
|
1030
685
|
self._waiters.append((update_type, check, future))
|
1031
686
|
return await future
|
1032
687
|
|
1033
688
|
async def process_update(self, update: Dict[str, Any]) -> None:
|
1034
|
-
"""Process a single update and call registered handlers.
|
689
|
+
"""Process a single update and call registered handlers."""
|
690
|
+
# print(f"Processing update: {update}")
|
1035
691
|
|
1036
|
-
Args:
|
1037
|
-
update (Dict[str, Any]): The update to process
|
1038
|
-
"""
|
1039
692
|
update_id = update.get("update_id")
|
1040
693
|
if update_id:
|
1041
694
|
self.last_update_id = update_id + 1
|
1042
|
-
|
1043
695
|
if self.check_defined_message:
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
696
|
+
try:
|
697
|
+
update_raw = update.get('message', {})
|
698
|
+
if update_raw.get("text") in self.defined_messages:
|
699
|
+
await self.send_message(
|
700
|
+
update_raw.get('chat', {}).get('id'),
|
701
|
+
self.defined_messages.get(update_raw.get("text")),
|
702
|
+
update_raw.get('message_id')
|
703
|
+
)
|
704
|
+
except Exception as e:
|
705
|
+
print(f"Error processing defined message: {e}")
|
1048
706
|
for waiter in list(self._waiters):
|
1049
707
|
w_type, check, future = waiter
|
1050
708
|
if w_type.value in update:
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
if
|
1055
|
-
future.
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
709
|
+
event_data = update[w_type.value]
|
710
|
+
try:
|
711
|
+
event = self._convert_event(w_type, event_data)
|
712
|
+
if check is None or check(event):
|
713
|
+
if not future.done():
|
714
|
+
future.set_result(event)
|
715
|
+
self._waiters.remove(waiter)
|
716
|
+
return
|
717
|
+
except Exception as e:
|
718
|
+
print(f"Error in waiter conversion: {e}")
|
719
|
+
continue
|
1059
720
|
for handler in self.handlers:
|
1060
|
-
|
1061
|
-
|
1062
|
-
raw_event = update[update_type]
|
721
|
+
handler_type = handler["type"]
|
722
|
+
update_type_key = handler_type.value
|
1063
723
|
|
724
|
+
if update_type_key not in update:
|
725
|
+
continue
|
1064
726
|
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
727
|
+
raw_event = update[update_type_key]
|
728
|
+
|
729
|
+
try:
|
730
|
+
event = self._convert_event(handler_type, raw_event)
|
731
|
+
except Exception as e:
|
732
|
+
print(f"Error converting event for handler {handler_type}: {e}")
|
733
|
+
continue
|
734
|
+
if handler_type == UpdatesTypes.COMMAND:
|
735
|
+
if not hasattr(event, 'text') or not event.text or not event.text.startswith('/'):
|
736
|
+
continue
|
737
|
+
|
738
|
+
command_text = event.text[1:].split('@')[0]
|
739
|
+
command_parts = command_text.split()
|
740
|
+
if not command_parts:
|
741
|
+
continue
|
742
|
+
|
743
|
+
actual_command = command_parts[0]
|
744
|
+
expected_command = handler.get("command", "")
|
745
|
+
|
746
|
+
if actual_command != expected_command:
|
747
|
+
continue
|
748
|
+
flt = handler.get("filter")
|
749
|
+
if flt is not None:
|
750
|
+
if callable(flt):
|
751
|
+
try:
|
752
|
+
if not flt(event):
|
1089
753
|
continue
|
1090
|
-
|
754
|
+
except Exception as e:
|
755
|
+
print(f"[Filter Error] {e}")
|
756
|
+
continue
|
757
|
+
elif isinstance(flt, Filters):
|
758
|
+
if not hasattr(event, flt.value):
|
759
|
+
continue
|
760
|
+
try:
|
1091
761
|
if asyncio.iscoroutinefunction(handler["callback"]):
|
1092
762
|
asyncio.create_task(handler["callback"](event))
|
1093
763
|
else:
|
1094
764
|
handler["callback"](event)
|
765
|
+
except Exception as e:
|
766
|
+
print(f"Error executing handler: {e}")
|
767
|
+
|
768
|
+
def _convert_event(self, handler_type: UpdatesTypes, event_data: Dict[str, Any]) -> Any:
|
769
|
+
"""Convert raw event data to appropriate object type."""
|
770
|
+
kwargs = {"client": self}
|
1095
771
|
|
772
|
+
try:
|
773
|
+
if handler_type == UpdatesTypes.MESSAGE:
|
774
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
1096
775
|
|
776
|
+
elif handler_type == UpdatesTypes.MESSAGE_EDITED:
|
777
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
1097
778
|
|
1098
|
-
|
1099
|
-
|
779
|
+
elif handler_type == UpdatesTypes.CALLBACK_QUERY:
|
780
|
+
return CallbackQuery(kwargs=kwargs, **pythonize(event_data))
|
781
|
+
|
782
|
+
elif handler_type == UpdatesTypes.PRE_CHECKOUT_QUERY:
|
783
|
+
return PreCheckoutQuery(kwargs=kwargs, **pythonize(event_data))
|
784
|
+
|
785
|
+
elif handler_type == UpdatesTypes.MEMBER_JOINED:
|
786
|
+
if "new_chat_member" in event_data:
|
787
|
+
return (
|
788
|
+
ChatMember(kwargs=kwargs, **pythonize(event_data["new_chat_member"])),
|
789
|
+
Chat(kwargs=kwargs, **pythonize(event_data.get("chat", {}))),
|
790
|
+
Message(kwargs=kwargs, **pythonize(event_data))
|
791
|
+
)
|
792
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
793
|
+
|
794
|
+
elif handler_type == UpdatesTypes.MEMBER_LEFT:
|
795
|
+
if "left_chat_member" in event_data:
|
796
|
+
return (
|
797
|
+
ChatMember(kwargs=kwargs, **pythonize(event_data["left_chat_member"])),
|
798
|
+
Chat(kwargs=kwargs, **pythonize(event_data.get("chat", {}))),
|
799
|
+
Message(kwargs=kwargs, **pythonize(event_data))
|
800
|
+
)
|
801
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
802
|
+
|
803
|
+
elif handler_type == UpdatesTypes.SUCCESSFUL_PAYMENT:
|
804
|
+
if "successful_payment" in event_data:
|
805
|
+
return SuccessfulPayment(kwargs=kwargs, **pythonize(event_data["successful_payment"]))
|
806
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
807
|
+
|
808
|
+
elif handler_type == UpdatesTypes.COMMAND:
|
809
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
810
|
+
|
811
|
+
elif handler_type == UpdatesTypes.PHOTO:
|
812
|
+
return Message(kwargs=kwargs, **pythonize(event_data))
|
813
|
+
|
814
|
+
else: return event_data
|
1100
815
|
|
1101
|
-
|
1102
|
-
|
816
|
+
except Exception as e:
|
817
|
+
print(f"Error converting event {handler_type}: {e}")
|
818
|
+
return event_data
|
819
|
+
|
820
|
+
def base_handler_decorator(self, update_type: UpdatesTypes):
|
821
|
+
"""Base decorator for handling different types of updates."""
|
1103
822
|
|
1104
|
-
Returns:
|
1105
|
-
Callable: A decorator function that registers the callback for the specified update type.
|
1106
|
-
"""
|
1107
823
|
def wrapper(filter: Optional[Filters] = None):
|
1108
824
|
def decorator(callback: Callable[[Any], Union[None, Awaitable[None]]]):
|
1109
825
|
self.add_handler(update_type, callback, filter)
|
1110
826
|
return callback
|
827
|
+
|
1111
828
|
return decorator
|
829
|
+
|
1112
830
|
return wrapper
|
1113
|
-
|
831
|
+
|
1114
832
|
def on_command(self, command: str, filter: Optional[Filters] = None):
|
1115
|
-
"""Decorator for handling command updates.
|
1116
|
-
|
1117
|
-
Args:
|
1118
|
-
command (str): The command to handle.
|
1119
|
-
filter (Optional[Filters]): An optional filter to apply to the command.
|
1120
|
-
Returns:
|
1121
|
-
Callable: A decorator function that registers the callback for the specified command.
|
1122
|
-
"""
|
833
|
+
"""Decorator for handling command updates."""
|
834
|
+
|
1123
835
|
def decorator(callback: Callable[[Any], Union[None, Awaitable[None]]]):
|
1124
836
|
self.add_handler(UpdatesTypes.COMMAND, callback, filter, command=command)
|
1125
837
|
return callback
|
1126
|
-
return decorator
|
1127
838
|
|
839
|
+
return decorator
|
1128
840
|
|
1129
841
|
def on_message(self, filter: Optional[Filters] = None):
|
1130
|
-
"""Decorator for handling new message updates.
|
1131
|
-
|
1132
|
-
Returns:
|
1133
|
-
Callable: A decorator function that registers the callback for message updates.
|
1134
|
-
"""
|
842
|
+
"""Decorator for handling new message updates."""
|
1135
843
|
return self.base_handler_decorator(UpdatesTypes.MESSAGE)(filter)
|
1136
844
|
|
845
|
+
def on_edited_message(self, filter: Optional[Filters] = None):
|
846
|
+
"""Decorator for handling edited message updates."""
|
847
|
+
return self.base_handler_decorator(UpdatesTypes.MESSAGE_EDITED)(filter)
|
1137
848
|
|
1138
|
-
def
|
1139
|
-
"""Decorator for handling
|
1140
|
-
|
1141
|
-
Returns:
|
1142
|
-
Callable: A decorator function that registers the callback for edited message updates.
|
1143
|
-
"""
|
1144
|
-
return self.base_handler_decorator(UpdatesTypes.MESSAGE_EDITED)
|
1145
|
-
|
1146
|
-
def on_callback_query(self):
|
1147
|
-
"""Decorator for handling callback query updates.
|
1148
|
-
|
1149
|
-
Returns:
|
1150
|
-
Callable: A decorator function that registers the callback for callback query updates.
|
1151
|
-
"""
|
1152
|
-
return self.base_handler_decorator(UpdatesTypes.CALLBACK_QUERY)
|
1153
|
-
|
1154
|
-
def on_new_members(self):
|
1155
|
-
"""Decorator for handling new chat members updates.
|
1156
|
-
|
1157
|
-
Returns:
|
1158
|
-
Callable: A decorator function that registers the callback for new members updates.
|
1159
|
-
"""
|
1160
|
-
return self.base_handler_decorator(UpdatesTypes.MEMBER_JOINED)
|
1161
|
-
|
1162
|
-
def on_members_left(self):
|
1163
|
-
return self.base_handler_decorator(UpdatesTypes.MEMBER_LEFT)
|
1164
|
-
|
1165
|
-
def on_pre_checkout_query(self):
|
1166
|
-
"""Decorator for handling pre-checkout query updates.
|
1167
|
-
|
1168
|
-
Returns:
|
1169
|
-
Callable: A decorator function that registers the callback for pre-checkout query updates.
|
1170
|
-
"""
|
1171
|
-
return self.base_handler_decorator(UpdatesTypes.PRE_CHECKOUT_QUERY)
|
1172
|
-
|
1173
|
-
def on_photo(self):
|
1174
|
-
"""Decorator for handling photo updates.
|
1175
|
-
|
1176
|
-
Returns:
|
1177
|
-
Callable: A decorator function that registers the callback for photo updates.
|
1178
|
-
"""
|
1179
|
-
return self.base_handler_decorator(UpdatesTypes.PHOTO)
|
1180
|
-
|
1181
|
-
def on_successful_payment(self):
|
1182
|
-
"""Decorator for handling successful payment updates.
|
1183
|
-
|
1184
|
-
Returns:
|
1185
|
-
Callable: A decorator function that registers the callback for successful payment updates.
|
1186
|
-
"""
|
1187
|
-
return self.base_handler_decorator(UpdatesTypes.SUCCESSFUL_PAYMENT)
|
1188
|
-
|
1189
|
-
def _convert_event(self, handler_type: UpdatesTypes, event: Dict[str, Any]) -> Any:
|
1190
|
-
"""Convert raw event data to appropriate object type.
|
1191
|
-
|
1192
|
-
Args:
|
1193
|
-
handler_type (UpdatesTypes): Type of the update
|
1194
|
-
event (Dict[str, Any]): Raw event data
|
1195
|
-
|
1196
|
-
Returns:
|
1197
|
-
Any: Converted event object
|
1198
|
-
"""
|
1199
|
-
if handler_type in (
|
1200
|
-
UpdatesTypes.MESSAGE,
|
1201
|
-
UpdatesTypes.MESSAGE_EDITED,
|
1202
|
-
UpdatesTypes.MEMBER_JOINED,
|
1203
|
-
UpdatesTypes.MEMBER_LEFT,
|
1204
|
-
UpdatesTypes.SUCCESSFUL_PAYMENT,
|
1205
|
-
UpdatesTypes.COMMAND
|
1206
|
-
):
|
1207
|
-
if (
|
1208
|
-
event.get("new_chat_member", False)
|
1209
|
-
and handler_type == UpdatesTypes.MEMBER_JOINED
|
1210
|
-
):
|
1211
|
-
return (
|
1212
|
-
ChatMember(
|
1213
|
-
kwargs={"client": self},
|
1214
|
-
**pythonize(event.get("new_chat_member", {})),
|
1215
|
-
),
|
1216
|
-
Chat(kwargs={"client": self}, **pythonize(event.get("chat", {}))),
|
1217
|
-
Message(
|
1218
|
-
kwargs={"client": self}, **pythonize(event.get("message", {}))
|
1219
|
-
),
|
1220
|
-
)
|
1221
|
-
elif (
|
1222
|
-
event.get("left_chat_member", False)
|
1223
|
-
and handler_type == UpdatesTypes.MEMBER_LEFT
|
1224
|
-
):
|
1225
|
-
return (
|
1226
|
-
ChatMember(
|
1227
|
-
kwargs={"client": self},
|
1228
|
-
**pythonize(event.get("left_chat_member", {})),
|
1229
|
-
),
|
1230
|
-
Chat(kwargs={"client": self}, **pythonize(event.get("chat", {}))),
|
1231
|
-
Message(
|
1232
|
-
kwargs={"client": self}, **pythonize(event.get("message", {}))
|
1233
|
-
),
|
1234
|
-
)
|
849
|
+
def on_callback_query(self, filter: Optional[Filters] = None):
|
850
|
+
"""Decorator for handling callback query updates."""
|
851
|
+
return self.base_handler_decorator(UpdatesTypes.CALLBACK_QUERY)(filter)
|
1235
852
|
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
):
|
1240
|
-
return Message(
|
1241
|
-
**pythonize(event.get("successful_payment", {})),
|
1242
|
-
kwargs={"client": self},
|
1243
|
-
)
|
853
|
+
def on_new_members(self, filter: Optional[Filters] = None):
|
854
|
+
"""Decorator for handling new chat members updates."""
|
855
|
+
return self.base_handler_decorator(UpdatesTypes.MEMBER_JOINED)(filter)
|
1244
856
|
|
1245
|
-
|
1246
|
-
|
857
|
+
def on_members_left(self, filter: Optional[Filters] = None):
|
858
|
+
"""Decorator for handling members left updates."""
|
859
|
+
return self.base_handler_decorator(UpdatesTypes.MEMBER_LEFT)(filter)
|
1247
860
|
|
1248
|
-
|
1249
|
-
|
861
|
+
def on_pre_checkout_query(self, filter: Optional[Filters] = None):
|
862
|
+
"""Decorator for handling pre-checkout query updates."""
|
863
|
+
return self.base_handler_decorator(UpdatesTypes.PRE_CHECKOUT_QUERY)(filter)
|
1250
864
|
|
1251
|
-
|
1252
|
-
|
865
|
+
def on_photo(self, filter: Optional[Filters] = None):
|
866
|
+
"""Decorator for handling photo updates."""
|
867
|
+
return self.base_handler_decorator(UpdatesTypes.PHOTO)(filter)
|
1253
868
|
|
1254
|
-
|
869
|
+
def on_successful_payment(self, filter: Optional[Filters] = None):
|
870
|
+
"""Decorator for handling successful payment updates."""
|
871
|
+
return self.base_handler_decorator(UpdatesTypes.SUCCESSFUL_PAYMENT)(filter)
|
1255
872
|
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
Args:
|
1261
|
-
update_type (UpdatesTypes): Type of update to handle
|
1262
|
-
callback (Callable): Function to call when update is received
|
1263
|
-
"""
|
1264
|
-
data = {
|
873
|
+
def add_handler(self, update_type: UpdatesTypes, callback: Callable, filter: Optional[Filters] = None, **kwargs):
|
874
|
+
"""Register a handler for specific update type."""
|
875
|
+
handler_data = {
|
1265
876
|
"type": update_type,
|
1266
877
|
"callback": callback,
|
1267
878
|
"filter": filter,
|
1268
879
|
}
|
1269
|
-
|
1270
|
-
self.handlers.append(
|
1271
|
-
|
880
|
+
handler_data.update(kwargs)
|
881
|
+
self.handlers.append(handler_data)
|
1272
882
|
|
1273
|
-
def remove_handler(
|
1274
|
-
|
1275
|
-
) -> None:
|
1276
|
-
"""Remove a handler from the list of handlers.
|
1277
|
-
|
1278
|
-
Args:
|
1279
|
-
callback (Callable): Handler function to remove
|
1280
|
-
"""
|
883
|
+
def remove_handler(self, callback: Callable) -> None:
|
884
|
+
"""Remove a handler from the list of handlers."""
|
1281
885
|
self.handlers = [
|
1282
886
|
handler for handler in self.handlers if handler["callback"] != callback
|
1283
887
|
]
|
@@ -1287,15 +891,7 @@ class Client:
|
|
1287
891
|
self.handlers = []
|
1288
892
|
|
1289
893
|
async def start_polling(self, timeout: int = 30, limit: int = 100) -> None:
|
1290
|
-
"""Start polling updates from the server.
|
1291
|
-
|
1292
|
-
Args:
|
1293
|
-
timeout (int, optional): Timeout in seconds for long polling. Defaults to 30.
|
1294
|
-
limit (int, optional): Maximum number of updates to retrieve. Defaults to 100.
|
1295
|
-
|
1296
|
-
Raises:
|
1297
|
-
RuntimeError: If client is already running
|
1298
|
-
"""
|
894
|
+
"""Start polling updates from the server."""
|
1299
895
|
if self.running:
|
1300
896
|
raise RuntimeError("Client is already running")
|
1301
897
|
|
@@ -1308,33 +904,26 @@ class Client:
|
|
1308
904
|
|
1309
905
|
for update in updates:
|
1310
906
|
await self.process_update(update)
|
1311
|
-
|
1312
|
-
except Exception as e:
|
1313
|
-
raise e
|
1314
907
|
|
908
|
+
except Exception as e:
|
909
|
+
print(f"Error in polling: {e}")
|
910
|
+
await asyncio.sleep(1)
|
911
|
+
|
1315
912
|
async def stop_polling(self) -> None:
|
1316
913
|
"""Stop polling updates."""
|
1317
914
|
self.running = False
|
1318
915
|
|
1319
916
|
def run(self, timeout: int = 30, limit: int = 100) -> None:
|
1320
|
-
"""Run the client.
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
"""
|
1326
|
-
loop = asyncio.get_event_loop()
|
1327
|
-
loop.run_until_complete(self.start_polling(timeout, limit))
|
917
|
+
"""Run the client."""
|
918
|
+
try:
|
919
|
+
asyncio.run(self.start_polling(timeout, limit))
|
920
|
+
except KeyboardInterrupt:
|
921
|
+
print("Bot stopped by user")
|
1328
922
|
|
1329
|
-
def stop(self) -> None:
|
923
|
+
async def stop(self) -> None:
|
1330
924
|
"""Stop the client."""
|
1331
|
-
|
1332
|
-
loop.run_until_complete(self.stop_polling())
|
925
|
+
await self.stop_polling()
|
1333
926
|
|
1334
927
|
async def handle_webhook_update(self, update_data: Dict[str, Any]) -> None:
|
1335
|
-
"""Process an update received via webhook.
|
1336
|
-
|
1337
|
-
Args:
|
1338
|
-
update_data (Dict[str, Any]): Update data received from webhook
|
1339
|
-
"""
|
1340
|
-
await self.process_update(update_data)
|
928
|
+
"""Process an update received via webhook."""
|
929
|
+
await self.process_update(update_data)
|