Rubka 6.7.1__tar.gz → 6.8.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-6.7.1 → rubka-6.8.5}/PKG-INFO +1 -1
  2. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/PKG-INFO +1 -1
  3. {rubka-6.7.1 → rubka-6.8.5}/rubka/asynco.py +92 -40
  4. {rubka-6.7.1 → rubka-6.8.5}/rubka/context.py +46 -7
  5. {rubka-6.7.1 → rubka-6.8.5}/rubka/update.py +34 -5
  6. {rubka-6.7.1 → rubka-6.8.5}/setup.py +1 -1
  7. {rubka-6.7.1 → rubka-6.8.5}/README.md +0 -0
  8. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/SOURCES.txt +0 -0
  9. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/dependency_links.txt +0 -0
  10. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/entry_points.txt +0 -0
  11. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/not-zip-safe +0 -0
  12. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/requires.txt +0 -0
  13. {rubka-6.7.1 → rubka-6.8.5}/Rubka.egg-info/top_level.txt +0 -0
  14. {rubka-6.7.1 → rubka-6.8.5}/rubka/__init__.py +0 -0
  15. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/__init__.py +0 -0
  16. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/client/__init__.py +0 -0
  17. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/client/client.py +0 -0
  18. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/crypto/__init__.py +0 -0
  19. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/crypto/crypto.py +0 -0
  20. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/enums.py +0 -0
  21. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/exceptions.py +0 -0
  22. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/methods/__init__.py +0 -0
  23. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/methods/methods.py +0 -0
  24. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/network/__init__.py +0 -0
  25. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/network/helper.py +0 -0
  26. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/network/network.py +0 -0
  27. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/network/socket.py +0 -0
  28. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/sessions/__init__.py +0 -0
  29. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/sessions/sessions.py +0 -0
  30. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/types/__init__.py +0 -0
  31. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
  32. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/types/socket/message.py +0 -0
  33. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/utils/__init__.py +0 -0
  34. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/utils/configs.py +0 -0
  35. {rubka-6.7.1 → rubka-6.8.5}/rubka/adaptorrubka/utils/utils.py +0 -0
  36. {rubka-6.7.1 → rubka-6.8.5}/rubka/api.py +0 -0
  37. {rubka-6.7.1 → rubka-6.8.5}/rubka/button.py +0 -0
  38. {rubka-6.7.1 → rubka-6.8.5}/rubka/config.py +0 -0
  39. {rubka-6.7.1 → rubka-6.8.5}/rubka/decorators.py +0 -0
  40. {rubka-6.7.1 → rubka-6.8.5}/rubka/exceptions.py +0 -0
  41. {rubka-6.7.1 → rubka-6.8.5}/rubka/filters.py +0 -0
  42. {rubka-6.7.1 → rubka-6.8.5}/rubka/helpers.py +0 -0
  43. {rubka-6.7.1 → rubka-6.8.5}/rubka/jobs.py +0 -0
  44. {rubka-6.7.1 → rubka-6.8.5}/rubka/keyboards.py +0 -0
  45. {rubka-6.7.1 → rubka-6.8.5}/rubka/keypad.py +0 -0
  46. {rubka-6.7.1 → rubka-6.8.5}/rubka/logger.py +0 -0
  47. {rubka-6.7.1 → rubka-6.8.5}/rubka/rubino.py +0 -0
  48. {rubka-6.7.1 → rubka-6.8.5}/rubka/tv.py +0 -0
  49. {rubka-6.7.1 → rubka-6.8.5}/rubka/utils.py +0 -0
  50. {rubka-6.7.1 → rubka-6.8.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 6.7.1
3
+ Version: 6.8.5
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.7.1
3
+ Version: 6.8.5
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
@@ -145,7 +145,7 @@ safeSendMode ensures reliable message sending even if replying by message_id fai
145
145
  max_cache_size and max_msg_age help manage duplicate message processing efficiently.
146
146
  """
147
147
 
148
- 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 = 1000,max_msg_age : int = 60):
148
+ 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):
149
149
  self.token = token
150
150
  self._inline_query_handlers: List[dict] = []
151
151
  self.timeout = timeout
@@ -167,10 +167,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
167
167
  self.sessions: Dict[str, Dict[str, Any]] = {}
168
168
  self._callback_handler = None
169
169
  self._processed_message_ids = OrderedDict()
170
- self._max_cache_size = max_cache_size
171
-
172
- self._connector = aiohttp.TCPConnector(limit=100, ssl=False)
173
-
170
+ self._max_cache_size = max_cache_size
174
171
  self._callback_handlers: List[dict] = []
175
172
  self._edited_message_handlers = []
176
173
  self._message_handlers: List[dict] = []
@@ -183,8 +180,9 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
183
180
  self._aiohttp_session = aiohttp.ClientSession(connector=connector, timeout=timeout)
184
181
  return self._aiohttp_session
185
182
  async def close(self):
186
- if self._session and not self._session.closed:
187
- await self._session.close()
183
+ if self._aiohttp_session and not self._aiohttp_session.closed:
184
+ await self._aiohttp_session.close()
185
+ logger.debug("aiohttp session closed successfully.")
188
186
 
189
187
  async def _initialize_webhook(self):
190
188
  """Initializes and sets the webhook endpoint if provided."""
@@ -1363,7 +1361,13 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1363
1361
  msg_time = int(msg_data.get("time", 0))
1364
1362
  elif "message_id" in update:
1365
1363
  message_id = update.get("message_id")
1364
+ else:
1365
+ msg_time = time.time()
1366
+ msg_data = update.get("updated_message", {})
1367
+ message_id = msg_data.get("message_id")
1368
+ text_content = msg_data.get("text", "")
1366
1369
  now = int(time.time())
1370
+
1367
1371
  if msg_time and (now - msg_time > self.max_msg_age):
1368
1372
  continue
1369
1373
  dup_ok = True
@@ -1372,15 +1376,10 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1372
1376
  dup_ok = not self._is_duplicate(dup_key)
1373
1377
  if message_id and dup_ok:
1374
1378
  received_updates.append(update)
1375
-
1376
-
1377
1379
  if not received_updates:
1378
- if pause_on_idle and sleep_time == 0:
1379
- await asyncio.sleep(0.005)
1380
- else:
1381
- await asyncio.sleep(sleep_time)
1382
- if not loop_forever and max_runtime is None:
1383
- break
1380
+ if pause_on_idle and sleep_time == 0:await asyncio.sleep(0.005)
1381
+ else:await asyncio.sleep(sleep_time)
1382
+ if not loop_forever and max_runtime is None:break
1384
1383
  continue
1385
1384
 
1386
1385
 
@@ -1497,7 +1496,53 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1497
1496
 
1498
1497
 
1499
1498
  _log("Auto-restart requested. You can call run(...) again as needed.", "warning")
1500
-
1499
+ async def _delete_after_task(self, chat_id: str, message_id: str, delay: int):
1500
+ try:
1501
+ await asyncio.sleep(delay)
1502
+ await self.delete_message(chat_id=chat_id, message_id=message_id)
1503
+ except Exception:
1504
+ return False
1505
+ async def _edit_after_task(self, chat_id: str, message_id: str, text:str, delay: int):
1506
+ try:
1507
+ await asyncio.sleep(delay)
1508
+ await self.edit_message_text(chat_id=chat_id, message_id=message_id,text=text)
1509
+ except Exception:
1510
+ return False
1511
+
1512
+ async def delete_after(self, chat_id: str, message_id: str, delay: int = 30) -> asyncio.Task:
1513
+ async def _task():
1514
+ await asyncio.sleep(delay)
1515
+ try:
1516
+ await self.delete_message(chat_id, message_id)
1517
+ except Exception:
1518
+ pass
1519
+
1520
+ try:
1521
+ loop = asyncio.get_running_loop()
1522
+ except RuntimeError:
1523
+ loop = asyncio.new_event_loop()
1524
+ asyncio.set_event_loop(loop)
1525
+
1526
+ task = loop.create_task(_task())
1527
+ return task
1528
+
1529
+ async def edit_after(self, chat_id: str, message_id: str, text : str, delay: int = 30) -> asyncio.Task:
1530
+ async def _task():
1531
+ await asyncio.sleep(delay)
1532
+ try:
1533
+ await self.edit_message_text(chat_id, message_id,text)
1534
+ except Exception:
1535
+ pass
1536
+
1537
+ try:
1538
+ loop = asyncio.get_running_loop()
1539
+ except RuntimeError:
1540
+ loop = asyncio.new_event_loop()
1541
+ asyncio.set_event_loop(loop)
1542
+
1543
+ task = loop.create_task(_task())
1544
+ return task
1545
+
1501
1546
  async def send_message(
1502
1547
  self,
1503
1548
  chat_id: str,
@@ -1506,7 +1551,8 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1506
1551
  inline_keypad: Optional[Dict[str, Any]] = None,
1507
1552
  disable_notification: bool = False,
1508
1553
  reply_to_message_id: Optional[str] = None,
1509
- chat_keypad_type: Optional[Literal["New", "Removed"]] = None
1554
+ chat_keypad_type: Optional[Literal["New", "Removed"]] = None,
1555
+ delete_after : int = None
1510
1556
  ) -> Dict[str, Any]:
1511
1557
  payload = {
1512
1558
  "chat_id": chat_id,
@@ -1522,12 +1568,16 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1522
1568
  payload["reply_to_message_id"] = reply_to_message_id
1523
1569
  if self.safeSendMode and reply_to_message_id:
1524
1570
  try:
1525
- return await self._post("sendMessage", payload)
1571
+ state = await self._post("sendMessage", payload)
1526
1572
  except Exception:
1527
1573
  payload.pop("reply_to_message_id", None)
1528
- return await self._post("sendMessage", payload)
1574
+ state = await self._post("sendMessage", payload)
1529
1575
  else:
1530
- return await self._post("sendMessage", payload)
1576
+ state = await self._post("sendMessage", payload)
1577
+ if delete_after:
1578
+ await self.delete_after(chat_id, state.message_id, delete_after)
1579
+ return state
1580
+ return state
1531
1581
 
1532
1582
 
1533
1583
  async def send_sticker(
@@ -1920,33 +1970,35 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1920
1970
  disable_notification,
1921
1971
  chat_keypad_type
1922
1972
  )
1923
- async def get_avatar_me(
1924
- self,
1925
- save_as: str = None) -> str:
1926
- """
1927
- Get the bot's profile photo URL and optionally save it locally.
1928
- Args:
1929
- save_as (str, optional): File name to save the avatar locally.
1930
- Returns:
1931
- str: Download URL of the bot's avatar, or "null" if not available.
1932
- """
1973
+
1974
+ async def get_avatar_me(self, save_as: str = None) -> str:
1975
+ session = None
1933
1976
  try:
1934
1977
  me_info = await self.get_me()
1935
1978
  avatar = me_info.get('data', {}).get('bot', {}).get('avatar', {})
1936
1979
  file_id = avatar.get('file_id')
1937
1980
  if not file_id:
1938
- return None
1939
- url = await self.get_url_file(file_id)
1981
+ return "null"
1982
+
1983
+ file_info = await self.get_url_file(file_id)
1984
+ url = file_info.get("download_url") if isinstance(file_info, dict) else file_info
1985
+
1940
1986
  if save_as:
1941
- async with aiohttp.ClientSession() as session:
1942
- async with session.get(url) as resp:
1943
- if resp.status == 200:
1944
- content = await resp.read()
1945
- with open(save_as, "wb") as f:
1946
- f.write(content)
1987
+ session = aiohttp.ClientSession()
1988
+ async with session.get(url) as resp:
1989
+ if resp.status == 200:
1990
+ content = await resp.read()
1991
+ with open(save_as, "wb") as f:
1992
+ f.write(content)
1993
+
1947
1994
  return url
1948
- except Exception:
1949
- return None
1995
+ except Exception as e:
1996
+ print(f"[get_avatar_me] Error: {e}")
1997
+ return "null"
1998
+ finally:
1999
+ if session and not session.closed:
2000
+ await session.close()
2001
+
1950
2002
  async def get_name(self, chat_id: str) -> str:
1951
2003
  try:
1952
2004
  chat = await self.get_chat(chat_id)
@@ -1,5 +1,8 @@
1
1
  from typing import Any, Dict, List,Optional
2
-
2
+ from typing import Union
3
+ from pathlib import Path
4
+ import re
5
+ import asyncio
3
6
  class File:
4
7
  def __init__(self, data: dict):
5
8
  self.file_id: str = data.get("file_id")
@@ -184,9 +187,25 @@ class Bot:
184
187
  self.username: str = data.get("username")
185
188
  self.start_message: str = data.get("start_message")
186
189
  self.share_url: str = data.get("share_url")
187
- from typing import Union
188
- from pathlib import Path
189
- import re
190
+
191
+ class hybrid_property:
192
+ def __init__(self, func):
193
+ self.func = func
194
+
195
+ def __get__(self, instance, owner):
196
+ if instance is None:
197
+ return self
198
+ coro = self.func(instance)
199
+ try:
200
+ loop = asyncio.get_running_loop()
201
+ return coro
202
+ except RuntimeError:
203
+ try:
204
+ loop = asyncio.get_event_loop()
205
+ except RuntimeError:
206
+ loop = asyncio.new_event_loop()
207
+ asyncio.set_event_loop(loop)
208
+ return loop.run_until_complete(coro)
190
209
  class Message:
191
210
  def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
192
211
  self.bot = bot
@@ -240,19 +259,30 @@ class Message:
240
259
  self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
241
260
  self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
242
261
  self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
243
- self.info = {attr: value for attr, value in vars(self).items()}
244
262
  @property
245
263
  def session(self):
246
264
  if self.chat_id not in self.bot.sessions:
247
265
  self.bot.sessions[self.chat_id] = {}
248
266
  return self.bot.sessions[self.chat_id]
249
- def reply(self, text: str, **kwargs):
250
- return self.bot.send_message(
267
+
268
+ async def reply(self, text: str, delete_after: int = None, **kwargs):
269
+ msg = await self.bot.send_message(
251
270
  self.chat_id,
252
271
  text,
253
272
  reply_to_message_id=self.message_id,
273
+ delete_after=delete_after,
254
274
  **kwargs
255
275
  )
276
+ class pick:
277
+ def __init__(self, bot, chat_id, message_id):
278
+ self.bot = bot
279
+ self.chat_id = chat_id
280
+ self.message_id = message_id
281
+ async def edit(self, new_text):
282
+ await self.bot.edit_message_text(self.chat_id, self.message_id, new_text)
283
+ async def delete(self):
284
+ await self.bot.delete_message(self.chat_id, self.message_id)
285
+ return pick(self.bot, msg.chat_id, msg.message_id)
256
286
  def answer(self, text: str, **kwargs):
257
287
  return self.bot.send_message(
258
288
  self.chat_id,
@@ -260,6 +290,7 @@ class Message:
260
290
  reply_to_message_id=self.message_id,
261
291
  **kwargs
262
292
  )
293
+
263
294
 
264
295
  def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
265
296
  return self.bot._post("sendPoll", {
@@ -471,6 +502,14 @@ class Message:
471
502
  chat_id=self.chat_id,
472
503
  message_id=self.message_id
473
504
  )
505
+ @hybrid_property
506
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
507
+ @hybrid_property
508
+ async def name(self):return await self.bot.get_name(self.chat_id)
509
+ @hybrid_property
510
+ async def username(self):return await self.bot.get_username(self.chat_id)
511
+ @hybrid_property
512
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
474
513
  class AuxData:
475
514
  def __init__(self, data: dict):
476
515
  self.start_id = data.get("start_id")
@@ -1,5 +1,8 @@
1
1
  from typing import Any, Dict, List,Optional
2
-
2
+ from typing import Union
3
+ from pathlib import Path
4
+ import re
5
+ import asyncio
3
6
  class File:
4
7
  def __init__(self, data: dict):
5
8
  self.file_id: str = data.get("file_id")
@@ -184,9 +187,25 @@ class Bot:
184
187
  self.username: str = data.get("username")
185
188
  self.start_message: str = data.get("start_message")
186
189
  self.share_url: str = data.get("share_url")
187
- from typing import Union
188
- from pathlib import Path
189
- import re
190
+
191
+ class hybrid_property:
192
+ def __init__(self, func):
193
+ self.func = func
194
+
195
+ def __get__(self, instance, owner):
196
+ if instance is None:
197
+ return self
198
+ coro = self.func(instance)
199
+ try:
200
+ loop = asyncio.get_running_loop()
201
+ return coro
202
+ except RuntimeError:
203
+ try:
204
+ loop = asyncio.get_event_loop()
205
+ except RuntimeError:
206
+ loop = asyncio.new_event_loop()
207
+ asyncio.set_event_loop(loop)
208
+ return loop.run_until_complete(coro)
190
209
  class Message:
191
210
  def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
192
211
  self.bot = bot
@@ -246,11 +265,12 @@ class Message:
246
265
  if self.chat_id not in self.bot.sessions:
247
266
  self.bot.sessions[self.chat_id] = {}
248
267
  return self.bot.sessions[self.chat_id]
249
- def reply(self, text: str, **kwargs):
268
+ def reply(self, text: str,delete_after :int = None, **kwargs):
250
269
  return self.bot.send_message(
251
270
  self.chat_id,
252
271
  text,
253
272
  reply_to_message_id=self.message_id,
273
+ delete_after=delete_after,
254
274
  **kwargs
255
275
  )
256
276
  def answer(self, text: str, **kwargs):
@@ -260,6 +280,7 @@ class Message:
260
280
  reply_to_message_id=self.message_id,
261
281
  **kwargs
262
282
  )
283
+
263
284
 
264
285
  def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
265
286
  return self.bot._post("sendPoll", {
@@ -471,6 +492,14 @@ class Message:
471
492
  chat_id=self.chat_id,
472
493
  message_id=self.message_id
473
494
  )
495
+ @hybrid_property
496
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
497
+ @hybrid_property
498
+ async def name(self):return await self.bot.get_name(self.chat_id)
499
+ @hybrid_property
500
+ async def username(self):return await self.bot.get_username(self.chat_id)
501
+ @hybrid_property
502
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
474
503
  class AuxData:
475
504
  def __init__(self, data: dict):
476
505
  self.start_id = data.get("start_id")
@@ -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.7.1',
16
+ version='6.8.5',
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
File without changes
File without changes
File without changes
File without changes