Rubka 7.1.18__tar.gz → 7.2.2__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 (51) hide show
  1. {rubka-7.1.18 → rubka-7.2.2}/PKG-INFO +1 -1
  2. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/PKG-INFO +1 -1
  3. {rubka-7.1.18 → rubka-7.2.2}/rubka/__init__.py +1 -2
  4. {rubka-7.1.18 → rubka-7.2.2}/rubka/asynco.py +74 -44
  5. {rubka-7.1.18 → rubka-7.2.2}/rubka/context.py +28 -2
  6. {rubka-7.1.18 → rubka-7.2.2}/rubka/filters.py +13 -4
  7. {rubka-7.1.18 → rubka-7.2.2}/rubka/rubino.py +41 -1
  8. {rubka-7.1.18 → rubka-7.2.2}/setup.py +1 -1
  9. {rubka-7.1.18 → rubka-7.2.2}/README.md +0 -0
  10. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/SOURCES.txt +0 -0
  11. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/dependency_links.txt +0 -0
  12. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/entry_points.txt +0 -0
  13. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/not-zip-safe +0 -0
  14. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/requires.txt +0 -0
  15. {rubka-7.1.18 → rubka-7.2.2}/Rubka.egg-info/top_level.txt +0 -0
  16. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/__init__.py +0 -0
  17. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/client/__init__.py +0 -0
  18. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/client/client.py +0 -0
  19. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/crypto/__init__.py +0 -0
  20. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/crypto/crypto.py +0 -0
  21. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/enums.py +0 -0
  22. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/exceptions.py +0 -0
  23. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/methods/__init__.py +0 -0
  24. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/methods/methods.py +0 -0
  25. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/network/__init__.py +0 -0
  26. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/network/helper.py +0 -0
  27. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/network/network.py +0 -0
  28. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/network/socket.py +0 -0
  29. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/sessions/__init__.py +0 -0
  30. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/sessions/sessions.py +0 -0
  31. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/types/__init__.py +0 -0
  32. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
  33. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/types/socket/message.py +0 -0
  34. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/utils/__init__.py +0 -0
  35. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/utils/configs.py +0 -0
  36. {rubka-7.1.18 → rubka-7.2.2}/rubka/adaptorrubka/utils/utils.py +0 -0
  37. {rubka-7.1.18 → rubka-7.2.2}/rubka/api.py +0 -0
  38. {rubka-7.1.18 → rubka-7.2.2}/rubka/button.py +0 -0
  39. {rubka-7.1.18 → rubka-7.2.2}/rubka/config.py +0 -0
  40. {rubka-7.1.18 → rubka-7.2.2}/rubka/decorators.py +0 -0
  41. {rubka-7.1.18 → rubka-7.2.2}/rubka/exceptions.py +0 -0
  42. {rubka-7.1.18 → rubka-7.2.2}/rubka/helpers.py +0 -0
  43. {rubka-7.1.18 → rubka-7.2.2}/rubka/jobs.py +0 -0
  44. {rubka-7.1.18 → rubka-7.2.2}/rubka/keyboards.py +0 -0
  45. {rubka-7.1.18 → rubka-7.2.2}/rubka/keypad.py +0 -0
  46. {rubka-7.1.18 → rubka-7.2.2}/rubka/logger.py +0 -0
  47. {rubka-7.1.18 → rubka-7.2.2}/rubka/metadata.py +0 -0
  48. {rubka-7.1.18 → rubka-7.2.2}/rubka/tv.py +0 -0
  49. {rubka-7.1.18 → rubka-7.2.2}/rubka/update.py +0 -0
  50. {rubka-7.1.18 → rubka-7.2.2}/rubka/utils.py +0 -0
  51. {rubka-7.1.18 → rubka-7.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 7.1.18
3
+ Version: 7.2.2
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.18
3
+ Version: 7.2.2
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
@@ -66,8 +66,7 @@ Sync = simple, step-by-step, blocking.
66
66
  Async = scalable, concurrent, non-blocking.
67
67
  """
68
68
 
69
- from .api import Robot
70
- from .rubino import Bot
69
+ from .api import Robot,Bot,robot,bot
71
70
  from .exceptions import APIRequestError
72
71
  from .rubino import Bot as rubino
73
72
  from .tv import TV as TvRubika
@@ -280,6 +280,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
280
280
  self.proxy = proxy
281
281
  self.max_msg_age = max_msg_age
282
282
  self.retries = retries
283
+ self.middleware_data = []
283
284
 
284
285
  self.retry_delay = retry_delay
285
286
  self.raise_errors = raise_errors
@@ -541,6 +542,11 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
541
542
 
542
543
  #decorator#
543
544
 
545
+ def middleware(self):
546
+ def decorator(func: Callable[[Any, Union[Message, InlineMessage]], None]):
547
+ self.middleware_data.append(func)
548
+ return func
549
+ return decorator
544
550
  def on_message_private(
545
551
  self,
546
552
  chat_id: Optional[Union[str, List[str]]] = None,
@@ -1842,20 +1848,23 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1842
1848
  reply_to_message_id: Optional[str] = None,
1843
1849
  chat_keypad_type: Optional[Literal["New", "Remove"]] = None,
1844
1850
  delete_after: Optional[int] = None,
1845
- parse_mode: Optional[Literal["HTML", "Markdown"]] = None
1851
+ parse_mode: Optional[Literal["HTML", "Markdown"]] = None,
1852
+ meta_data:Optional[dict] = None
1846
1853
  ) -> Dict[str, Any]:
1847
-
1848
1854
  payload = {
1849
1855
  "chat_id": chat_id,
1850
1856
  "text": text,
1851
1857
  "disable_notification": disable_notification,
1852
1858
  }
1853
- parse_mode_to_use = parse_mode or self.parse_mode
1854
- if text:
1855
- text, metadata = self._parse_text_metadata(text, parse_mode_to_use)
1856
- payload["text"] = text
1857
- if metadata:
1858
- payload["metadata"] = metadata
1859
+ if not meta_data:
1860
+ parse_mode_to_use = parse_mode or self.parse_mode
1861
+ if text:
1862
+ text, metadata = self._parse_text_metadata(text, parse_mode_to_use)
1863
+ payload["text"] = text
1864
+ if metadata:
1865
+ payload["metadata"] = metadata
1866
+ else :
1867
+ payload["metadata"] = meta_data
1859
1868
  if chat_keypad:
1860
1869
  payload["chat_keypad"] = chat_keypad
1861
1870
  payload["chat_keypad_type"] = chat_keypad_type or "New"
@@ -2017,7 +2026,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2017
2026
  if reply_to_message_id: payload["reply_to_message_id"] = reply_to_message_id
2018
2027
  if chat_keypad_type: payload["chat_keypad_type"] = chat_keypad_type
2019
2028
  return await self._post("sendLocation", {k: v for k, v in payload.items() if v is not None})
2020
- async def upload_media_file(self, upload_url: str, name: str, path: Union[str, Path]) -> str:
2029
+ async def upload_media_file(self, upload_url: str, name: str, path: Union[str, Path, bytes]) -> str:
2021
2030
  session = await self._get_session()
2022
2031
  is_temp_file = False
2023
2032
  if isinstance(path, str) and path.startswith("http"):
@@ -2029,12 +2038,17 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2029
2038
  tmp.write(content)
2030
2039
  path = tmp.name
2031
2040
  is_temp_file = True
2041
+ elif isinstance(path, bytes):
2042
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
2043
+ tmp.write(path)
2044
+ path = tmp.name
2045
+ is_temp_file = True
2032
2046
 
2033
2047
  file_size = os.path.getsize(path)
2034
2048
  chunk_size = self.chunk_size
2035
2049
 
2036
2050
  progress_bar = tqdm(total=file_size, unit='B', unit_scale=True, unit_divisor=1024,
2037
- desc=f'Uploading: {name}', colour='cyan', disable=not getattr(self, 'show_progress', True))
2051
+ desc=f'Upload : {name}', colour='blue', disable=not getattr(self, 'show_progress', True))
2038
2052
 
2039
2053
  async def file_generator(file_path):
2040
2054
  async with aiofiles.open(file_path, 'rb') as f:
@@ -2044,7 +2058,6 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2044
2058
 
2045
2059
  form = aiohttp.FormData()
2046
2060
  form.add_field('file', file_generator(path), filename=name, content_type='application/octet-stream')
2047
-
2048
2061
  try:
2049
2062
  async with session.post(upload_url, data=form, timeout=aiohttp.ClientTimeout(total=None)) as response:
2050
2063
  progress_bar.close()
@@ -2053,7 +2066,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2053
2066
  raise Exception(f"Upload failed ({response.status}): {text}")
2054
2067
  return (await response.json()).get('data', {}).get('file_id')
2055
2068
  except Exception as e:
2056
- raise FeatureNotAvailableError(f"File upload not supported: {e}")
2069
+ raise FeatureNotAvailableError(f"File upload not supported : {e}")
2057
2070
  finally:
2058
2071
  if is_temp_file:
2059
2072
  os.remove(path)
@@ -2142,16 +2155,20 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2142
2155
  raise ValueError(f"Invalid media type. Must be one of {allowed}")
2143
2156
  result = await self._post("requestSendFile", {"type": media_type})
2144
2157
  return result.get("data", {}).get("upload_url")
2145
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2158
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2146
2159
  payload = {"chat_id": chat_id, "file_id": file_id, "text": text, "disable_notification": disable_notification, "chat_keypad_type": chat_keypad_type}
2147
2160
  if chat_keypad: payload["chat_keypad"] = chat_keypad
2148
2161
  if inline_keypad: payload["inline_keypad"] = inline_keypad
2149
2162
  if reply_to_message_id: payload["reply_to_message_id"] = str(reply_to_message_id)
2150
- parse_mode_to_use = parse_mode or self.parse_mode
2151
- if text:
2152
- text, metadata = self._parse_text_metadata(text, parse_mode_to_use)
2153
- payload["text"] = text
2154
- if metadata:payload["metadata"] = metadata
2163
+ if not meta_data:
2164
+ parse_mode_to_use = parse_mode or self.parse_mode
2165
+ if text:
2166
+ text, metadata = self._parse_text_metadata(text, parse_mode_to_use)
2167
+ payload["text"] = text
2168
+ if metadata:
2169
+ payload["metadata"] = metadata
2170
+ else :
2171
+ payload["metadata"] = meta_data
2155
2172
  payload["time"] = "10"
2156
2173
  resp = await self._post("sendFile", payload)
2157
2174
  message_id_put = resp["data"]["message_id"]
@@ -2171,26 +2188,26 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2171
2188
  "chat_keypad_type":chat_keypad_type
2172
2189
  }
2173
2190
  return AttrDict(result)
2174
- 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,parse_mode: Optional[Literal["HTML", "Markdown"]] = None):
2191
+ 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,parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None):
2175
2192
  if path:
2176
2193
  file_name = file_name or Path(path).name
2177
2194
  upload_url = await self.get_upload_url(media_type)
2178
2195
  file_id = await self.upload_media_file(upload_url, file_name, path)
2179
2196
  if not file_id:
2180
2197
  raise ValueError("Either path or file_id must be provided.")
2181
- 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,parse_mode=parse_mode)
2182
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2183
- 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,parse_mode=parse_mode)
2184
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2185
- 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,parse_mode=parse_mode)
2186
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2187
- 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,parse_mode=parse_mode)
2188
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2189
- 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,parse_mode=parse_mode)
2190
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2191
- 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,parse_mode=parse_mode)
2192
- 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2193
- 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,parse_mode=parse_mode)
2198
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2199
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2200
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2201
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2202
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2203
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2204
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2205
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2206
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2207
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2208
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2209
+ 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",parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2210
+ 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,parse_mode=parse_mode,meta_data=meta_data)
2194
2211
  async def send_music(
2195
2212
  self,
2196
2213
  chat_id: str,
@@ -2203,7 +2220,8 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2203
2220
  reply_to_message_id: Optional[str] = None,
2204
2221
  disable_notification: bool = False,
2205
2222
  chat_keypad_type: Optional[Literal["New", "Remove", "None"]] = "None",
2206
- parse_mode: Optional[Literal["HTML", "Markdown"]] = None
2223
+ parse_mode: Optional[Literal["HTML", "Markdown"]] = None,
2224
+ meta_data:Optional[dict] = None
2207
2225
  ) -> Dict[str, Any]:
2208
2226
  valid_extensions = {"ogg", "oga", "opus", "flac"}
2209
2227
  extension = "flac"
@@ -2236,7 +2254,8 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2236
2254
  reply_to_message_id,
2237
2255
  disable_notification,
2238
2256
  chat_keypad_type,
2239
- parse_mode=parse_mode
2257
+ parse_mode=parse_mode,
2258
+ meta_data=meta_data
2240
2259
  )
2241
2260
  async def send_gif(
2242
2261
  self,
@@ -2250,7 +2269,8 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2250
2269
  reply_to_message_id: Optional[str] = None,
2251
2270
  disable_notification: bool = False,
2252
2271
  chat_keypad_type: Optional[Literal["New", "Remove", "None"]] = "None",
2253
- parse_mode: Optional[Literal["HTML", "Markdown"]] = None
2272
+ parse_mode: Optional[Literal["HTML", "Markdown"]] = None,
2273
+ meta_data:Optional[dict] = None
2254
2274
  ) -> Dict[str, Any]:
2255
2275
  valid_extensions = {"gif"}
2256
2276
  extension = "gif"
@@ -2283,7 +2303,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2283
2303
  reply_to_message_id,
2284
2304
  disable_notification,
2285
2305
  chat_keypad_type,
2286
- parse_mode=parse_mode
2306
+ parse_mode=parse_mode,meta_data=meta_data
2287
2307
  )
2288
2308
 
2289
2309
  async def get_avatar_me(self, save_as: str = None) -> str:
@@ -2427,18 +2447,21 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2427
2447
  return await self._post("leaveChat", {"chat_id": chat_id})
2428
2448
  async def forward_message(self, from_chat_id: str, message_id: str, to_chat_id: str, disable_notification: bool = False) -> Dict[str, Any]:
2429
2449
  return await self._post("forwardMessage", {"from_chat_id": from_chat_id, "message_id": message_id, "to_chat_id": to_chat_id, "disable_notification": disable_notification})
2430
- async def edit_message_text(self, chat_id: str, message_id: str, text: str, parse_mode: Optional[Literal["HTML", "Markdown"]] = None) -> Dict[str, Any]:
2450
+ async def edit_message_text(self, chat_id: str, message_id: str, text: str, parse_mode: Optional[Literal["HTML", "Markdown"]] = None,meta_data:Optional[dict] = None) -> Dict[str, Any]:
2431
2451
  payload = {
2432
2452
  "chat_id": chat_id,
2433
2453
  "message_id": message_id,
2434
2454
  "text": text,
2435
2455
  }
2436
- parse_mode_to_use = parse_mode or self.parse_mode
2437
- if text:
2438
- text, metadata = self._parse_text_metadata(text, parse_mode_to_use)
2439
- payload["text"] = text
2440
- if metadata:
2441
- payload["metadata"] = metadata
2456
+ if not meta_data:
2457
+ parse_mode_to_use = parse_mode or self.parse_mode
2458
+ if text:
2459
+ text, metadata = self._parse_text_metadata(text, parse_mode_to_use)
2460
+ payload["text"] = text
2461
+ if metadata:
2462
+ payload["metadata"] = metadata
2463
+ else :
2464
+ payload["metadata"] = meta_data
2442
2465
  return await self._post("editMessageText", payload)
2443
2466
  async def edit_inline_keypad(self,chat_id: str,message_id: str,inline_keypad: Dict[str, Any],text: str = None) -> Dict[str, Any]:
2444
2467
  if text is not None:await self._post("editMessageText", {"chat_id": chat_id,"message_id": message_id,"text": text})
@@ -2511,4 +2534,11 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2511
2534
  result = await asyncio.to_thread(self.get_all_member, channel_guid, search_text=first_name)
2512
2535
  members = result.get('in_chat_members', [])
2513
2536
  return any(m.get('first_name') == first_name for m in members)
2514
- return False
2537
+ return False
2538
+
2539
+ class Bot(Robot):
2540
+ pass
2541
+ class bot(Robot):
2542
+ pass
2543
+ class robot(Robot):
2544
+ pass
@@ -288,6 +288,7 @@ class Message:
288
288
  self.is_audio = None
289
289
  self.is_voice = None
290
290
  self.is_document = None
291
+ self.is_music = None
291
292
  self.is_archive = None
292
293
  self.is_executable = None
293
294
  self.is_font = None
@@ -356,6 +357,7 @@ class Message:
356
357
  self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
357
358
  self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
358
359
  self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
360
+ self.is_music = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
359
361
  self.is_voice = name.endswith((".ogg", ".m4a"))
360
362
  self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
361
363
  self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
@@ -437,8 +439,32 @@ class Message:
437
439
  reply_to_message_id=self.message_id,
438
440
  **kwargs
439
441
  )
440
-
441
-
442
+ async def copy(self, to_chat_id: Optional[str], message_id: Optional[str] = None):await self.copy_message(to_chat_id, message_id)
443
+ async def copy_message(self, to_chat_id: Optional[str], message_id: Optional[str] = None):
444
+ try:
445
+ send_func = None
446
+ kwargs = {
447
+ "chat_id": to_chat_id,
448
+ "reply_to_message_id": message_id,
449
+ "meta_data": self.metadata
450
+ }
451
+ if getattr(self, "is_photo", False):
452
+ send_func = self.bot.send_image
453
+ elif getattr(self, "is_video", False):
454
+ send_func = self.bot.send_video
455
+ elif getattr(self, "is_document", False):
456
+ send_func = self.bot.send_document
457
+ elif getattr(self, "is_text", False):
458
+ send_func = self.bot.send_message
459
+ kwargs["text"] = self.text
460
+ if send_func:
461
+ if hasattr(self, "file") and self.file:
462
+ kwargs["path"] = await self.bot.get_url_file(self.file.file_id)
463
+ return await send_func(**kwargs)
464
+ else:
465
+ raise Exception("Unsupported message type.")
466
+ except Exception as e:
467
+ raise Exception(f"Error: {e}")
442
468
  def reply_poll(
443
469
  self,
444
470
  question: str,
@@ -1,4 +1,4 @@
1
- from typing import Callable
1
+ from typing import Callable,Union
2
2
  import re
3
3
  class TextFilter:
4
4
  def __call__(self, keyword=None):
@@ -244,9 +244,18 @@ def chat_title_equals(value: str):
244
244
 
245
245
  return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "title", "") == value)
246
246
 
247
- def chat_id_is(cid: str):
248
- return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "id", None) == cid)
249
-
247
+ def chat_id_is(sender_id: str):
248
+ return Filter(lambda m: getattr(m, "chat_id", None) == sender_id)
249
+ def sender_id_is(sender_id: str):
250
+ return Filter(lambda m: getattr(m, "sender_id", None) == sender_id)
251
+ def senders_id(sender_ids: Union[str, list]):
252
+ if isinstance(sender_ids, list):
253
+ return Filter(lambda m: getattr(m, "sender_id", None) in sender_ids)
254
+ return Filter(lambda m: getattr(m, "sender_id", None) == sender_ids)
255
+ def chat_ids(sender_ids: Union[str, list]):
256
+ if isinstance(sender_ids, list):
257
+ return Filter(lambda m: getattr(m, "chat_id", None) in sender_ids)
258
+ return Filter(lambda m: getattr(m, "chat_id", None) == sender_ids)
250
259
  def chat_member_count(min_count: int = 0, max_count: int = None):
251
260
 
252
261
  def _filter(m):
@@ -1228,4 +1228,44 @@ class Bot():
1228
1228
  "limit": limit,
1229
1229
  "sort": sort
1230
1230
  }
1231
- return self._reuests_post("getNewFollowRequests", data=payload)
1231
+ return self._reuests_post("getNewFollowRequests", data=payload)
1232
+ def get_myprofile_posts(
1233
+ self,
1234
+ profile_id: Optional[str] = None ,
1235
+ limit: int = 20,
1236
+ sort: str = "FromMax"
1237
+ ) -> Dict[str, Any]:
1238
+ payload = {
1239
+ "profile_id": profile_id,
1240
+ "limit": limit,
1241
+ "sort": sort
1242
+ }
1243
+ return self._reuests_post("getMyProfilePosts", data=payload)
1244
+ def get_recent_following_posts(
1245
+ self,
1246
+ profile_id: Optional[str] = None ,
1247
+ limit: int = 20,
1248
+ sort: str = "FromMax"
1249
+ ) -> Dict[str, Any]:
1250
+ payload = {
1251
+ "profile_id": profile_id,
1252
+ "limit": limit,
1253
+ "sort": sort
1254
+ }
1255
+ return self._reuests_post("getRecentFollowingPosts", data=payload)
1256
+ def get_explore_post_topics(
1257
+ self,
1258
+ profile_id: Optional[str] = None ,
1259
+ ) -> Dict[str, Any]:
1260
+ payload = {
1261
+ "profile_id": profile_id,
1262
+ }
1263
+ return self._reuests_post("getExplorePostTopics", data=payload)
1264
+ def get_profiles_stories(
1265
+ self,
1266
+ profile_id: Optional[str] = None ,
1267
+ ) -> Dict[str, Any]:
1268
+ payload = {
1269
+ "profile_id": profile_id,
1270
+ }
1271
+ return self._reuests_post("getProfilesStories", data=payload)
@@ -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.18',
16
+ version='7.2.2',
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