Rubka 7.1.3__tar.gz → 7.1.5__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-7.1.3 → rubka-7.1.5}/PKG-INFO +3 -3
  2. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/PKG-INFO +3 -3
  3. {rubka-7.1.3 → rubka-7.1.5}/rubka/api.py +0 -6
  4. {rubka-7.1.3 → rubka-7.1.5}/rubka/asynco.py +89 -48
  5. {rubka-7.1.3 → rubka-7.1.5}/rubka/context.py +105 -14
  6. {rubka-7.1.3 → rubka-7.1.5}/rubka/rubino.py +13 -1
  7. {rubka-7.1.3 → rubka-7.1.5}/setup.py +11 -3
  8. {rubka-7.1.3 → rubka-7.1.5}/README.md +0 -0
  9. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/SOURCES.txt +0 -0
  10. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/dependency_links.txt +0 -0
  11. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/entry_points.txt +0 -0
  12. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/not-zip-safe +0 -0
  13. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/requires.txt +0 -0
  14. {rubka-7.1.3 → rubka-7.1.5}/Rubka.egg-info/top_level.txt +0 -0
  15. {rubka-7.1.3 → rubka-7.1.5}/rubka/__init__.py +0 -0
  16. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/__init__.py +0 -0
  17. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/client/__init__.py +0 -0
  18. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/client/client.py +0 -0
  19. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/crypto/__init__.py +0 -0
  20. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/crypto/crypto.py +0 -0
  21. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/enums.py +0 -0
  22. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/exceptions.py +0 -0
  23. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/methods/__init__.py +0 -0
  24. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/methods/methods.py +0 -0
  25. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/network/__init__.py +0 -0
  26. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/network/helper.py +0 -0
  27. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/network/network.py +0 -0
  28. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/network/socket.py +0 -0
  29. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/sessions/__init__.py +0 -0
  30. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/sessions/sessions.py +0 -0
  31. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/types/__init__.py +0 -0
  32. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
  33. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/types/socket/message.py +0 -0
  34. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/utils/__init__.py +0 -0
  35. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/utils/configs.py +0 -0
  36. {rubka-7.1.3 → rubka-7.1.5}/rubka/adaptorrubka/utils/utils.py +0 -0
  37. {rubka-7.1.3 → rubka-7.1.5}/rubka/button.py +0 -0
  38. {rubka-7.1.3 → rubka-7.1.5}/rubka/config.py +0 -0
  39. {rubka-7.1.3 → rubka-7.1.5}/rubka/decorators.py +0 -0
  40. {rubka-7.1.3 → rubka-7.1.5}/rubka/exceptions.py +0 -0
  41. {rubka-7.1.3 → rubka-7.1.5}/rubka/filters.py +0 -0
  42. {rubka-7.1.3 → rubka-7.1.5}/rubka/helpers.py +0 -0
  43. {rubka-7.1.3 → rubka-7.1.5}/rubka/jobs.py +0 -0
  44. {rubka-7.1.3 → rubka-7.1.5}/rubka/keyboards.py +0 -0
  45. {rubka-7.1.3 → rubka-7.1.5}/rubka/keypad.py +0 -0
  46. {rubka-7.1.3 → rubka-7.1.5}/rubka/logger.py +0 -0
  47. {rubka-7.1.3 → rubka-7.1.5}/rubka/tv.py +0 -0
  48. {rubka-7.1.3 → rubka-7.1.5}/rubka/update.py +0 -0
  49. {rubka-7.1.3 → rubka-7.1.5}/rubka/utils.py +0 -0
  50. {rubka-7.1.3 → rubka-7.1.5}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 7.1.3
4
- Summary: rubika A Python library for interacting with Rubika Bot API.
3
+ Version: 7.1.5
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
7
7
  Author: Mahdi Ahmadi
@@ -12,7 +12,7 @@ License: MIT
12
12
  Project-URL: Bug Tracker, https://t.me/Bprogrammer
13
13
  Project-URL: Documentation, https://github.com/Mahdy-Ahmadi/rubka/blob/main/README.md
14
14
  Project-URL: Source Code, https://github.com/Mahdy-Ahmadi/Rubka
15
- Keywords: rubika bot api library chat messaging rubpy pyrubi rubigram
15
+ Keywords: rubika bot api library chat messaging rubpy pyrubi rubigram rubika_bot rubika_api fast_rub
16
16
  Classifier: Development Status :: 5 - Production/Stable
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Programming Language :: Python :: 3
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 7.1.3
4
- Summary: rubika A Python library for interacting with Rubika Bot API.
3
+ Version: 7.1.5
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
7
7
  Author: Mahdi Ahmadi
@@ -12,7 +12,7 @@ License: MIT
12
12
  Project-URL: Bug Tracker, https://t.me/Bprogrammer
13
13
  Project-URL: Documentation, https://github.com/Mahdy-Ahmadi/rubka/blob/main/README.md
14
14
  Project-URL: Source Code, https://github.com/Mahdy-Ahmadi/Rubka
15
- Keywords: rubika bot api library chat messaging rubpy pyrubi rubigram
15
+ Keywords: rubika bot api library chat messaging rubpy pyrubi rubigram rubika_bot rubika_api fast_rub
16
16
  Classifier: Development Status :: 5 - Production/Stable
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Programming Language :: Python :: 3
@@ -61,13 +61,7 @@ def check_rubka_version():
61
61
  latest_version = get_latest_version(package_name)
62
62
  if latest_version is None:return
63
63
  if installed_version != latest_version:
64
- print(f"\n\nWARNING: Your installed version of '{package_name}' is OUTDATED and may cause errors or security risks!")
65
- print(f"Installed version : {installed_version}")
66
- print(f"Latest available version : {latest_version}")
67
- print(f"Please update IMMEDIATELY by running:")
68
64
  print(f"\npip install {package_name}=={latest_version}\n")
69
- print(f"Not updating may lead to malfunctions or incompatibility.")
70
- print(f"To see new methods : @rubka_library\n\n")
71
65
 
72
66
  check_rubka_version()
73
67
  def show_last_six_words(text):
@@ -72,14 +72,16 @@ async def check_rubka_version():
72
72
  return
73
73
 
74
74
  if installed_version != latest_version:
75
- print(f"\n\nWARNING: Your installed version of '{package_name}' is OUTDATED and may cause errors or security risks!")
76
- print(f"Installed version : {installed_version}")
77
- print(f"Latest available version : {latest_version}")
78
- print(f"Please update IMMEDIATELY by running:")
79
- print(f"\npip install {package_name}=={latest_version}\n")
80
- print("Not updating may lead to malfunctions or incompatibility.")
81
- print("To see new methods : @rubka_library\n\n")
82
-
75
+ print(f"CRITICAL WARNING: Your installed version of '{package_name}' is outdated.")
76
+ print("This poses a serious risk to stability, security, and compatibility with current features.")
77
+ print(f"- Installed version : {installed_version}")
78
+ print(f"- Latest version : {latest_version}")
79
+ print("\nImmediate action is required.")
80
+ print(f"Run the following command to update safely:")
81
+ print(f"\n pip install {package_name}=={latest_version}\n")
82
+ print("Delaying this update may result in unexpected crashes, data loss, or broken functionality.")
83
+ print("Stay up-to-date to ensure full support and access to the latest improvements.")
84
+ print("For new methods and updates, visit: @rubka_library\n")
83
85
 
84
86
 
85
87
 
@@ -141,11 +143,12 @@ safeSendMode ensures reliable message sending even if replying by message_id fai
141
143
  max_cache_size and max_msg_age help manage duplicate message processing efficiently.
142
144
  """
143
145
 
144
- def __init__(self, token: str, session_name: str = None, auth: str = None, Key: str = None, platform: str = "web", web_hook: str = None, timeout: int = 10, show_progress: bool = False, raise_errors: bool = True,proxy: str = None,retries: int = 2,retry_delay: float = 0.5,user_agent: str = None,safeSendMode = False,max_cache_size: int = 2000,max_msg_age : int = 60):
146
+ def __init__(self, token: str, session_name: str = None, auth: str = None, Key: str = None, platform: str = "web", web_hook: str = None, timeout: int = 10, show_progress: bool = False, raise_errors: bool = True,proxy: str = None,retries: int = 2,retry_delay: float = 0.5,user_agent: str = None,safeSendMode = False,max_cache_size: int = 2000,max_msg_age : int = 60,chunk_size : int = 64 * 1024):
145
147
  self.token = token
146
148
  self._inline_query_handlers: List[dict] = []
147
149
  self.timeout = timeout
148
150
  self.auth = auth
151
+ self.chunk_size = chunk_size
149
152
  self.safeSendMode = safeSendMode
150
153
  self.user_agent = user_agent
151
154
  self.proxy = proxy
@@ -194,9 +197,8 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
194
197
  async with session.get(self.web_hook, timeout=self.timeout) as response:
195
198
  response.raise_for_status()
196
199
  data = await response.json()
197
- print(data)
200
+ if data:print(f"[INFO] Retrieving WebHook URL information...")
198
201
  json_url = data.get('url', self.web_hook)
199
- print(self.web_hook)
200
202
  for endpoint_type in [
201
203
  "ReceiveUpdate",
202
204
  "ReceiveInlineMessage",
@@ -205,7 +207,8 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
205
207
  "SearchSelectionItems"
206
208
  ]:
207
209
  result = await self.update_bot_endpoint(self.web_hook, endpoint_type)
208
- print(result)
210
+ if result['status'] =="OK":print(f"✔ Set endpoint type to '{endpoint_type}' — Operation succeeded with status: {result['status']}")
211
+ else:print(f"[ERROR] Failed to set endpoint type '{endpoint_type}': Status code {result['status']}")
209
212
  self.web_hook = json_url
210
213
  except Exception as e:
211
214
  logger.error(f"Failed to set webhook from {self.web_hook}: {e}")
@@ -1693,7 +1696,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1693
1696
  inline_keypad: Optional[Dict[str, Any]] = None,
1694
1697
  disable_notification: bool = False,
1695
1698
  reply_to_message_id: Optional[str] = None,
1696
- chat_keypad_type: Optional[Literal["New", "Removed"]] = None,
1699
+ chat_keypad_type: Optional[Literal["New", "Remove"]] = None,
1697
1700
  delete_after : int = None
1698
1701
  ) -> Dict[str, Any]:
1699
1702
  payload = {
@@ -1857,48 +1860,52 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1857
1860
 
1858
1861
  async def close_poll(self, chat_id: str, message_id: str) -> Dict[str, Any]:
1859
1862
  return await self._post("closePoll", {"chat_id": chat_id, "message_id": message_id})
1860
- async def send_location(self, chat_id: str, latitude: str, longitude: str, disable_notification: bool = False, inline_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Removed"]] = None) -> Dict[str, Any]:
1863
+ async def send_location(self, chat_id: str, latitude: str, longitude: str, disable_notification: bool = False, inline_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Remove"]] = None) -> Dict[str, Any]:
1861
1864
  payload = {"chat_id": chat_id, "latitude": latitude, "longitude": longitude, "disable_notification": disable_notification}
1862
1865
  if inline_keypad: payload["inline_keypad"] = inline_keypad
1863
1866
  if reply_to_message_id: payload["reply_to_message_id"] = reply_to_message_id
1864
1867
  if chat_keypad_type: payload["chat_keypad_type"] = chat_keypad_type
1865
1868
  return await self._post("sendLocation", {k: v for k, v in payload.items() if v is not None})
1866
1869
  async def upload_media_file(self, upload_url: str, name: str, path: Union[str, Path]) -> str:
1867
- is_temp_file = False
1868
1870
  session = await self._get_session()
1871
+ is_temp_file = False
1869
1872
  if isinstance(path, str) and path.startswith("http"):
1870
1873
  async with session.get(path) as response:
1871
1874
  if response.status != 200:
1872
1875
  raise Exception(f"Failed to download file from URL ({response.status})")
1873
1876
  content = await response.read()
1874
- with tempfile.NamedTemporaryFile(delete=False) as temp_file:
1875
- temp_file.write(content)
1876
- path = temp_file.name
1877
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
1878
+ tmp.write(content)
1879
+ path = tmp.name
1877
1880
  is_temp_file = True
1881
+
1878
1882
  file_size = os.path.getsize(path)
1879
- progress_bar = tqdm(total=file_size, unit='B', unit_scale=True, unit_divisor=1024, desc=f'Uploading : {name}', bar_format='{l_bar}{bar:100}{r_bar}', colour='cyan', disable=not self.show_progress)
1880
- async def file_progress_generator(file_path, chunk_size=8192):
1883
+ chunk_size = self.chunk_size
1884
+
1885
+ progress_bar = tqdm(total=file_size, unit='B', unit_scale=True, unit_divisor=1024,
1886
+ desc=f'Uploading: {name}', colour='cyan', disable=not getattr(self, 'show_progress', True))
1887
+
1888
+ async def file_generator(file_path):
1881
1889
  async with aiofiles.open(file_path, 'rb') as f:
1882
- while True:
1883
- chunk = await f.read(chunk_size)
1884
- if not chunk:
1885
- break
1890
+ while chunk := await f.read(chunk_size):
1886
1891
  progress_bar.update(len(chunk))
1887
1892
  yield chunk
1888
- data = aiohttp.FormData()
1889
- data.add_field('file', file_progress_generator(path), filename=name, content_type='application/octet-stream')
1893
+
1894
+ form = aiohttp.FormData()
1895
+ form.add_field('file', file_generator(path), filename=name, content_type='application/octet-stream')
1896
+
1890
1897
  try:
1891
- async with session.post(upload_url, data=data) as response:
1898
+ async with session.post(upload_url, data=form, timeout=aiohttp.ClientTimeout(total=None)) as response:
1892
1899
  progress_bar.close()
1893
1900
  if response.status != 200:
1894
- raise Exception(f"Upload failed ({response.status}): {await response.text()}")
1895
-
1896
- json_data = await response.json()
1897
- if is_temp_file:
1898
- os.remove(path)
1899
- return json_data.get('data', {}).get('file_id')
1900
- except :
1901
- raise FeatureNotAvailableError(f"files is not currently supported by the server.")
1901
+ text = await response.text()
1902
+ raise Exception(f"Upload failed ({response.status}): {text}")
1903
+ return (await response.json()).get('data', {}).get('file_id')
1904
+ except Exception as e:
1905
+ raise FeatureNotAvailableError(f"File upload not supported: {e}")
1906
+ finally:
1907
+ if is_temp_file:
1908
+ os.remove(path)
1902
1909
  def get_extension(content_type: str) -> str:
1903
1910
  ext = mimetypes.guess_extension(content_type)
1904
1911
  return ext if ext else ''
@@ -1984,7 +1991,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1984
1991
  raise ValueError(f"Invalid media type. Must be one of {allowed}")
1985
1992
  result = await self._post("requestSendFile", {"type": media_type})
1986
1993
  return result.get("data", {}).get("upload_url")
1987
- 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]:
1994
+ 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", "Remove", "None"]] = "None") -> Dict[str, Any]:
1988
1995
  payload = {"chat_id": chat_id, "file_id": file_id, "text": text, "disable_notification": disable_notification, "chat_keypad_type": chat_keypad_type}
1989
1996
  if chat_keypad: payload["chat_keypad"] = chat_keypad
1990
1997
  if inline_keypad: payload["inline_keypad"] = inline_keypad
@@ -2016,11 +2023,11 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2016
2023
  if not file_id:
2017
2024
  raise ValueError("Either path or file_id must be provided.")
2018
2025
  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)
2019
- 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]:
2026
+ 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", "Remove", "None"]] = "None") -> Dict[str, Any]:
2020
2027
  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)
2021
- async def send_file(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]:
2028
+ async def send_file(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", "Remove", "None"]] = "None") -> Dict[str, Any]:
2022
2029
  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)
2023
- 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]:
2030
+ 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", "Remove", "None"]] = "None") -> Dict[str, Any]:
2024
2031
  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)
2025
2032
  async def send_music(
2026
2033
  self,
@@ -2033,7 +2040,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2033
2040
  chat_keypad: Optional[Dict[str, Any]] = None,
2034
2041
  reply_to_message_id: Optional[str] = None,
2035
2042
  disable_notification: bool = False,
2036
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
2043
+ chat_keypad_type: Optional[Literal["New", "Remove", "None"]] = "None"
2037
2044
  ) -> Dict[str, Any]:
2038
2045
  valid_extensions = {"ogg", "oga", "opus", "flac"}
2039
2046
  extension = "flac"
@@ -2078,7 +2085,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2078
2085
  chat_keypad: Optional[Dict[str, Any]] = None,
2079
2086
  reply_to_message_id: Optional[str] = None,
2080
2087
  disable_notification: bool = False,
2081
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
2088
+ chat_keypad_type: Optional[Literal["New", "Remove", "None"]] = "None"
2082
2089
  ) -> Dict[str, Any]:
2083
2090
  valid_extensions = {"gif"}
2084
2091
  extension = "gif"
@@ -2172,7 +2179,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2172
2179
  async def set_chat_photo(self, chat_id: str, file_id: str) -> Dict[str, Any]:
2173
2180
  return await self._post("editChatPhoto", {"chat_id": chat_id, "file_id": file_id})
2174
2181
  async def remove_chat_photo(self, chat_id: str) -> Dict[str, Any]:
2175
- return await self._post("editChatPhoto", {"chat_id": chat_id, "file_id": "Removed"})
2182
+ return await self._post("editChatPhoto", {"chat_id": chat_id, "file_id": "Remove"})
2176
2183
  async def add_member_chat(self, chat_id: str, user_ids: list[str]) -> Dict[str, Any]:
2177
2184
  return await self._post("addChatMembers", {"chat_id": chat_id, "member_ids": user_ids})
2178
2185
  async def ban_member_chat(self, chat_id: str, user_id: str) -> Dict[str, Any]:
@@ -2221,24 +2228,58 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2221
2228
  async def update_bot_endpoint(self, url: str, type: str) -> Dict[str, Any]:
2222
2229
  return await self._post("updateBotEndpoints", {"url": url, "type": type})
2223
2230
  async def remove_keypad(self, chat_id: str) -> Dict[str, Any]:
2224
- return await self._post("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "Removed"})
2231
+ return await self._post("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "Remove"})
2225
2232
  async def edit_chat_keypad(self, chat_id: str, chat_keypad: Dict[str, Any]) -> Dict[str, Any]:
2226
2233
  return await self._post("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "New", "chat_keypad": chat_keypad})
2227
2234
  async def send_contact(self, chat_id: str, first_name: str, last_name: str, phone_number: str) -> Dict[str, Any]:
2228
2235
  return await self._post("sendContact", {"chat_id": chat_id, "first_name": first_name, "last_name": last_name, "phone_number": phone_number})
2229
2236
  async def get_chat(self, chat_id: str) -> Dict[str, Any]:
2230
2237
  return await self._post("getChat", {"chat_id": chat_id})
2231
- 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]:
2238
+ 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", "Remove", "None"]] = "None") -> Dict[str, Any]:
2232
2239
  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)
2233
- 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]:
2240
+ 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", "Remove", "None"]] = "None") -> Dict[str, Any]:
2234
2241
  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)
2235
- 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]:
2242
+ 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", "Remove", "None"]] = "None") -> Dict[str, Any]:
2236
2243
  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)
2237
2244
  def get_all_member(self, channel_guid: str, search_text: str = None, start_id: str = None, just_get_guids: bool = False):
2238
2245
  client = self._get_client()
2239
2246
  return client.get_all_members(channel_guid, search_text, start_id, just_get_guids)
2240
- async def send_poll(self, chat_id: str, question: str, options: List[str]) -> Dict[str, Any]:
2241
- return await self._post("sendPoll", {"chat_id": chat_id, "question": question, "options": options})
2247
+ async def send_poll(
2248
+ self,
2249
+ chat_id: str,
2250
+ question: str,
2251
+ options: List[str],
2252
+ type: Literal["Regular", "Quiz"] = "Regular",
2253
+ allows_multiple_answers: bool = False,
2254
+ is_anonymous: bool = True,
2255
+ correct_option_index: Optional[int] = None,
2256
+ hint: Optional[str] = None,
2257
+ reply_to_message_id: Optional[str] = None,
2258
+ disable_notification: bool = False,
2259
+ show_results : bool = False,
2260
+ inline_keypad : Optional[Dict[str, Any]] = None,
2261
+ chat_keypad: Optional[Dict[str, Any]] = None,
2262
+ chat_keypad_type: Optional[Literal["New", "Remove", "None"]] = None,
2263
+
2264
+ ) -> AttrDict:
2265
+ return await self._post(
2266
+ "sendPoll", {
2267
+ "chat_id": chat_id,
2268
+ "question": question,
2269
+ "options": options,
2270
+ "type": type,
2271
+ "allows_multiple_answers": allows_multiple_answers,
2272
+ "is_anonymous": is_anonymous,
2273
+ "correct_option_index": correct_option_index,
2274
+ "explanation": hint,
2275
+ "show_results":show_results,
2276
+ "reply_to_message_id": reply_to_message_id,
2277
+ "disable_notification": disable_notification,
2278
+ "chat_keypad": chat_keypad,
2279
+ "inline_keypad":inline_keypad,
2280
+ "chat_keypad_type": chat_keypad_type,
2281
+ }
2282
+ )
2242
2283
  async def check_join(self, channel_guid: str, chat_id: str = None) -> Union[bool, list[str]]:
2243
2284
  client = self._get_client()
2244
2285
  if chat_id:
@@ -1,6 +1,6 @@
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
6
  class File:
@@ -336,14 +336,40 @@ class Message:
336
336
  )
337
337
 
338
338
 
339
- def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
340
- return self.bot._post("sendPoll", {
339
+ def reply_poll(
340
+ self,
341
+ question: str,
342
+ options: List[str],
343
+ type: Literal['Regular', 'Quiz'] = "Regular",
344
+ allows_multiple_answers: bool = False,
345
+ is_anonymous: bool = True,
346
+ correct_option_index: Optional[int] = None,
347
+ hint: Optional[str] = None,
348
+ reply_to_message_id: Optional[str] = None,
349
+ disable_notification: bool = False,
350
+ show_results: bool = False,
351
+ inline_keypad: Optional[Dict[str, Any]] = None,
352
+ chat_keypad: Optional[Dict[str, Any]] = None,
353
+ chat_keypad_type: Optional[Literal['New', 'Remove', 'None']] = None,
354
+ **kwargs
355
+ ) -> dict:
356
+ payload = {
341
357
  "chat_id": self.chat_id,
342
358
  "question": question,
343
359
  "options": options,
344
- "reply_to_message_id": self.message_id,
345
- **kwargs
346
- })
360
+ "type": type,
361
+ "allows_multiple_answers": allows_multiple_answers,
362
+ "is_anonymous": is_anonymous,
363
+ "correct_option_index": correct_option_index,
364
+ "hint": hint,
365
+ "reply_to_message_id": self.message_id if not reply_to_message_id else reply_to_message_id,
366
+ "disable_notification": disable_notification,
367
+ "show_results": show_results,
368
+ "inline_keypad": inline_keypad,
369
+ "chat_keypad": chat_keypad,
370
+ "chat_keypad_type": chat_keypad_type,
371
+ }
372
+ return self.bot._post("sendPoll", {key: value for key, value in payload.items() if value is not None}, **kwargs)
347
373
 
348
374
 
349
375
  def reply_document(
@@ -617,13 +643,69 @@ class InlineMessage:
617
643
  if self.chat_id not in self.bot.sessions:
618
644
  self.bot.sessions[self.chat_id] = {}
619
645
  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
- )
646
+
647
+ def reply(self, text: str, delete_after: int = None, **kwargs):
648
+ async def _reply_async():
649
+ send_func = self.bot.send_message
650
+ if inspect.iscoroutinefunction(send_func):
651
+ msg = await send_func(
652
+ self.chat_id,
653
+ text,
654
+ reply_to_message_id=self.message_id,
655
+ delete_after=delete_after,
656
+ **kwargs
657
+ )
658
+ else:
659
+ msg = send_func(
660
+ self.chat_id,
661
+ text,
662
+ reply_to_message_id=self.message_id,
663
+ delete_after=delete_after,
664
+ **kwargs
665
+ )
666
+ class Pick:
667
+ def __init__(self, bot, chat_id, message_id):
668
+ self.bot = bot
669
+ self.chat_id = chat_id
670
+ self.message_id = message_id
671
+
672
+ def edit(self, new_text):
673
+ async def _edit():
674
+ func = self.bot.edit_message_text
675
+ if inspect.iscoroutinefunction(func):
676
+ await func(self.chat_id, self.message_id, new_text)
677
+ else:
678
+ func(self.chat_id, self.message_id, new_text)
679
+
680
+ try:
681
+ loop = asyncio.get_running_loop()
682
+ if loop.is_running():
683
+ return asyncio.create_task(_edit())
684
+ except RuntimeError:
685
+ return asyncio.run(_edit())
686
+
687
+ def delete(self):
688
+ async def _delete():
689
+ func = self.bot.delete_message
690
+ if inspect.iscoroutinefunction(func):
691
+ await func(self.chat_id, self.message_id)
692
+ else:
693
+ func(self.chat_id, self.message_id)
694
+ try:
695
+ loop = asyncio.get_running_loop()
696
+ if loop.is_running():
697
+ return asyncio.create_task(_delete())
698
+ except RuntimeError:
699
+ return asyncio.run(_delete())
700
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
701
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
702
+ return Pick(self.bot, chat_id, message_id)
703
+ try:
704
+ loop = asyncio.get_running_loop()
705
+ if loop.is_running():
706
+ return asyncio.create_task(_reply_async())
707
+ except RuntimeError:
708
+ return asyncio.run(_reply_async())
627
709
  def answer(self, text: str, **kwargs):
628
710
  return self.bot.send_message(
629
711
  self.chat_id,
@@ -631,6 +713,7 @@ class InlineMessage:
631
713
  reply_to_message_id=self.message_id,
632
714
  **kwargs
633
715
  )
716
+
634
717
 
635
718
  def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
636
719
  return self.bot._post("sendPoll", {
@@ -841,4 +924,12 @@ class InlineMessage:
841
924
  return self.bot.delete_message(
842
925
  chat_id=self.chat_id,
843
926
  message_id=self.message_id
844
- )
927
+ )
928
+ @hybrid_property
929
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
930
+ @hybrid_property
931
+ async def name(self):return await self.bot.get_name(self.chat_id)
932
+ @hybrid_property
933
+ async def username(self):return await self.bot.get_username(self.chat_id)
934
+ @hybrid_property
935
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
@@ -1177,4 +1177,16 @@ class Bot():
1177
1177
  "post_id": post_id,
1178
1178
  "post_profile_id": post_profile_id,
1179
1179
  "profile_id": profile_id
1180
- },methode="addPostViewTime")['data']
1180
+ },methode="addPostViewTime")['data']
1181
+ def get_Profile_Posts(self,target_profile_id:str,max_id:str,sort:str="FromMax",limit:str=10):
1182
+ return self._reuests_post(data={
1183
+ "limit": limit,
1184
+ "max_id": max_id,
1185
+ "sort":sort,
1186
+ "target_profile_id": target_profile_id,
1187
+ },methode="getProfilePosts")['data']
1188
+ def get_info_Post(self,url_post:str,profile_id:str=None):
1189
+ return self._reuests_post(data={
1190
+ "share_string": url_post,
1191
+ "profile_id": profile_id,
1192
+ },methode="getPostByShareLink")['data']
@@ -13,8 +13,16 @@ with open("README.md", "r", encoding="utf-8") as f:
13
13
 
14
14
  setup(
15
15
  name='Rubka',
16
- version='7.1.3',
17
- description='rubika A Python library for interacting with Rubika Bot API.',
16
+ version='7.1.5',
17
+ description=(
18
+ "Rubika: A Python library for interacting with the Rubika Bot API. "
19
+ "This library provides an easy-to-use interface to send messages, polls, "
20
+ "stickers, media files, manage groups and channels, handle inline keyboards, "
21
+ "and implement advanced bot features like subscription management, "
22
+ "user authentication, and message handling. "
23
+ "Ideal for developers looking to automate and extend their Rubika bots with Python."
24
+ ),
25
+
18
26
  long_description=long_description,
19
27
  long_description_content_type='text/markdown',
20
28
  author='Mahdi Ahmadi',
@@ -56,7 +64,7 @@ setup(
56
64
  "rubka=rubka.__main__:main",
57
65
  ],
58
66
  },
59
- keywords="rubika bot api library chat messaging rubpy pyrubi rubigram",
67
+ keywords="rubika bot api library chat messaging rubpy pyrubi rubigram rubika_bot rubika_api fast_rub",
60
68
  project_urls={
61
69
  "Bug Tracker": "https://t.me/Bprogrammer",
62
70
  "Documentation": "https://github.com/Mahdy-Ahmadi/rubka/blob/main/README.md",
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