Rubka 6.4.4__tar.gz → 6.4.8__tar.gz
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.
- {rubka-6.4.4 → rubka-6.4.8}/PKG-INFO +1 -1
- {rubka-6.4.4 → rubka-6.4.8}/Rubka.egg-info/PKG-INFO +1 -1
- {rubka-6.4.4 → rubka-6.4.8}/rubka/api.py +182 -12
- {rubka-6.4.4 → rubka-6.4.8}/rubka/asynco.py +218 -38
- {rubka-6.4.4 → rubka-6.4.8}/rubka/context.py +16 -2
- {rubka-6.4.4 → rubka-6.4.8}/rubka/update.py +16 -2
- {rubka-6.4.4 → rubka-6.4.8}/setup.py +1 -1
- {rubka-6.4.4 → rubka-6.4.8}/README.md +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/Rubka.egg-info/SOURCES.txt +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/Rubka.egg-info/dependency_links.txt +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/Rubka.egg-info/requires.txt +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/Rubka.egg-info/top_level.txt +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/client/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/client/client.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/crypto/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/crypto/crypto.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/enums.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/exceptions.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/methods/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/methods/methods.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/network/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/network/helper.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/network/network.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/network/socket.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/sessions/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/sessions/sessions.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/types/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/types/socket/message.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/utils/__init__.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/utils/configs.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/adaptorrubka/utils/utils.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/button.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/config.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/decorators.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/exceptions.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/jobs.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/keyboards.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/keypad.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/logger.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/rubino.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/rubka/utils.py +0 -0
- {rubka-6.4.4 → rubka-6.4.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Rubka
|
|
3
|
-
Version: 6.4.
|
|
3
|
+
Version: 6.4.8
|
|
4
4
|
Summary: A Python library for interacting with Rubika Bot API.
|
|
5
5
|
Home-page: https://github.com/Mahdy-Ahmadi/Rubka
|
|
6
6
|
Download-URL: https://github.com/Mahdy-Ahmadi/rubka/blob/main/project_library.zip
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Rubka
|
|
3
|
-
Version: 6.4.
|
|
3
|
+
Version: 6.4.8
|
|
4
4
|
Summary: A Python library for interacting with Rubika Bot API.
|
|
5
5
|
Home-page: https://github.com/Mahdy-Ahmadi/Rubka
|
|
6
6
|
Download-URL: https://github.com/Mahdy-Ahmadi/rubka/blob/main/project_library.zip
|
|
@@ -498,6 +498,168 @@ class Robot:
|
|
|
498
498
|
})
|
|
499
499
|
return func
|
|
500
500
|
return decorator
|
|
501
|
+
def on_message_file(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
502
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
503
|
+
def wrapper(bot, message: Message):
|
|
504
|
+
if not message.file:
|
|
505
|
+
return
|
|
506
|
+
if filters and not filters(message):
|
|
507
|
+
return
|
|
508
|
+
return func(bot, message)
|
|
509
|
+
|
|
510
|
+
self._message_handlers.append({
|
|
511
|
+
"func": wrapper,
|
|
512
|
+
"filters": filters,
|
|
513
|
+
"file_only": True,
|
|
514
|
+
"commands":commands
|
|
515
|
+
})
|
|
516
|
+
return wrapper
|
|
517
|
+
return decorator
|
|
518
|
+
|
|
519
|
+
def on_message_forwarded(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
520
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
521
|
+
def wrapper(bot, message: Message):
|
|
522
|
+
if not message.is_forwarded:
|
|
523
|
+
return
|
|
524
|
+
if filters and not filters(message):
|
|
525
|
+
return
|
|
526
|
+
return func(bot, message)
|
|
527
|
+
|
|
528
|
+
self._message_handlers.append({
|
|
529
|
+
"func": wrapper,
|
|
530
|
+
"filters": filters,
|
|
531
|
+
"forwarded_only": True,
|
|
532
|
+
"commands":commands
|
|
533
|
+
})
|
|
534
|
+
return wrapper
|
|
535
|
+
return decorator
|
|
536
|
+
|
|
537
|
+
def on_message_reply(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
538
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
539
|
+
def wrapper(bot, message: Message):
|
|
540
|
+
if not message.is_reply:
|
|
541
|
+
return
|
|
542
|
+
if filters and not filters(message):
|
|
543
|
+
return
|
|
544
|
+
return func(bot, message)
|
|
545
|
+
|
|
546
|
+
self._message_handlers.append({
|
|
547
|
+
"func": wrapper,
|
|
548
|
+
"filters": filters,
|
|
549
|
+
"reply_only": True,
|
|
550
|
+
"commands":commands
|
|
551
|
+
})
|
|
552
|
+
return wrapper
|
|
553
|
+
return decorator
|
|
554
|
+
|
|
555
|
+
def on_message_text(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
556
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
557
|
+
def wrapper(bot, message: Message):
|
|
558
|
+
if not message.text:
|
|
559
|
+
return
|
|
560
|
+
if filters and not filters(message):
|
|
561
|
+
return
|
|
562
|
+
return func(bot, message)
|
|
563
|
+
|
|
564
|
+
self._message_handlers.append({
|
|
565
|
+
"func": wrapper,
|
|
566
|
+
"filters": filters,
|
|
567
|
+
"text_only": True,
|
|
568
|
+
"commands":commands
|
|
569
|
+
})
|
|
570
|
+
return wrapper
|
|
571
|
+
return decorator
|
|
572
|
+
|
|
573
|
+
def on_message_media(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
574
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
575
|
+
def wrapper(bot, message: Message):
|
|
576
|
+
if not message.is_media:
|
|
577
|
+
return
|
|
578
|
+
if filters and not filters(message):
|
|
579
|
+
return
|
|
580
|
+
return func(bot, message)
|
|
581
|
+
|
|
582
|
+
self._message_handlers.append({
|
|
583
|
+
"func": wrapper,
|
|
584
|
+
"filters": filters,
|
|
585
|
+
"media_only": True,
|
|
586
|
+
"commands":commands
|
|
587
|
+
})
|
|
588
|
+
return wrapper
|
|
589
|
+
return decorator
|
|
590
|
+
|
|
591
|
+
def on_message_sticker(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
592
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
593
|
+
def wrapper(bot, message: Message):
|
|
594
|
+
if not message.sticker:
|
|
595
|
+
return
|
|
596
|
+
if filters and not filters(message):
|
|
597
|
+
return
|
|
598
|
+
return func(bot, message)
|
|
599
|
+
|
|
600
|
+
self._message_handlers.append({
|
|
601
|
+
"func": wrapper,
|
|
602
|
+
"filters": filters,
|
|
603
|
+
"sticker_only": True,
|
|
604
|
+
"commands":commands
|
|
605
|
+
})
|
|
606
|
+
return wrapper
|
|
607
|
+
return decorator
|
|
608
|
+
|
|
609
|
+
def on_message_contact(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
610
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
611
|
+
def wrapper(bot, message: Message):
|
|
612
|
+
if not message.is_contact:
|
|
613
|
+
return
|
|
614
|
+
if filters and not filters(message):
|
|
615
|
+
return
|
|
616
|
+
return func(bot, message)
|
|
617
|
+
|
|
618
|
+
self._message_handlers.append({
|
|
619
|
+
"func": wrapper,
|
|
620
|
+
"filters": filters,
|
|
621
|
+
"contact_only": True,
|
|
622
|
+
"commands":commands
|
|
623
|
+
})
|
|
624
|
+
return wrapper
|
|
625
|
+
return decorator
|
|
626
|
+
|
|
627
|
+
def on_message_location(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
628
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
629
|
+
def wrapper(bot, message: Message):
|
|
630
|
+
if not message.is_location:
|
|
631
|
+
return
|
|
632
|
+
if filters and not filters(message):
|
|
633
|
+
return
|
|
634
|
+
return func(bot, message)
|
|
635
|
+
|
|
636
|
+
self._message_handlers.append({
|
|
637
|
+
"func": wrapper,
|
|
638
|
+
"filters": filters,
|
|
639
|
+
"location_only": True,
|
|
640
|
+
"commands":commands
|
|
641
|
+
})
|
|
642
|
+
return wrapper
|
|
643
|
+
return decorator
|
|
644
|
+
|
|
645
|
+
def on_message_poll(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
646
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
647
|
+
def wrapper(bot, message: Message):
|
|
648
|
+
if not message.is_poll:
|
|
649
|
+
return
|
|
650
|
+
if filters and not filters(message):
|
|
651
|
+
return
|
|
652
|
+
return func(bot, message)
|
|
653
|
+
|
|
654
|
+
self._message_handlers.append({
|
|
655
|
+
"func": wrapper,
|
|
656
|
+
"filters": filters,
|
|
657
|
+
"poll_only": True,
|
|
658
|
+
"commands":commands
|
|
659
|
+
})
|
|
660
|
+
return wrapper
|
|
661
|
+
return decorator
|
|
662
|
+
|
|
501
663
|
def message_handler(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
502
664
|
def decorator(func: Callable[[Any, Message], None]):
|
|
503
665
|
self._message_handlers.append({
|
|
@@ -1191,17 +1353,7 @@ class Robot:
|
|
|
1191
1353
|
raise ValueError(f"Invalid media type. Must be one of {allowed}")
|
|
1192
1354
|
result = self._post("requestSendFile", {"type": media_type})
|
|
1193
1355
|
return result.get("data", {}).get("upload_url")
|
|
1194
|
-
def _send_uploaded_file(
|
|
1195
|
-
self,
|
|
1196
|
-
chat_id: str,
|
|
1197
|
-
file_id: str,
|
|
1198
|
-
text: Optional[str] = None,
|
|
1199
|
-
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
1200
|
-
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
1201
|
-
disable_notification: bool = False,
|
|
1202
|
-
reply_to_message_id: Optional[str] = None,
|
|
1203
|
-
chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
|
|
1204
|
-
) -> Dict[str, Any]:
|
|
1356
|
+
def _send_uploaded_file(self, chat_id: str, file_id: str,type_file : str = "file",text: Optional[str] = None, chat_keypad: Optional[Dict[str, Any]] = None, inline_keypad: Optional[Dict[str, Any]] = None, disable_notification: bool = False, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1205
1357
|
payload = {
|
|
1206
1358
|
"chat_id": chat_id,
|
|
1207
1359
|
"file_id": file_id,
|
|
@@ -1216,7 +1368,25 @@ class Robot:
|
|
|
1216
1368
|
if reply_to_message_id:
|
|
1217
1369
|
payload["reply_to_message_id"] = str(reply_to_message_id)
|
|
1218
1370
|
|
|
1219
|
-
|
|
1371
|
+
resp = self._post("sendFile", payload)
|
|
1372
|
+
message_id_put = resp["data"]["message_id"]
|
|
1373
|
+
result = {
|
|
1374
|
+
"status": resp.get("status"),
|
|
1375
|
+
"status_det": resp.get("status_det"),
|
|
1376
|
+
"file_id": file_id,
|
|
1377
|
+
"text":text,
|
|
1378
|
+
"message_id": message_id_put,
|
|
1379
|
+
"send_to_chat_id": chat_id,
|
|
1380
|
+
"reply_to_message_id": reply_to_message_id,
|
|
1381
|
+
"disable_notification": disable_notification,
|
|
1382
|
+
"type_file": type_file,
|
|
1383
|
+
"raw_response": resp,
|
|
1384
|
+
"chat_keypad":chat_keypad,
|
|
1385
|
+
"inline_keypad":inline_keypad,
|
|
1386
|
+
"chat_keypad_type":chat_keypad_type
|
|
1387
|
+
}
|
|
1388
|
+
import json
|
|
1389
|
+
return json.dumps(result, ensure_ascii=False, indent=4)
|
|
1220
1390
|
def send_file(
|
|
1221
1391
|
self,
|
|
1222
1392
|
chat_id: str,
|
|
@@ -9,6 +9,8 @@ try:
|
|
|
9
9
|
from .context import Message, InlineMessage
|
|
10
10
|
except (ImportError, ModuleNotFoundError):
|
|
11
11
|
from context import Message, InlineMessage
|
|
12
|
+
class FeatureNotAvailableError(Exception):
|
|
13
|
+
pass
|
|
12
14
|
|
|
13
15
|
from tqdm.asyncio import tqdm
|
|
14
16
|
from urllib.parse import urlparse, parse_qs
|
|
@@ -16,7 +18,7 @@ class InvalidTokenError(Exception):pass
|
|
|
16
18
|
import mimetypes
|
|
17
19
|
from pathlib import Path
|
|
18
20
|
import time
|
|
19
|
-
import datetime
|
|
21
|
+
import datetime,json
|
|
20
22
|
import tempfile
|
|
21
23
|
from tqdm import tqdm
|
|
22
24
|
import os
|
|
@@ -32,7 +34,31 @@ def install_package(package_name: str) -> bool:
|
|
|
32
34
|
return True
|
|
33
35
|
except Exception:
|
|
34
36
|
return False
|
|
35
|
-
|
|
37
|
+
class MessageResponse:
|
|
38
|
+
def __init__(self, resp: dict, chat_id: str, file_id: str,
|
|
39
|
+
type_file: str, reply_to_message_id: str,
|
|
40
|
+
disable_notification: bool, text: str = None,
|
|
41
|
+
chat_keypad=None, inline_keypad=None, chat_keypad_type="None"):
|
|
42
|
+
|
|
43
|
+
self.status = resp.get("status")
|
|
44
|
+
self.status_det = resp.get("status_det")
|
|
45
|
+
self.file_id = file_id
|
|
46
|
+
self.message_id = resp["data"].get("message_id")
|
|
47
|
+
self.send_to_chat_id = chat_id
|
|
48
|
+
self.reply_to_message_id = reply_to_message_id
|
|
49
|
+
self.disable_notification = disable_notification
|
|
50
|
+
self.type_file = type_file
|
|
51
|
+
self.text = text
|
|
52
|
+
self.chat_keypad = chat_keypad
|
|
53
|
+
self.inline_keypad = inline_keypad
|
|
54
|
+
self.chat_keypad_type = chat_keypad_type
|
|
55
|
+
self.raw_response = resp
|
|
56
|
+
|
|
57
|
+
def to_dict(self):
|
|
58
|
+
return self.__dict__
|
|
59
|
+
|
|
60
|
+
def to_json(self):
|
|
61
|
+
return json.dumps(self.__dict__, ensure_ascii=False, indent=4)
|
|
36
62
|
def get_importlib_metadata():
|
|
37
63
|
"""Dynamically imports and returns metadata functions from importlib."""
|
|
38
64
|
try:
|
|
@@ -192,6 +218,9 @@ class Robot:
|
|
|
192
218
|
raise InvalidTokenError("The provided bot token is invalid or expired.")
|
|
193
219
|
from typing import Callable, Any, Optional, List
|
|
194
220
|
|
|
221
|
+
|
|
222
|
+
#decorator#
|
|
223
|
+
|
|
195
224
|
def on_message_private(
|
|
196
225
|
self,
|
|
197
226
|
chat_id: Optional[Union[str, List[str]]] = None,
|
|
@@ -221,30 +250,20 @@ class Robot:
|
|
|
221
250
|
|
|
222
251
|
if not message.is_private:
|
|
223
252
|
return
|
|
224
|
-
|
|
225
|
-
|
|
226
253
|
if chat_id:
|
|
227
254
|
if isinstance(chat_id, str) and message.chat_id != chat_id:
|
|
228
255
|
return
|
|
229
256
|
if isinstance(chat_id, list) and message.chat_id not in chat_id:
|
|
230
257
|
return
|
|
231
|
-
|
|
232
|
-
|
|
233
258
|
if sender_id:
|
|
234
259
|
if isinstance(sender_id, str) and message.sender_id != sender_id:
|
|
235
260
|
return
|
|
236
261
|
if isinstance(sender_id, list) and message.sender_id not in sender_id:
|
|
237
262
|
return
|
|
238
|
-
|
|
239
|
-
|
|
240
263
|
if sender_type and message.sender_type != sender_type:
|
|
241
264
|
return
|
|
242
|
-
|
|
243
|
-
|
|
244
265
|
if not allow_forwarded and message.forwarded_from:
|
|
245
266
|
return
|
|
246
|
-
|
|
247
|
-
|
|
248
267
|
if not allow_files and message.file:
|
|
249
268
|
return
|
|
250
269
|
if not allow_stickers and message.sticker:
|
|
@@ -517,6 +536,142 @@ class Robot:
|
|
|
517
536
|
})
|
|
518
537
|
return func
|
|
519
538
|
return decorator
|
|
539
|
+
|
|
540
|
+
def on_message_file(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
541
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
542
|
+
async def wrapper(bot, message: Message):
|
|
543
|
+
if not message.file:return
|
|
544
|
+
if filters and not filters(message):return
|
|
545
|
+
return await func(bot, message)
|
|
546
|
+
|
|
547
|
+
self._message_handlers.append({
|
|
548
|
+
"func": wrapper,
|
|
549
|
+
"filters": filters,
|
|
550
|
+
"file_only": True,
|
|
551
|
+
"commands": commands
|
|
552
|
+
})
|
|
553
|
+
return wrapper
|
|
554
|
+
return decorator
|
|
555
|
+
def on_message_forwarded(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
556
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
557
|
+
async def wrapper(bot, message: Message):
|
|
558
|
+
if not message.is_forwarded:return
|
|
559
|
+
if filters and not filters(message):return
|
|
560
|
+
return await func(bot, message)
|
|
561
|
+
|
|
562
|
+
self._message_handlers.append({
|
|
563
|
+
"func": wrapper,
|
|
564
|
+
"filters": filters,
|
|
565
|
+
"forwarded_only": True,
|
|
566
|
+
"commands": commands
|
|
567
|
+
})
|
|
568
|
+
return wrapper
|
|
569
|
+
return decorator
|
|
570
|
+
def on_message_reply(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
571
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
572
|
+
async def wrapper(bot, message: Message):
|
|
573
|
+
if not message.is_reply:return
|
|
574
|
+
if filters and not filters(message):return
|
|
575
|
+
return await func(bot, message)
|
|
576
|
+
|
|
577
|
+
self._message_handlers.append({
|
|
578
|
+
"func": wrapper,
|
|
579
|
+
"filters": filters,
|
|
580
|
+
"reply_only": True,
|
|
581
|
+
"commands": commands
|
|
582
|
+
})
|
|
583
|
+
return wrapper
|
|
584
|
+
return decorator
|
|
585
|
+
def on_message_text(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
586
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
587
|
+
async def wrapper(bot, message: Message):
|
|
588
|
+
if not message.text:return
|
|
589
|
+
if filters and not filters(message):return
|
|
590
|
+
return await func(bot, message)
|
|
591
|
+
|
|
592
|
+
self._message_handlers.append({
|
|
593
|
+
"func": wrapper,
|
|
594
|
+
"filters": filters,
|
|
595
|
+
"text_only": True,
|
|
596
|
+
"commands": commands
|
|
597
|
+
})
|
|
598
|
+
return wrapper
|
|
599
|
+
return decorator
|
|
600
|
+
def on_message_media(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
601
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
602
|
+
async def wrapper(bot, message: Message):
|
|
603
|
+
if not message.is_media:return
|
|
604
|
+
if filters and not filters(message):return
|
|
605
|
+
return await func(bot, message)
|
|
606
|
+
|
|
607
|
+
self._message_handlers.append({
|
|
608
|
+
"func": wrapper,
|
|
609
|
+
"filters": filters,
|
|
610
|
+
"media_only": True,
|
|
611
|
+
"commands": commands
|
|
612
|
+
})
|
|
613
|
+
return wrapper
|
|
614
|
+
return decorator
|
|
615
|
+
def on_message_sticker(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
616
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
617
|
+
async def wrapper(bot, message: Message):
|
|
618
|
+
if not message.sticker:return
|
|
619
|
+
if filters and not filters(message):return
|
|
620
|
+
return await func(bot, message)
|
|
621
|
+
|
|
622
|
+
self._message_handlers.append({
|
|
623
|
+
"func": wrapper,
|
|
624
|
+
"filters": filters,
|
|
625
|
+
"sticker_only": True,
|
|
626
|
+
"commands": commands
|
|
627
|
+
})
|
|
628
|
+
return wrapper
|
|
629
|
+
return decorator
|
|
630
|
+
def on_message_contact(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
631
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
632
|
+
async def wrapper(bot, message: Message):
|
|
633
|
+
if not message.is_contact:return
|
|
634
|
+
if filters and not filters(message):return
|
|
635
|
+
return await func(bot, message)
|
|
636
|
+
|
|
637
|
+
self._message_handlers.append({
|
|
638
|
+
"func": wrapper,
|
|
639
|
+
"filters": filters,
|
|
640
|
+
"contact_only": True,
|
|
641
|
+
"commands": commands
|
|
642
|
+
})
|
|
643
|
+
return wrapper
|
|
644
|
+
return decorator
|
|
645
|
+
def on_message_location(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
646
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
647
|
+
async def wrapper(bot, message: Message):
|
|
648
|
+
if not message.is_location:return
|
|
649
|
+
if filters and not filters(message):return
|
|
650
|
+
return await func(bot, message)
|
|
651
|
+
|
|
652
|
+
self._message_handlers.append({
|
|
653
|
+
"func": wrapper,
|
|
654
|
+
"filters": filters,
|
|
655
|
+
"location_only": True,
|
|
656
|
+
"commands": commands
|
|
657
|
+
})
|
|
658
|
+
return wrapper
|
|
659
|
+
return decorator
|
|
660
|
+
def on_message_poll(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
661
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
662
|
+
async def wrapper(bot, message: Message):
|
|
663
|
+
if not message.is_poll:return
|
|
664
|
+
if filters and not filters(message):return
|
|
665
|
+
return await func(bot, message)
|
|
666
|
+
|
|
667
|
+
self._message_handlers.append({
|
|
668
|
+
"func": wrapper,
|
|
669
|
+
"filters": filters,
|
|
670
|
+
"poll_only": True,
|
|
671
|
+
"commands": commands
|
|
672
|
+
})
|
|
673
|
+
return wrapper
|
|
674
|
+
return decorator
|
|
520
675
|
def on_update(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
521
676
|
def decorator(func: Callable[[Any, Message], None]):
|
|
522
677
|
self._message_handlers.append({
|
|
@@ -1481,17 +1636,18 @@ class Robot:
|
|
|
1481
1636
|
|
|
1482
1637
|
data = aiohttp.FormData()
|
|
1483
1638
|
data.add_field('file', file_progress_generator(path), filename=name, content_type='application/octet-stream')
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1639
|
+
try:
|
|
1640
|
+
async with session.post(upload_url, data=data) as response:
|
|
1641
|
+
progress_bar.close()
|
|
1642
|
+
if response.status != 200:
|
|
1643
|
+
raise Exception(f"Upload failed ({response.status}): {await response.text()}")
|
|
1644
|
+
|
|
1645
|
+
json_data = await response.json()
|
|
1646
|
+
if is_temp_file:
|
|
1647
|
+
os.remove(path)
|
|
1648
|
+
return json_data.get('data', {}).get('file_id')
|
|
1649
|
+
except :
|
|
1650
|
+
raise FeatureNotAvailableError(f"files is not currently supported by the server.")
|
|
1495
1651
|
|
|
1496
1652
|
|
|
1497
1653
|
def get_extension(content_type: str) -> str:
|
|
@@ -1584,19 +1740,37 @@ class Robot:
|
|
|
1584
1740
|
except Exception as e:
|
|
1585
1741
|
raise Exception(f"An error occurred while downloading the file: {e}")
|
|
1586
1742
|
|
|
1587
|
-
async def get_upload_url(self, media_type: Literal['File', 'Image', '
|
|
1588
|
-
allowed = ['File', 'Image', '
|
|
1743
|
+
async def get_upload_url(self, media_type: Literal['File', 'Image', 'voice', 'Music', 'Gif', 'Video']) -> str:
|
|
1744
|
+
allowed = ['File', 'Image', 'voice', 'Music', 'Gif', 'Video']
|
|
1589
1745
|
if media_type not in allowed:
|
|
1590
1746
|
raise ValueError(f"Invalid media type. Must be one of {allowed}")
|
|
1591
1747
|
result = await self._post("requestSendFile", {"type": media_type})
|
|
1592
1748
|
return result.get("data", {}).get("upload_url")
|
|
1593
1749
|
|
|
1594
|
-
async def _send_uploaded_file(self, chat_id: str, file_id: str, text: Optional[str] = None, chat_keypad: Optional[Dict[str, Any]] = None, inline_keypad: Optional[Dict[str, Any]] = None, disable_notification: bool = False, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1750
|
+
async def _send_uploaded_file(self, chat_id: str, file_id: str,type_file : str = "file",text: Optional[str] = None, chat_keypad: Optional[Dict[str, Any]] = None, inline_keypad: Optional[Dict[str, Any]] = None, disable_notification: bool = False, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1595
1751
|
payload = {"chat_id": chat_id, "file_id": file_id, "text": text, "disable_notification": disable_notification, "chat_keypad_type": chat_keypad_type}
|
|
1596
1752
|
if chat_keypad: payload["chat_keypad"] = chat_keypad
|
|
1597
1753
|
if inline_keypad: payload["inline_keypad"] = inline_keypad
|
|
1598
1754
|
if reply_to_message_id: payload["reply_to_message_id"] = str(reply_to_message_id)
|
|
1599
|
-
|
|
1755
|
+
payload["time"] = "10"
|
|
1756
|
+
resp = await self._post("sendFile", payload)
|
|
1757
|
+
message_id_put = resp["data"]["message_id"]
|
|
1758
|
+
result = {
|
|
1759
|
+
"status": resp.get("status"),
|
|
1760
|
+
"status_det": resp.get("status_det"),
|
|
1761
|
+
"file_id": file_id,
|
|
1762
|
+
"text":text,
|
|
1763
|
+
"message_id": message_id_put,
|
|
1764
|
+
"send_to_chat_id": chat_id,
|
|
1765
|
+
"reply_to_message_id": reply_to_message_id,
|
|
1766
|
+
"disable_notification": disable_notification,
|
|
1767
|
+
"type_file": type_file,
|
|
1768
|
+
"raw_response": resp,
|
|
1769
|
+
"chat_keypad":chat_keypad,
|
|
1770
|
+
"inline_keypad":inline_keypad,
|
|
1771
|
+
"chat_keypad_type":chat_keypad_type
|
|
1772
|
+
}
|
|
1773
|
+
return result
|
|
1600
1774
|
|
|
1601
1775
|
async def _send_file_generic(self, media_type, chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type):
|
|
1602
1776
|
if path:
|
|
@@ -1605,7 +1779,7 @@ class Robot:
|
|
|
1605
1779
|
file_id = await self.upload_media_file(upload_url, file_name, path)
|
|
1606
1780
|
if not file_id:
|
|
1607
1781
|
raise ValueError("Either path or file_id must be provided.")
|
|
1608
|
-
return await self._send_uploaded_file(chat_id=chat_id, file_id=file_id, text=text, inline_keypad=inline_keypad, chat_keypad=chat_keypad, reply_to_message_id=reply_to_message_id, disable_notification=disable_notification, chat_keypad_type=chat_keypad_type)
|
|
1782
|
+
return await self._send_uploaded_file(chat_id=chat_id, file_id=file_id, text=text, inline_keypad=inline_keypad, chat_keypad=chat_keypad, reply_to_message_id=reply_to_message_id, disable_notification=disable_notification, chat_keypad_type=chat_keypad_type,type_file=media_type)
|
|
1609
1783
|
|
|
1610
1784
|
async def send_document(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1611
1785
|
return await self._send_file_generic("File", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
@@ -1613,14 +1787,14 @@ class Robot:
|
|
|
1613
1787
|
return await self._send_file_generic("File", chat_id, path, file_id, caption, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1614
1788
|
async def re_send(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, caption: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1615
1789
|
return await self._send_file_generic("File", chat_id, path, file_id, caption, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1616
|
-
async def send_music(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] =
|
|
1617
|
-
return await self._send_file_generic("
|
|
1790
|
+
async def send_music(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = "music", inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1791
|
+
return await self._send_file_generic("File", chat_id, path, file_id, text, f"{file_name}.ogg", inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1618
1792
|
|
|
1619
1793
|
async def send_video(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1620
1794
|
return await self._send_file_generic("Video", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1621
1795
|
|
|
1622
1796
|
async def send_voice(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1623
|
-
return await self._send_file_generic("
|
|
1797
|
+
return await self._send_file_generic("voice", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1624
1798
|
|
|
1625
1799
|
async def send_image(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1626
1800
|
return await self._send_file_generic("Image", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
@@ -1656,13 +1830,19 @@ class Robot:
|
|
|
1656
1830
|
try:
|
|
1657
1831
|
chat = await self.get_chat(chat_id)
|
|
1658
1832
|
chat_info = chat.get("data", {}).get("chat", {})
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1833
|
+
chat_type = chat_info.get("chat_type", "").lower()
|
|
1834
|
+
if chat_type == "user":
|
|
1835
|
+
first_name = chat_info.get("first_name", "")
|
|
1836
|
+
last_name = chat_info.get("last_name", "")
|
|
1837
|
+
full_name = f"{first_name} {last_name}".strip()
|
|
1838
|
+
return full_name if full_name else "null"
|
|
1839
|
+
elif chat_type in ["group", "channel"]:
|
|
1840
|
+
title = chat_info.get("title", "")
|
|
1841
|
+
return title if title else "null"
|
|
1842
|
+
else:return "null"
|
|
1843
|
+
except Exception:return "null"
|
|
1844
|
+
|
|
1845
|
+
|
|
1666
1846
|
|
|
1667
1847
|
async def get_username(self, chat_id: str) -> str:
|
|
1668
1848
|
chat_info = await self.get_chat(chat_id)
|
|
@@ -190,8 +190,10 @@ from pathlib import Path
|
|
|
190
190
|
class Message:
|
|
191
191
|
def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
|
|
192
192
|
self.bot = bot
|
|
193
|
-
self.chat_id = chat_id
|
|
194
193
|
self.raw_data = raw_data or {}
|
|
194
|
+
self.chat_id = chat_id
|
|
195
|
+
self.object_guid = chat_id
|
|
196
|
+
self.author_guid = self.raw_data.get("sender_id", sender_id)
|
|
195
197
|
self.message_id: str = self.raw_data.get("message_id", message_id)
|
|
196
198
|
self.text: str = self.raw_data.get("text", text)
|
|
197
199
|
self.sender_id: str = self.raw_data.get("sender_id", sender_id)
|
|
@@ -199,6 +201,7 @@ class Message:
|
|
|
199
201
|
self.is_edited: bool = self.raw_data.get("is_edited", False)
|
|
200
202
|
self.sender_type: str = self.raw_data.get("sender_type")
|
|
201
203
|
self.args = []
|
|
204
|
+
self.is_command = bool(self.text and self.text.startswith("/"))
|
|
202
205
|
self.is_user = self.chat_id.startswith("b")
|
|
203
206
|
self.is_private = self.chat_id.startswith("b")
|
|
204
207
|
self.is_group = self.chat_id.startswith("g")
|
|
@@ -212,7 +215,18 @@ class Message:
|
|
|
212
215
|
self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
|
|
213
216
|
self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
|
|
214
217
|
self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
|
|
215
|
-
|
|
218
|
+
self.is_reply = self.reply_to_message_id is not None
|
|
219
|
+
self.has_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
|
|
220
|
+
self.is_forwarded = self.forwarded_from is not None
|
|
221
|
+
self.is_text = bool(self.text and not self.has_media)
|
|
222
|
+
self.is_media = self.has_media
|
|
223
|
+
self.is_poll = self.poll is not None
|
|
224
|
+
self.is_location = self.location is not None
|
|
225
|
+
self.is_live_location = self.live_location is not None
|
|
226
|
+
self.is_contact = self.contact_message is not None
|
|
227
|
+
self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
|
|
228
|
+
self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
|
|
229
|
+
self.info = {attr: value for attr, value in vars(self).items()}
|
|
216
230
|
@property
|
|
217
231
|
def session(self):
|
|
218
232
|
if self.chat_id not in self.bot.sessions:
|
|
@@ -190,8 +190,10 @@ from pathlib import Path
|
|
|
190
190
|
class Message:
|
|
191
191
|
def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
|
|
192
192
|
self.bot = bot
|
|
193
|
-
self.chat_id = chat_id
|
|
194
193
|
self.raw_data = raw_data or {}
|
|
194
|
+
self.chat_id = chat_id
|
|
195
|
+
self.object_guid = chat_id
|
|
196
|
+
self.author_guid = self.raw_data.get("sender_id", sender_id)
|
|
195
197
|
self.message_id: str = self.raw_data.get("message_id", message_id)
|
|
196
198
|
self.text: str = self.raw_data.get("text", text)
|
|
197
199
|
self.sender_id: str = self.raw_data.get("sender_id", sender_id)
|
|
@@ -199,6 +201,7 @@ class Message:
|
|
|
199
201
|
self.is_edited: bool = self.raw_data.get("is_edited", False)
|
|
200
202
|
self.sender_type: str = self.raw_data.get("sender_type")
|
|
201
203
|
self.args = []
|
|
204
|
+
self.is_command = bool(self.text and self.text.startswith("/"))
|
|
202
205
|
self.is_user = self.chat_id.startswith("b")
|
|
203
206
|
self.is_private = self.chat_id.startswith("b")
|
|
204
207
|
self.is_group = self.chat_id.startswith("g")
|
|
@@ -212,7 +215,18 @@ class Message:
|
|
|
212
215
|
self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
|
|
213
216
|
self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
|
|
214
217
|
self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
|
|
215
|
-
|
|
218
|
+
self.is_reply = self.reply_to_message_id is not None
|
|
219
|
+
self.has_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
|
|
220
|
+
self.is_forwarded = self.forwarded_from is not None
|
|
221
|
+
self.is_text = bool(self.text and not self.has_media)
|
|
222
|
+
self.is_media = self.has_media
|
|
223
|
+
self.is_poll = self.poll is not None
|
|
224
|
+
self.is_location = self.location is not None
|
|
225
|
+
self.is_live_location = self.live_location is not None
|
|
226
|
+
self.is_contact = self.contact_message is not None
|
|
227
|
+
self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
|
|
228
|
+
self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
|
|
229
|
+
self.info = {attr: value for attr, value in vars(self).items()}
|
|
216
230
|
@property
|
|
217
231
|
def session(self):
|
|
218
232
|
if self.chat_id not in self.bot.sessions:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|