Rubka 6.6.11__tar.gz → 6.6.13__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.

Potentially problematic release.


This version of Rubka might be problematic. Click here for more details.

Files changed (50) hide show
  1. {rubka-6.6.11 → rubka-6.6.13}/PKG-INFO +1 -1
  2. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/PKG-INFO +1 -1
  3. {rubka-6.6.11 → rubka-6.6.13}/rubka/asynco.py +112 -5
  4. {rubka-6.6.11 → rubka-6.6.13}/rubka/context.py +63 -2
  5. {rubka-6.6.11 → rubka-6.6.13}/rubka/update.py +63 -2
  6. {rubka-6.6.11 → rubka-6.6.13}/setup.py +1 -1
  7. {rubka-6.6.11 → rubka-6.6.13}/README.md +0 -0
  8. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/SOURCES.txt +0 -0
  9. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/dependency_links.txt +0 -0
  10. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/entry_points.txt +0 -0
  11. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/not-zip-safe +0 -0
  12. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/requires.txt +0 -0
  13. {rubka-6.6.11 → rubka-6.6.13}/Rubka.egg-info/top_level.txt +0 -0
  14. {rubka-6.6.11 → rubka-6.6.13}/rubka/__init__.py +0 -0
  15. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/__init__.py +0 -0
  16. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/client/__init__.py +0 -0
  17. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/client/client.py +0 -0
  18. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/crypto/__init__.py +0 -0
  19. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/crypto/crypto.py +0 -0
  20. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/enums.py +0 -0
  21. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/exceptions.py +0 -0
  22. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/methods/__init__.py +0 -0
  23. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/methods/methods.py +0 -0
  24. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/network/__init__.py +0 -0
  25. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/network/helper.py +0 -0
  26. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/network/network.py +0 -0
  27. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/network/socket.py +0 -0
  28. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/sessions/__init__.py +0 -0
  29. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/sessions/sessions.py +0 -0
  30. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/types/__init__.py +0 -0
  31. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
  32. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/types/socket/message.py +0 -0
  33. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/utils/__init__.py +0 -0
  34. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/utils/configs.py +0 -0
  35. {rubka-6.6.11 → rubka-6.6.13}/rubka/adaptorrubka/utils/utils.py +0 -0
  36. {rubka-6.6.11 → rubka-6.6.13}/rubka/api.py +0 -0
  37. {rubka-6.6.11 → rubka-6.6.13}/rubka/button.py +0 -0
  38. {rubka-6.6.11 → rubka-6.6.13}/rubka/config.py +0 -0
  39. {rubka-6.6.11 → rubka-6.6.13}/rubka/decorators.py +0 -0
  40. {rubka-6.6.11 → rubka-6.6.13}/rubka/exceptions.py +0 -0
  41. {rubka-6.6.11 → rubka-6.6.13}/rubka/filters.py +0 -0
  42. {rubka-6.6.11 → rubka-6.6.13}/rubka/helpers.py +0 -0
  43. {rubka-6.6.11 → rubka-6.6.13}/rubka/jobs.py +0 -0
  44. {rubka-6.6.11 → rubka-6.6.13}/rubka/keyboards.py +0 -0
  45. {rubka-6.6.11 → rubka-6.6.13}/rubka/keypad.py +0 -0
  46. {rubka-6.6.11 → rubka-6.6.13}/rubka/logger.py +0 -0
  47. {rubka-6.6.11 → rubka-6.6.13}/rubka/rubino.py +0 -0
  48. {rubka-6.6.11 → rubka-6.6.13}/rubka/tv.py +0 -0
  49. {rubka-6.6.11 → rubka-6.6.13}/rubka/utils.py +0 -0
  50. {rubka-6.6.11 → rubka-6.6.13}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 6.6.11
3
+ Version: 6.6.13
4
4
  Summary: rubika 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/archive/refs/tags/v6.6.4.zip
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 6.6.11
3
+ Version: 6.6.13
4
4
  Summary: rubika 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/archive/refs/tags/v6.6.4.zip
@@ -143,6 +143,7 @@ class Robot:
143
143
  self._inline_query_handler = None
144
144
 
145
145
  self._callback_handlers: List[dict] = []
146
+ self._edited_message_handlers = []
146
147
  self._processed_message_ids: Dict[str, float] = {}
147
148
  self._message_handlers: List[dict] = []
148
149
 
@@ -223,7 +224,7 @@ class Robot:
223
224
  allow_polls: bool = True,
224
225
  allow_contacts: bool = True,
225
226
  allow_locations: bool = True,
226
- min_text_length: Optional[int] = None,
227
+ min_text_length: Optional[int] = None,
227
228
  max_text_length: Optional[int] = None,
228
229
  contains: Optional[str] = None,
229
230
  startswith: Optional[str] = None,
@@ -410,6 +411,7 @@ class Robot:
410
411
 
411
412
  def decorator(func: Callable[[Any, Message], None]):
412
413
  async def wrapper(bot, message: Message):
414
+
413
415
  if not message.is_group:
414
416
  return
415
417
  if chat_id:
@@ -470,7 +472,37 @@ class Robot:
470
472
  })
471
473
  return wrapper
472
474
  return decorator
475
+ def remove_handler(self, func: Callable):
476
+ """
477
+ Remove a message handler by its original function reference.
478
+ """
479
+ self._message_handlers = [
480
+ h for h in self._message_handlers if h["func"].__wrapped__ != func
481
+ ]
482
+ def on_edited_message(
483
+ self,
484
+ filters: Optional[Callable[[Message], bool]] = None,
485
+ commands: Optional[List[str]] = None
486
+ ):
487
+ def decorator(func: Callable[[Any, Message], None]):
488
+ async def wrapper(bot, message: Message):
489
+ if filters and not filters(message):
490
+ return
491
+ if commands:
492
+ if not message.is_command:
493
+ return
494
+ cmd = message.text.split()[0].lstrip("/")
495
+ if cmd not in commands:
496
+ return
497
+ return await func(bot, message)
473
498
 
499
+ self._edited_message_handlers.append({
500
+ "func": wrapper,
501
+ "filters": filters,
502
+ "commands": commands
503
+ })
504
+ return wrapper
505
+ return decorator
474
506
  def on_message(
475
507
  self,
476
508
  filters: Optional[Callable[[Message], bool]] = None,
@@ -762,7 +794,34 @@ class Robot:
762
794
  if handler_info["commands"] or handler_info["filters"]:
763
795
  asyncio.create_task(handler_info["func"](self, context))#jaq
764
796
  continue
797
+ elif update.get("type") == "UpdatedMessage":
798
+ msg = update.get("updated_message", {})
799
+ if not msg:
800
+ return
765
801
 
802
+ context = Message(
803
+ bot=self,
804
+ chat_id=update.get("chat_id"),
805
+ message_id=msg.get("message_id"),
806
+ text=msg.get("text"),
807
+ sender_id=msg.get("sender_id"),
808
+ raw_data=msg
809
+ )
810
+ if self._edited_message_handlers:
811
+ for handler_info in self._edited_message_handlers:
812
+ if handler_info["commands"]:
813
+ if not context.text or not context.text.startswith("/"):
814
+ continue
815
+ parts = context.text.split()
816
+ cmd = parts[0][1:]
817
+ if cmd not in handler_info["commands"]:
818
+ continue
819
+ context.args = parts[1:]
820
+ if handler_info["filters"]:
821
+ if not handler_info["filters"](context):
822
+ continue
823
+ asyncio.create_task(handler_info["func"](self, context))
824
+
766
825
  async def get_updates(self, offset_id: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
767
826
  data = {}
768
827
  if offset_id: data["offset_id"] = offset_id
@@ -834,7 +893,7 @@ class Robot:
834
893
  notify_on_error: bool = False,
835
894
  notification_handler: Optional[Callable[[str], Any]] = None,
836
895
  watchdog_timeout: Optional[float] = None,
837
- ):
896
+ ):
838
897
  """
839
898
  Starts the bot's main execution loop with extensive configuration options.
840
899
 
@@ -977,12 +1036,16 @@ class Robot:
977
1036
  im = update.get("inline_message", {})
978
1037
  sender = im.get("author_object_guid") or im.get("author_guid")
979
1038
  chat = im.get("object_guid") or im.get("chat_id")
1039
+ elif t == "UpdatedMessage":
1040
+ im = update.get("updated_message", {})
1041
+ sender = im.get("author_object_guid") or im.get("author_guid")
1042
+ chat = im.get("object_guid") or im.get("chat_id")
980
1043
  else:
981
1044
  sender = update.get("author_guid") or update.get("from_id")
982
1045
  chat = update.get("object_guid") or update.get("chat_id")
983
1046
  return str(sender) if sender is not None else None, str(chat) if chat is not None else None
984
1047
 
985
- def _is_group_chat(chat_guid: str | None) -> bool | None:
1048
+ def _is_group_chat(chat_guid: Optional[str]) -> Optional[bool]:
986
1049
 
987
1050
  if chat_guid is None:
988
1051
  return None
@@ -1050,8 +1113,6 @@ class Robot:
1050
1113
  return False
1051
1114
  if skip_service_messages and t == "ServiceMessage":
1052
1115
  return False
1053
- if skip_edited_messages and t == "EditMessage":
1054
- return False
1055
1116
  if skip_channel_posts and t == "ChannelPost":
1056
1117
  return False
1057
1118
 
@@ -1081,6 +1142,8 @@ class Robot:
1081
1142
  content = (update.get("new_message") or {}).get("text")
1082
1143
  elif t == "ReceiveQuery":
1083
1144
  content = (update.get("inline_message") or {}).get("text")
1145
+ elif t == "UpdatedMessage":
1146
+ content = (update.get("updated_message") or {}).get("text")
1084
1147
  elif "text" in update:
1085
1148
  content = update.get("text")
1086
1149
  if content and isinstance(content, str) and len(content) > max_message_size:
@@ -1197,6 +1260,8 @@ class Robot:
1197
1260
  message_id = update.get("new_message", {}).get("message_id")
1198
1261
  elif update.get("type") == "ReceiveQuery":
1199
1262
  message_id = update.get("inline_message", {}).get("message_id")
1263
+ elif update.get("type") == "UpdatedMessage":
1264
+ message_id = update.get("updated_message", {}).get("message_id")
1200
1265
  elif "message_id" in update:
1201
1266
  message_id = update.get("message_id")
1202
1267
 
@@ -1220,6 +1285,8 @@ class Robot:
1220
1285
  message_id = update.get("new_message", {}).get("message_id")
1221
1286
  elif update.get("type") == "ReceiveQuery":
1222
1287
  message_id = update.get("inline_message", {}).get("message_id")
1288
+ elif update.get("type") == "UpdatedMessage":
1289
+ message_id = update.get("updated_message", {}).get("message_id")
1223
1290
  elif "message_id" in update:
1224
1291
  message_id = update.get("message_id")
1225
1292
 
@@ -1377,6 +1444,46 @@ class Robot:
1377
1444
  if reply_to_message_id:
1378
1445
  payload["reply_to_message_id"] = reply_to_message_id
1379
1446
  return await self._post("sendMessage", payload)
1447
+
1448
+ from typing import Optional, Dict, Any, Literal
1449
+
1450
+ async def send_sticker(
1451
+ self,
1452
+ chat_id: str,
1453
+ sticker_id: str,
1454
+ chat_keypad: Optional[Dict[str, Any]] = None,
1455
+ disable_notification: bool = False,
1456
+ inline_keypad: Optional[Dict[str, Any]] = None,
1457
+ reply_to_message_id: Optional[str] = None,
1458
+ chat_keypad_type: Optional[Literal['New', 'Remove']] = None,
1459
+ ) -> str:
1460
+ """
1461
+ Send a sticker to a chat.
1462
+
1463
+ Args:
1464
+ token: Bot token.
1465
+ chat_id: Target chat ID.
1466
+ sticker_id: ID of the sticker to send.
1467
+ chat_keypad: Optional chat keypad data.
1468
+ disable_notification: If True, disables notification.
1469
+ inline_keypad: Optional inline keyboard data.
1470
+ reply_to_message_id: Optional message ID to reply to.
1471
+ chat_keypad_type: Type of chat keypad change ('New' or 'Remove').
1472
+
1473
+ Returns:
1474
+ API response as a string.
1475
+ """
1476
+ data = {
1477
+ 'chat_id': chat_id,
1478
+ 'sticker_id': sticker_id,
1479
+ 'chat_keypad': chat_keypad,
1480
+ 'disable_notification': disable_notification,
1481
+ 'inline_keypad': inline_keypad,
1482
+ 'reply_to_message_id': reply_to_message_id,
1483
+ 'chat_keypad_type': chat_keypad_type,
1484
+ }
1485
+ return await self._post("sendSticker", data)
1486
+
1380
1487
 
1381
1488
  async def get_url_file(self,file_id):
1382
1489
  data = await self._post("getFile", {'file_id': file_id})
@@ -186,7 +186,7 @@ class Bot:
186
186
  self.share_url: str = data.get("share_url")
187
187
  from typing import Union
188
188
  from pathlib import Path
189
-
189
+ import re
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
@@ -196,6 +196,10 @@ class Message:
196
196
  self.author_guid = self.raw_data.get("sender_id", sender_id)
197
197
  self.message_id: str = self.raw_data.get("message_id", message_id)
198
198
  self.text: str = self.raw_data.get("text", text)
199
+ self.has_link = bool(re.search(
200
+ r"(https?://[^\s]+|www\.[^\s]+|[a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co)|t\.me/[^\s]+|telegram\.me/[^\s]+|@\w+|\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)",
201
+ self.raw_data.get("text", text) or ""
202
+ ))
199
203
  self.sender_id: str = self.raw_data.get("sender_id", sender_id)
200
204
  self.time: str = self.raw_data.get("time")
201
205
  self.is_edited: bool = self.raw_data.get("is_edited", False)
@@ -226,6 +230,16 @@ class Message:
226
230
  self.is_contact = self.contact_message is not None
227
231
  self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
228
232
  self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
233
+ if self.file and self.file.file_name:
234
+ name = self.file.file_name.lower()
235
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
236
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
237
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
238
+ self.is_voice = name.endswith((".ogg", ".m4a"))
239
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
240
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
241
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
242
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
229
243
  self.info = {attr: value for attr, value in vars(self).items()}
230
244
  @property
231
245
  def session(self):
@@ -467,12 +481,59 @@ class InlineMessage:
467
481
  def __init__(self, bot, raw_data: dict):
468
482
  self.bot = bot
469
483
  self.raw_data = raw_data
470
-
484
+ chat_id : str = raw_data.get("chat_id")
485
+ sender_id : str = raw_data.get("sender_id")
471
486
  self.chat_id: str = raw_data.get("chat_id")
472
487
  self.message_id: str = raw_data.get("message_id")
473
488
  self.sender_id: str = raw_data.get("sender_id")
474
489
  self.text: str = raw_data.get("text")
475
490
  self.aux_data = AuxData(raw_data.get("aux_data", {})) if "aux_data" in raw_data else None
491
+ self.bot = bot
492
+ self.raw_data = raw_data or {}
493
+ self.object_guid = chat_id
494
+ self.author_guid = self.raw_data.get("sender_id", sender_id)
495
+ self.has_link = bool(re.search(r"(https?://[^\s]+ | www\.[^\s]+ | [a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co) | t\.me/[^\s]+ | telegram\.me/[^\s]+ | @\w+ | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)", self.text))
496
+ self.sender_id: str = self.raw_data.get("sender_id", sender_id)
497
+ self.time: str = self.raw_data.get("time")
498
+ self.is_edited: bool = self.raw_data.get("is_edited", False)
499
+ self.sender_type: str = self.raw_data.get("sender_type")
500
+ self.args = []
501
+ self.is_command = bool(self.text and self.text.startswith("/"))
502
+ self.is_user = self.chat_id.startswith("b")
503
+ self.is_private = self.chat_id.startswith("b")
504
+ self.is_group = self.chat_id.startswith("g")
505
+ self.is_channel = self.chat_id.startswith("c")
506
+ self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
507
+ self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
508
+ self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
509
+ self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
510
+ self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
511
+ self.poll = Poll(self.raw_data["poll"]) if "poll" in self.raw_data else None
512
+ self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
513
+ self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
514
+ self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
515
+ self.is_reply = self.reply_to_message_id is not None
516
+ self.has_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
517
+ self.is_forwarded = self.forwarded_from is not None
518
+ self.is_text = bool(self.text and not self.has_media)
519
+ self.is_media = self.has_media
520
+ self.is_poll = self.poll is not None
521
+ self.is_location = self.location is not None
522
+ self.is_live_location = self.live_location is not None
523
+ self.is_contact = self.contact_message is not None
524
+ self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
525
+ self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
526
+ if self.file and self.file.file_name:
527
+ name = self.file.file_name.lower()
528
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
529
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
530
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
531
+ self.is_voice = name.endswith((".ogg", ".m4a"))
532
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
533
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
534
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
535
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
536
+
476
537
 
477
538
  def reply(self, text: str, **kwargs):
478
539
  return self.bot.send_message(
@@ -186,7 +186,7 @@ class Bot:
186
186
  self.share_url: str = data.get("share_url")
187
187
  from typing import Union
188
188
  from pathlib import Path
189
-
189
+ import re
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
@@ -196,6 +196,10 @@ class Message:
196
196
  self.author_guid = self.raw_data.get("sender_id", sender_id)
197
197
  self.message_id: str = self.raw_data.get("message_id", message_id)
198
198
  self.text: str = self.raw_data.get("text", text)
199
+ self.has_link = bool(re.search(
200
+ r"(https?://[^\s]+|www\.[^\s]+|[a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co)|t\.me/[^\s]+|telegram\.me/[^\s]+|@\w+|\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)",
201
+ self.raw_data.get("text", text) or ""
202
+ ))
199
203
  self.sender_id: str = self.raw_data.get("sender_id", sender_id)
200
204
  self.time: str = self.raw_data.get("time")
201
205
  self.is_edited: bool = self.raw_data.get("is_edited", False)
@@ -226,6 +230,16 @@ class Message:
226
230
  self.is_contact = self.contact_message is not None
227
231
  self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
228
232
  self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
233
+ if self.file and self.file.file_name:
234
+ name = self.file.file_name.lower()
235
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
236
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
237
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
238
+ self.is_voice = name.endswith((".ogg", ".m4a"))
239
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
240
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
241
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
242
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
229
243
  self.info = {attr: value for attr, value in vars(self).items()}
230
244
  @property
231
245
  def session(self):
@@ -467,12 +481,59 @@ class InlineMessage:
467
481
  def __init__(self, bot, raw_data: dict):
468
482
  self.bot = bot
469
483
  self.raw_data = raw_data
470
-
484
+ chat_id : str = raw_data.get("chat_id")
485
+ sender_id : str = raw_data.get("sender_id")
471
486
  self.chat_id: str = raw_data.get("chat_id")
472
487
  self.message_id: str = raw_data.get("message_id")
473
488
  self.sender_id: str = raw_data.get("sender_id")
474
489
  self.text: str = raw_data.get("text")
475
490
  self.aux_data = AuxData(raw_data.get("aux_data", {})) if "aux_data" in raw_data else None
491
+ self.bot = bot
492
+ self.raw_data = raw_data or {}
493
+ self.object_guid = chat_id
494
+ self.author_guid = self.raw_data.get("sender_id", sender_id)
495
+ self.has_link = bool(re.search(r"(https?://[^\s]+ | www\.[^\s]+ | [a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co) | t\.me/[^\s]+ | telegram\.me/[^\s]+ | @\w+ | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)", self.text))
496
+ self.sender_id: str = self.raw_data.get("sender_id", sender_id)
497
+ self.time: str = self.raw_data.get("time")
498
+ self.is_edited: bool = self.raw_data.get("is_edited", False)
499
+ self.sender_type: str = self.raw_data.get("sender_type")
500
+ self.args = []
501
+ self.is_command = bool(self.text and self.text.startswith("/"))
502
+ self.is_user = self.chat_id.startswith("b")
503
+ self.is_private = self.chat_id.startswith("b")
504
+ self.is_group = self.chat_id.startswith("g")
505
+ self.is_channel = self.chat_id.startswith("c")
506
+ self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
507
+ self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
508
+ self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
509
+ self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
510
+ self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
511
+ self.poll = Poll(self.raw_data["poll"]) if "poll" in self.raw_data else None
512
+ self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
513
+ self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
514
+ self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
515
+ self.is_reply = self.reply_to_message_id is not None
516
+ self.has_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
517
+ self.is_forwarded = self.forwarded_from is not None
518
+ self.is_text = bool(self.text and not self.has_media)
519
+ self.is_media = self.has_media
520
+ self.is_poll = self.poll is not None
521
+ self.is_location = self.location is not None
522
+ self.is_live_location = self.live_location is not None
523
+ self.is_contact = self.contact_message is not None
524
+ self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
525
+ self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
526
+ if self.file and self.file.file_name:
527
+ name = self.file.file_name.lower()
528
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
529
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
530
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
531
+ self.is_voice = name.endswith((".ogg", ".m4a"))
532
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
533
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
534
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
535
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
536
+
476
537
 
477
538
  def reply(self, text: str, **kwargs):
478
539
  return self.bot.send_message(
@@ -13,7 +13,7 @@ with open("README.md", "r", encoding="utf-8") as f:
13
13
 
14
14
  setup(
15
15
  name='Rubka',
16
- version='6.6.11',
16
+ version='6.6.13',
17
17
  description='rubika A Python library for interacting with Rubika Bot API.',
18
18
  long_description=long_description,
19
19
  long_description_content_type='text/markdown',
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