Rubka 7.1.9__tar.gz → 7.1.10__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.
Files changed (50) hide show
  1. {rubka-7.1.9 → rubka-7.1.10}/PKG-INFO +1 -1
  2. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/PKG-INFO +1 -1
  3. rubka-7.1.9/rubka/update.py → rubka-7.1.10/rubka/context.py +211 -18
  4. rubka-7.1.9/rubka/context.py → rubka-7.1.10/rubka/update.py +29 -0
  5. {rubka-7.1.9 → rubka-7.1.10}/setup.py +1 -1
  6. {rubka-7.1.9 → rubka-7.1.10}/README.md +0 -0
  7. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/SOURCES.txt +0 -0
  8. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/dependency_links.txt +0 -0
  9. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/entry_points.txt +0 -0
  10. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/not-zip-safe +0 -0
  11. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/requires.txt +0 -0
  12. {rubka-7.1.9 → rubka-7.1.10}/Rubka.egg-info/top_level.txt +0 -0
  13. {rubka-7.1.9 → rubka-7.1.10}/rubka/__init__.py +0 -0
  14. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/__init__.py +0 -0
  15. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/client/__init__.py +0 -0
  16. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/client/client.py +0 -0
  17. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/crypto/__init__.py +0 -0
  18. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/crypto/crypto.py +0 -0
  19. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/enums.py +0 -0
  20. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/exceptions.py +0 -0
  21. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/methods/__init__.py +0 -0
  22. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/methods/methods.py +0 -0
  23. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/network/__init__.py +0 -0
  24. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/network/helper.py +0 -0
  25. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/network/network.py +0 -0
  26. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/network/socket.py +0 -0
  27. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/sessions/__init__.py +0 -0
  28. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/sessions/sessions.py +0 -0
  29. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/types/__init__.py +0 -0
  30. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
  31. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/types/socket/message.py +0 -0
  32. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/utils/__init__.py +0 -0
  33. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/utils/configs.py +0 -0
  34. {rubka-7.1.9 → rubka-7.1.10}/rubka/adaptorrubka/utils/utils.py +0 -0
  35. {rubka-7.1.9 → rubka-7.1.10}/rubka/api.py +0 -0
  36. {rubka-7.1.9 → rubka-7.1.10}/rubka/asynco.py +0 -0
  37. {rubka-7.1.9 → rubka-7.1.10}/rubka/button.py +0 -0
  38. {rubka-7.1.9 → rubka-7.1.10}/rubka/config.py +0 -0
  39. {rubka-7.1.9 → rubka-7.1.10}/rubka/decorators.py +0 -0
  40. {rubka-7.1.9 → rubka-7.1.10}/rubka/exceptions.py +0 -0
  41. {rubka-7.1.9 → rubka-7.1.10}/rubka/filters.py +0 -0
  42. {rubka-7.1.9 → rubka-7.1.10}/rubka/helpers.py +0 -0
  43. {rubka-7.1.9 → rubka-7.1.10}/rubka/jobs.py +0 -0
  44. {rubka-7.1.9 → rubka-7.1.10}/rubka/keyboards.py +0 -0
  45. {rubka-7.1.9 → rubka-7.1.10}/rubka/keypad.py +0 -0
  46. {rubka-7.1.9 → rubka-7.1.10}/rubka/logger.py +0 -0
  47. {rubka-7.1.9 → rubka-7.1.10}/rubka/rubino.py +0 -0
  48. {rubka-7.1.9 → rubka-7.1.10}/rubka/tv.py +0 -0
  49. {rubka-7.1.9 → rubka-7.1.10}/rubka/utils.py +0 -0
  50. {rubka-7.1.9 → rubka-7.1.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 7.1.9
3
+ Version: 7.1.10
4
4
  Summary: Rubika: A Python library for interacting with the Rubika Bot API. This library provides an easy-to-use interface to send messages, polls, stickers, media files, manage groups and channels, handle inline keyboards, and implement advanced bot features like subscription management, user authentication, and message handling. Ideal for developers looking to automate and extend their Rubika bots with Python.
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: 7.1.9
3
+ Version: 7.1.10
4
4
  Summary: Rubika: A Python library for interacting with the Rubika Bot API. This library provides an easy-to-use interface to send messages, polls, stickers, media files, manage groups and channels, handle inline keyboards, and implement advanced bot features like subscription management, user authentication, and message handling. Ideal for developers looking to automate and extend their Rubika bots with Python.
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,8 +1,68 @@
1
- from typing import Any, Dict, List,Optional
2
1
  from typing import Union
3
2
  from pathlib import Path
3
+ from typing import List, Optional, Dict, Any, Literal, Callable, Union,Set
4
4
  import re,inspect
5
5
  import asyncio
6
+ _EMOJI_PATTERN = re.compile(
7
+ "["
8
+ "\U0001F300-\U0001F5FF"
9
+ "\U0001F600-\U0001F64F"
10
+ "\U0001F680-\U0001F6FF"
11
+ "\U0001F700-\U0001F77F"
12
+ "\U0001F780-\U0001F7FF"
13
+ "\U0001F800-\U0001F8FF"
14
+ "\U0001F900-\U0001F9FF"
15
+ "\U0001FA00-\U0001FA6F"
16
+ "\U0001FA70-\U0001FAFF"
17
+ "\U00002700-\U000027BF"
18
+ "\U00002600-\U000026FF"
19
+ "\U00002000-\U000023FF"
20
+ "]+",
21
+ flags=re.UNICODE
22
+ )
23
+
24
+ def contains_emoji(text: str) -> bool:
25
+ if not text:return False
26
+ return bool(_EMOJI_PATTERN.search(text))
27
+
28
+ def count_emojis(text: str) -> int:
29
+ if not text:return 0
30
+ return len(_EMOJI_PATTERN.findall(text))
31
+ def contains_link_or_mention(text: str) -> bool:
32
+ if not text:return False
33
+ pattern = re.compile(
34
+ r"(?i)\b("
35
+ r"https?://[^\s]+"
36
+ r"|www\.[^\s]+"
37
+ r"|[a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co|xyz|in|us|uk|ru|tv|cc|app|dev|site|store|cloud|shop)"
38
+ r"|t\.me/[^\s]+"
39
+ r"|telegram\.me/[^\s]+"
40
+ r"|rubika\.(ir|app)/[^\s]+"
41
+ r"|whatsapp\.com/[^\s]+"
42
+ r"|wa\.me/[^\s]+"
43
+ r"|instagram\.com/[^\s]+"
44
+ r"|instagr\.am/[^\s]+"
45
+ r"|youtube\.com/[^\s]+"
46
+ r"|youtu\.be/[^\s]+"
47
+ r"|aparat\.com/[^\s]+"
48
+ r"|discord\.gg/[^\s]+"
49
+ r"|discord\.com/[^\s]+"
50
+ r"|splus\.ir/[^\s]+"
51
+ r"|eitaa\.com/[^\s]+"
52
+ r"|ble\.ir/[^\s]+"
53
+ r"|gap\.im/[^\s]+"
54
+ r"|rubino\.ir/[^\s]+"
55
+ r"|pin\.it/[^\s]+"
56
+ r"|twitter\.com/[^\s]+"
57
+ r"|x\.com/[^\s]+"
58
+ r"|facebook\.com/[^\s]+"
59
+ r"|threads\.net/[^\s]+"
60
+ r"|@\w+"
61
+ r"|\b\d{1,3}(?:\.\d{1,3}){3}\b"
62
+ r"|\[?[A-F0-9:]{2,39}\]?"
63
+ r")\b"
64
+ )
65
+ return bool(pattern.search(text))
6
66
  class File:
7
67
  def __init__(self, data: dict):
8
68
  self.file_id: str = data.get("file_id")
@@ -215,10 +275,52 @@ class Message:
215
275
  self.author_guid = self.raw_data.get("sender_id", sender_id)
216
276
  self.message_id: str = self.raw_data.get("message_id", message_id)
217
277
  self.text: str = self.raw_data.get("text", text)
218
- self.has_link = bool(re.search(
219
- 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)",
220
- self.raw_data.get("text", text) or ""
221
- ))
278
+ self.has_link = contains_link_or_mention(self.raw_data.get("text", text))
279
+ self.is_link = self.has_link
280
+ self.is_mention = bool(re.search(r"@\w+", self.raw_data.get("text", text) or ""))
281
+ self.is_hashtag = bool(re.search(r"#\w+", text or ""))
282
+ self.is_number = bool(re.search(r"\d+", text or ""))
283
+ self.is_emoji = contains_emoji(self.raw_data.get("text", text))
284
+ self.emoji_count = count_emojis(self.raw_data.get("text", text))
285
+ self.is_pure_emoji = bool(self.is_emoji and self.emoji_count == len(self.text))
286
+ self.is_photo = None
287
+ self.is_video = None
288
+ self.is_audio = None
289
+ self.is_voice = None
290
+ self.is_document = None
291
+ self.is_archive = None
292
+ self.is_executable = None
293
+ self.is_font = None
294
+ self.metadata = self.raw_data.get("metadata", {})
295
+ self.is_metadata = self.metadata
296
+ self.meta_parts = self.metadata.get("meta_data_parts", [])
297
+ self.has_metadata = bool(self.meta_parts)
298
+ self.meta_types = [part.get("type") for part in self.meta_parts] if self.has_metadata else []
299
+ self.is_bold = "Bold" in self.meta_types
300
+ self.is_italic = "Italic" in self.meta_types
301
+ self.is_strike = "Strike" in self.meta_types
302
+ self.is_underline = "Underline" in self.meta_types
303
+ self.is_quote = "Quote" in self.meta_types
304
+ self.is_spoiler = "Spoiler" in self.meta_types
305
+ self.is_pre = "Pre" in self.meta_types
306
+ self.is_mono = "Mono" in self.meta_types
307
+ self.is_link_meta = "Link" in self.meta_types
308
+ self.meta_links = [part.get("link_url") for part in self.meta_parts if part.get("type") == "Link"]
309
+ self.meta_link_positions = [
310
+ {"from": part.get("from_index"), "length": part.get("length"), "url": part.get("link_url")}
311
+ for part in self.meta_parts if part.get("type") == "Link"
312
+ ]
313
+ self.has_link = contains_link_or_mention(self.text) or self.is_link_meta
314
+ self.is_formatted = any([
315
+ self.is_bold,
316
+ self.is_italic,
317
+ self.is_strike,
318
+ self.is_underline,
319
+ self.is_quote,
320
+ self.is_spoiler,
321
+ self.is_pre,
322
+ self.is_mono
323
+ ])
222
324
  self.sender_id: str = self.raw_data.get("sender_id", sender_id)
223
325
  self.time: str = self.raw_data.get("time")
224
326
  self.is_edited: bool = self.raw_data.get("is_edited", False)
@@ -336,14 +438,40 @@ class Message:
336
438
  )
337
439
 
338
440
 
339
- def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
340
- return self.bot._post("sendPoll", {
441
+ def reply_poll(
442
+ self,
443
+ question: str,
444
+ options: List[str],
445
+ type: Literal['Regular', 'Quiz'] = "Regular",
446
+ allows_multiple_answers: bool = False,
447
+ is_anonymous: bool = True,
448
+ correct_option_index: Optional[int] = None,
449
+ hint: Optional[str] = None,
450
+ reply_to_message_id: Optional[str] = None,
451
+ disable_notification: bool = False,
452
+ show_results: bool = False,
453
+ inline_keypad: Optional[Dict[str, Any]] = None,
454
+ chat_keypad: Optional[Dict[str, Any]] = None,
455
+ chat_keypad_type: Optional[Literal['New', 'Remove', 'None']] = None,
456
+ **kwargs
457
+ ) -> dict:
458
+ payload = {
341
459
  "chat_id": self.chat_id,
342
460
  "question": question,
343
461
  "options": options,
344
- "reply_to_message_id": self.message_id,
345
- **kwargs
346
- })
462
+ "type": type,
463
+ "allows_multiple_answers": allows_multiple_answers,
464
+ "is_anonymous": is_anonymous,
465
+ "correct_option_index": correct_option_index,
466
+ "hint": hint,
467
+ "reply_to_message_id": self.message_id if not reply_to_message_id else reply_to_message_id,
468
+ "disable_notification": disable_notification,
469
+ "show_results": show_results,
470
+ "inline_keypad": inline_keypad,
471
+ "chat_keypad": chat_keypad,
472
+ "chat_keypad_type": chat_keypad_type,
473
+ }
474
+ return self.bot._post("sendPoll", {key: value for key, value in payload.items() if value is not None}, **kwargs)
347
475
 
348
476
 
349
477
  def reply_document(
@@ -617,13 +745,69 @@ class InlineMessage:
617
745
  if self.chat_id not in self.bot.sessions:
618
746
  self.bot.sessions[self.chat_id] = {}
619
747
  return self.bot.sessions[self.chat_id]
620
- def reply(self, text: str, **kwargs):
621
- return self.bot.send_message(
622
- self.chat_id,
623
- text,
624
- reply_to_message_id=self.message_id,
625
- **kwargs
626
- )
748
+
749
+ def reply(self, text: str, delete_after: int = None, **kwargs):
750
+ async def _reply_async():
751
+ send_func = self.bot.send_message
752
+ if inspect.iscoroutinefunction(send_func):
753
+ msg = await send_func(
754
+ self.chat_id,
755
+ text,
756
+ reply_to_message_id=self.message_id,
757
+ delete_after=delete_after,
758
+ **kwargs
759
+ )
760
+ else:
761
+ msg = send_func(
762
+ self.chat_id,
763
+ text,
764
+ reply_to_message_id=self.message_id,
765
+ delete_after=delete_after,
766
+ **kwargs
767
+ )
768
+ class Pick:
769
+ def __init__(self, bot, chat_id, message_id):
770
+ self.bot = bot
771
+ self.chat_id = chat_id
772
+ self.message_id = message_id
773
+
774
+ def edit(self, new_text):
775
+ async def _edit():
776
+ func = self.bot.edit_message_text
777
+ if inspect.iscoroutinefunction(func):
778
+ await func(self.chat_id, self.message_id, new_text)
779
+ else:
780
+ func(self.chat_id, self.message_id, new_text)
781
+
782
+ try:
783
+ loop = asyncio.get_running_loop()
784
+ if loop.is_running():
785
+ return asyncio.create_task(_edit())
786
+ except RuntimeError:
787
+ return asyncio.run(_edit())
788
+
789
+ def delete(self):
790
+ async def _delete():
791
+ func = self.bot.delete_message
792
+ if inspect.iscoroutinefunction(func):
793
+ await func(self.chat_id, self.message_id)
794
+ else:
795
+ func(self.chat_id, self.message_id)
796
+ try:
797
+ loop = asyncio.get_running_loop()
798
+ if loop.is_running():
799
+ return asyncio.create_task(_delete())
800
+ except RuntimeError:
801
+ return asyncio.run(_delete())
802
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
803
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
804
+ return Pick(self.bot, chat_id, message_id)
805
+ try:
806
+ loop = asyncio.get_running_loop()
807
+ if loop.is_running():
808
+ return asyncio.create_task(_reply_async())
809
+ except RuntimeError:
810
+ return asyncio.run(_reply_async())
627
811
  def answer(self, text: str, **kwargs):
628
812
  return self.bot.send_message(
629
813
  self.chat_id,
@@ -631,6 +815,7 @@ class InlineMessage:
631
815
  reply_to_message_id=self.message_id,
632
816
  **kwargs
633
817
  )
818
+
634
819
 
635
820
  def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
636
821
  return self.bot._post("sendPoll", {
@@ -841,4 +1026,12 @@ class InlineMessage:
841
1026
  return self.bot.delete_message(
842
1027
  chat_id=self.chat_id,
843
1028
  message_id=self.message_id
844
- )
1029
+ )
1030
+ @hybrid_property
1031
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
1032
+ @hybrid_property
1033
+ async def name(self):return await self.bot.get_name(self.chat_id)
1034
+ @hybrid_property
1035
+ async def username(self):return await self.bot.get_username(self.chat_id)
1036
+ @hybrid_property
1037
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
@@ -291,6 +291,35 @@ class Message:
291
291
  self.is_archive = None
292
292
  self.is_executable = None
293
293
  self.is_font = None
294
+ self.metadata = self.raw_data.get("metadata", {})
295
+ self.meta_parts = self.metadata.get("meta_data_parts", [])
296
+ self.has_metadata = bool(self.meta_parts)
297
+ self.meta_types = [part.get("type") for part in self.meta_parts] if self.has_metadata else []
298
+ self.is_bold = "Bold" in self.meta_types
299
+ self.is_italic = "Italic" in self.meta_types
300
+ self.is_strike = "Strike" in self.meta_types
301
+ self.is_underline = "Underline" in self.meta_types
302
+ self.is_quote = "Quote" in self.meta_types
303
+ self.is_spoiler = "Spoiler" in self.meta_types
304
+ self.is_pre = "Pre" in self.meta_types
305
+ self.is_mono = "Mono" in self.meta_types
306
+ self.is_link_meta = "Link" in self.meta_types
307
+ self.meta_links = [part.get("link_url") for part in self.meta_parts if part.get("type") == "Link"]
308
+ self.meta_link_positions = [
309
+ {"from": part.get("from_index"), "length": part.get("length"), "url": part.get("link_url")}
310
+ for part in self.meta_parts if part.get("type") == "Link"
311
+ ]
312
+ self.has_link = contains_link_or_mention(self.text) or self.is_link_meta
313
+ self.is_formatted = any([
314
+ self.is_bold,
315
+ self.is_italic,
316
+ self.is_strike,
317
+ self.is_underline,
318
+ self.is_quote,
319
+ self.is_spoiler,
320
+ self.is_pre,
321
+ self.is_mono
322
+ ])
294
323
  self.sender_id: str = self.raw_data.get("sender_id", sender_id)
295
324
  self.time: str = self.raw_data.get("time")
296
325
  self.is_edited: bool = self.raw_data.get("is_edited", False)
@@ -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='7.1.9',
16
+ version='7.1.10',
17
17
  description=(
18
18
  "Rubika: A Python library for interacting with the Rubika Bot API. "
19
19
  "This library provides an easy-to-use interface to send messages, polls, "
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