Rubka 4.5.2__py3-none-any.whl → 4.5.11__py3-none-any.whl

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.
rubka/api.py CHANGED
@@ -13,6 +13,8 @@ import tempfile
13
13
  from tqdm import tqdm
14
14
  import os
15
15
  API_URL = "https://botapi.rubika.ir/v3"
16
+ import mimetypes
17
+ import re
16
18
  import sys
17
19
  import subprocess
18
20
  def install_package(package_name):
@@ -109,6 +111,7 @@ class Robot:
109
111
  self.Key = Key
110
112
  self.platform = platform
111
113
  self.web_hook = web_hook
114
+ self.hook = web_hook
112
115
  self._offset_id = None
113
116
  self.session = requests.Session()
114
117
  self.sessions: Dict[str, Dict[str, Any]] = {}
@@ -117,7 +120,7 @@ class Robot:
117
120
  self._inline_query_handler = None
118
121
  self._message_handlers: List[dict] = []
119
122
  self._callback_handlers = None
120
- self._callback_handlers = [] # ✅ این خط مهمه
123
+ self._callback_handlers = []
121
124
  if web_hook:
122
125
  try:
123
126
  json_url = requests.get(web_hook, timeout=self.timeout).json().get('url', web_hook)
@@ -133,7 +136,7 @@ class Robot:
133
136
  except Exception as e:
134
137
  logger.error(f"Failed to set webhook from {web_hook}: {e}")
135
138
  else:
136
- self.web_hook = None
139
+ self.web_hook = self.hook
137
140
 
138
141
 
139
142
 
@@ -202,14 +205,13 @@ class Robot:
202
205
 
203
206
  def _process_update(self, update: dict):
204
207
  import threading
205
- # هندل پیام inline (بدون تغییر)
208
+
206
209
  if update.get("type") == "ReceiveQuery":
207
210
  msg = update.get("inline_message", {})
208
211
  context = InlineMessage(bot=self, raw_data=msg)
209
212
  threading.Thread(target=self._handle_inline_query, args=(context,), daemon=True).start()
210
213
  return
211
214
 
212
- # هندل پیام جدید متنی
213
215
  if update.get("type") == "NewMessage":
214
216
  msg = update.get("new_message", {})
215
217
  try:
@@ -225,17 +227,14 @@ class Robot:
225
227
  text=msg.get("text"),
226
228
  raw_data=msg)
227
229
 
228
- # هندل callback ها (دکمه‌ها) - بدون تغییر
229
230
  if context.aux_data and self._callback_handlers:
230
231
  for handler in self._callback_handlers:
231
232
  if not handler["button_id"] or context.aux_data.button_id == handler["button_id"]:
232
233
  threading.Thread(target=handler["func"], args=(self, context), daemon=True).start()
233
234
  return
234
235
 
235
- # هندل پیام‌های متنی با حلقه روی تمام هندلرها
236
236
  if self._message_handlers:
237
237
  for handler in self._message_handlers:
238
- # بررسی شرط دستورات (commands)
239
238
  if handler["commands"]:
240
239
  if not context.text or not context.text.startswith("/"):
241
240
  continue
@@ -245,11 +244,9 @@ class Robot:
245
244
  continue
246
245
  context.args = parts[1:]
247
246
 
248
- # بررسی شرط فیلترها (filters)
249
247
  if handler["filters"] and not handler["filters"](context):
250
248
  continue
251
249
 
252
- # اگر شرایط بالا برقرار بود یا هندلر عمومی بود، اجرا کن و خارج شو
253
250
  threading.Thread(target=handler["func"], args=(self, context), daemon=True).start()
254
251
  return
255
252
 
@@ -279,12 +276,10 @@ class Robot:
279
276
  def _is_duplicate(self, message_id: str, max_age_sec: int = 300) -> bool:
280
277
  now = time.time()
281
278
 
282
- # حذف پیام‌های قدیمی‌تر از max_age_sec
283
279
  expired = [mid for mid, ts in self._processed_message_ids.items() if now - ts > max_age_sec]
284
280
  for mid in expired:
285
281
  del self._processed_message_ids[mid]
286
282
 
287
- # بررسی تکراری بودن پیام
288
283
  if message_id in self._processed_message_ids:
289
284
  return True
290
285
 
@@ -298,7 +293,6 @@ class Robot:
298
293
  def run(self):
299
294
  print("Bot started running...")
300
295
  self._processed_message_ids: Dict[str, float] = {}
301
- # self._offset_id می‌تواند قبلاً مقداردهی شده باشد
302
296
 
303
297
  while True:
304
298
  try:
@@ -309,12 +303,11 @@ class Robot:
309
303
  for item in updates:
310
304
  data = item.get("data", {})
311
305
 
312
- # بررسی زمان دریافت پیام و رد کردن پیام‌های قدیمی (بیش از 20 ثانیه)
313
306
  received_at_str = item.get("received_at")
314
307
  if received_at_str:
315
308
  received_at_ts = datetime.datetime.strptime(received_at_str, "%Y-%m-%d %H:%M:%S").timestamp()
316
309
  if time.time() - received_at_ts > 20:
317
- continue # رد کردن پیام قدیمی
310
+ continue
318
311
 
319
312
  update = None
320
313
  if "update" in data:
@@ -343,7 +336,6 @@ class Robot:
343
336
 
344
337
  self._process_update(update)
345
338
 
346
- # ثبت پیام به عنوان پردازش شده
347
339
  if message_id:
348
340
  self._processed_message_ids[message_id] = time.time()
349
341
 
@@ -431,6 +423,10 @@ class Robot:
431
423
 
432
424
  return False
433
425
 
426
+ def get_url_file(self,file_id):
427
+ data = self._post("getFile", {'file_id': file_id})
428
+ return data.get("data").get("download_url")
429
+
434
430
 
435
431
  def get_all_member(
436
432
  self,
@@ -479,7 +475,6 @@ class Robot:
479
475
  "reply_to_message_id": reply_to_message_id,
480
476
  "chat_keypad_type": chat_keypad_type
481
477
  }
482
- # Remove None values
483
478
  payload = {k: v for k, v in payload.items() if v is not None}
484
479
  return self._post("sendLocation", payload)
485
480
 
@@ -499,7 +494,63 @@ class Robot:
499
494
  "last_name": last_name,
500
495
  "phone_number": phone_number
501
496
  })
497
+ def download(self,file_id: str, save_as: str = None, chunk_size: int = 1024 * 512, timeout_sec: int = 60, verbose: bool = False):
498
+ """
499
+ Download a file from server using its file_id with chunked transfer,
500
+ progress bar, file extension detection, custom filename, and timeout.
501
+
502
+ If save_as is not provided, filename will be extracted from
503
+ Content-Disposition header or Content-Type header extension.
504
+
505
+ Parameters:
506
+ file_id (str): The file ID to fetch the download URL.
507
+ save_as (str, optional): Custom filename to save. If None, automatically detected.
508
+ chunk_size (int, optional): Size of each chunk in bytes. Default 512KB.
509
+ timeout_sec (int, optional): HTTP timeout in seconds. Default 60.
510
+ verbose (bool, optional): Show progress messages. Default True.
502
511
 
512
+ Returns:
513
+ bool: True if success, raises exceptions otherwise.
514
+ """
515
+ try:
516
+ url = self.get_url_file(file_id)
517
+ if not url:
518
+ raise ValueError("Download URL not found in response.")
519
+ except Exception as e:
520
+ raise ValueError(f"Failed to get download URL: {e}")
521
+
522
+ try:
523
+ with requests.get(url, stream=True, timeout=timeout_sec) as resp:
524
+ if resp.status_code != 200:
525
+ raise requests.HTTPError(f"Failed to download file. Status code: {resp.status_code}")
526
+
527
+ if not save_as:
528
+ content_disp = resp.headers.get("Content-Disposition", "")
529
+ match = re.search(r'filename="?([^\";]+)"?', content_disp)
530
+ if match:
531
+ save_as = match.group(1)
532
+ else:
533
+ content_type = resp.headers.get("Content-Type", "").split(";")[0]
534
+ extension = mimetypes.guess_extension(content_type) or ".bin"
535
+ save_as = f"{file_id}{extension}"
536
+
537
+ total_size = int(resp.headers.get("Content-Length", 0))
538
+ progress = tqdm(total=total_size, unit="B", unit_scale=True)
539
+
540
+ with open(save_as, "wb") as f:
541
+ for chunk in resp.iter_content(chunk_size=chunk_size):
542
+ if chunk:
543
+ f.write(chunk)
544
+ progress.update(len(chunk))
545
+
546
+ progress.close()
547
+ if verbose:
548
+ print(f"File saved as: {save_as}")
549
+
550
+ return True
551
+
552
+ except Exception as e:
553
+ raise RuntimeError(f"Download failed: {e}")
503
554
  def get_chat(self, chat_id: str) -> Dict[str, Any]:
504
555
  """Get chat info."""
505
556
  return self._post("getChat", {"chat_id": chat_id})
@@ -600,7 +651,64 @@ class Robot:
600
651
  payload["reply_to_message_id"] = str(reply_to_message_id)
601
652
 
602
653
  return self._post("sendFile", payload)
603
-
654
+ def send_file(
655
+ self,
656
+ chat_id: str,
657
+ path: Optional[Union[str, Path]] = None,
658
+ file_id: Optional[str] = None,
659
+ caption: Optional[str] = None,
660
+ file_name: Optional[str] = None,
661
+ inline_keypad: Optional[Dict[str, Any]] = None,
662
+ chat_keypad: Optional[Dict[str, Any]] = None,
663
+ reply_to_message_id: Optional[str] = None,
664
+ disable_notification: bool = False,
665
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
666
+ ) -> Dict[str, Any]:
667
+ if path:
668
+ file_name = file_name or Path(path).name
669
+ upload_url = self.get_upload_url("File")
670
+ file_id = self.upload_media_file(upload_url, file_name, path)
671
+ if not file_id:
672
+ raise ValueError("Either path or file_id must be provided.")
673
+ return self._send_uploaded_file(
674
+ chat_id=chat_id,
675
+ file_id=file_id,
676
+ text=caption,
677
+ inline_keypad=inline_keypad,
678
+ chat_keypad=chat_keypad,
679
+ reply_to_message_id=reply_to_message_id,
680
+ disable_notification=disable_notification,
681
+ chat_keypad_type=chat_keypad_type
682
+ )
683
+ def re_send_file(
684
+ self,
685
+ chat_id: str,
686
+ path: Optional[Union[str, Path]] = None,
687
+ file_id: Optional[str] = None,
688
+ caption: Optional[str] = None,
689
+ file_name: Optional[str] = None,
690
+ inline_keypad: Optional[Dict[str, Any]] = None,
691
+ chat_keypad: Optional[Dict[str, Any]] = None,
692
+ reply_to_message_id: Optional[str] = None,
693
+ disable_notification: bool = False,
694
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
695
+ ) -> Dict[str, Any]:
696
+ if path:
697
+ file_name = file_name or Path(path).name
698
+ upload_url = self.get_upload_url("File")
699
+ file_id = self.upload_media_file(upload_url, file_name, path)
700
+ if not file_id:
701
+ raise ValueError("Either path or file_id must be provided.")
702
+ return self._send_uploaded_file(
703
+ chat_id=chat_id,
704
+ file_id=file_id,
705
+ text=caption,
706
+ inline_keypad=inline_keypad,
707
+ chat_keypad=chat_keypad,
708
+ reply_to_message_id=reply_to_message_id,
709
+ disable_notification=disable_notification,
710
+ chat_keypad_type=chat_keypad_type
711
+ )
604
712
  def send_document(
605
713
  self,
606
714
  chat_id: str,
@@ -612,7 +720,7 @@ class Robot:
612
720
  chat_keypad: Optional[Dict[str, Any]] = None,
613
721
  reply_to_message_id: Optional[str] = None,
614
722
  disable_notification: bool = False,
615
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
723
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
616
724
  ) -> Dict[str, Any]:
617
725
  if path:
618
726
  file_name = file_name or Path(path).name
@@ -641,7 +749,7 @@ class Robot:
641
749
  chat_keypad: Optional[Dict[str, Any]] = None,
642
750
  reply_to_message_id: Optional[str] = None,
643
751
  disable_notification: bool = False,
644
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
752
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
645
753
  ) -> Dict[str, Any]:
646
754
  if path:
647
755
  file_name = file_name or Path(path).name
@@ -670,7 +778,7 @@ class Robot:
670
778
  chat_keypad: Optional[Dict[str, Any]] = None,
671
779
  reply_to_message_id: Optional[str] = None,
672
780
  disable_notification: bool = False,
673
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
781
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
674
782
  ) -> Dict[str, Any]:
675
783
  if path:
676
784
  file_name = file_name or Path(path).name
@@ -699,7 +807,7 @@ class Robot:
699
807
  chat_keypad: Optional[Dict[str, Any]] = None,
700
808
  reply_to_message_id: Optional[str] = None,
701
809
  disable_notification: bool = False,
702
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
810
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
703
811
  ) -> Dict[str, Any]:
704
812
  if path:
705
813
  file_name = file_name or Path(path).name
@@ -728,7 +836,7 @@ class Robot:
728
836
  chat_keypad: Optional[Dict[str, Any]] = None,
729
837
  reply_to_message_id: Optional[str] = None,
730
838
  disable_notification: bool = False,
731
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
839
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
732
840
  ) -> Dict[str, Any]:
733
841
  if path:
734
842
  file_name = file_name or Path(path).name
@@ -757,7 +865,7 @@ class Robot:
757
865
  chat_keypad: Optional[Dict[str, Any]] = None,
758
866
  reply_to_message_id: Optional[str] = None,
759
867
  disable_notification: bool = False,
760
- chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
868
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
761
869
  ) -> Dict[str, Any]:
762
870
  if path:
763
871
  file_name = file_name or Path(path).name
rubka/asynco.py CHANGED
@@ -8,8 +8,12 @@ from .logger import logger
8
8
  try:
9
9
  from .context import Message, InlineMessage
10
10
  except (ImportError, ModuleNotFoundError):
11
- # اگر به صورت مستقیم اجرا شود، از این حالت استفاده می‌کند
12
11
  from context import Message, InlineMessage
12
+
13
+ from tqdm.asyncio import tqdm
14
+ from urllib.parse import urlparse, parse_qs
15
+
16
+ import mimetypes
13
17
  from pathlib import Path
14
18
  import time
15
19
  import datetime
@@ -307,6 +311,7 @@ class Robot:
307
311
 
308
312
  self._processed_message_ids[message_id] = now
309
313
  return False
314
+
310
315
 
311
316
  async def run(self):
312
317
  """
@@ -384,14 +389,40 @@ class Robot:
384
389
  await self._aiohttp_session.close()
385
390
  print("Bot stopped and session closed.")
386
391
 
387
- async def send_message(self, chat_id: str, text: str, 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) -> Dict[str, Any]:
388
- payload = {"chat_id": chat_id, "text": text, "disable_notification": disable_notification}
389
- if chat_keypad: payload["chat_keypad"] = chat_keypad
390
- if inline_keypad: payload["inline_keypad"] = inline_keypad
391
- if reply_to_message_id: payload["reply_to_message_id"] = reply_to_message_id
392
- if chat_keypad_type: payload["chat_keypad_type"] = chat_keypad_type
392
+ async def send_message(
393
+ self,
394
+ chat_id: str,
395
+ text: str,
396
+ chat_keypad: Optional[Dict[str, Any]] = None,
397
+ inline_keypad: Optional[Dict[str, Any]] = None,
398
+ disable_notification: bool = False,
399
+ reply_to_message_id: Optional[str] = None,
400
+ chat_keypad_type: Optional[Literal["New", "Removed"]] = None
401
+ ) -> Dict[str, Any]:
402
+ payload = {
403
+ "chat_id": chat_id,
404
+ "text": text,
405
+ "disable_notification": disable_notification,
406
+ }
407
+
408
+ if chat_keypad:
409
+ payload["chat_keypad"] = chat_keypad
410
+ payload["chat_keypad_type"] = chat_keypad_type or "New"
411
+
412
+ if inline_keypad:
413
+ payload["inline_keypad"] = inline_keypad
414
+
415
+ if reply_to_message_id:
416
+ payload["reply_to_message_id"] = reply_to_message_id
417
+
393
418
  return await self._post("sendMessage", payload)
394
419
 
420
+
421
+
422
+ async def get_url_file(self,file_id):
423
+ data = await self._post("getFile", {'file_id': file_id})
424
+ return data.get("data").get("download_url")
425
+
395
426
  def _get_client(self) -> Client_get:
396
427
  if self.session_name:
397
428
  return Client_get(self.session_name, self.auth, self.Key, self.platform)
@@ -454,7 +485,7 @@ class Robot:
454
485
  path = temp_file.name
455
486
  is_temp_file = True
456
487
 
457
- file_size = os.path.getsize(path) # Note: os.path.getsize is sync, but fast enough for most cases. aiofiles can be used for async alternative if needed on huge file lists.
488
+ file_size = os.path.getsize(path)
458
489
 
459
490
  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)
460
491
 
@@ -478,9 +509,100 @@ class Robot:
478
509
  json_data = await response.json()
479
510
  if is_temp_file:
480
511
  os.remove(path)
481
-
512
+ print(json_data)
482
513
  return json_data.get('data', {}).get('file_id')
483
514
 
515
+
516
+ def get_extension(content_type: str) -> str:
517
+ ext = mimetypes.guess_extension(content_type)
518
+ return ext if ext else ''
519
+
520
+ async def download(self, file_id: str, save_as: str = None, chunk_size: int = 1024 * 512,timeout_sec: int = 60, verbose: bool = False):
521
+ """
522
+ Download a file from server using its file_id with chunked transfer,
523
+ progress bar, file extension detection, custom filename, and timeout.
524
+
525
+ If save_as is not provided, filename will be extracted from
526
+ Content-Disposition header or Content-Type header extension.
527
+
528
+ Parameters:
529
+ file_id (str): The file ID to fetch the download URL.
530
+ save_as (str, optional): Custom filename to save. If None, automatically detected.
531
+ chunk_size (int, optional): Size of each chunk in bytes. Default 512KB.
532
+ timeout_sec (int, optional): HTTP timeout in seconds. Default 60.
533
+ verbose (bool, optional): Show progress messages. Default True.
534
+
535
+ Returns:
536
+ bool: True if success, raises exceptions otherwise.
537
+ """
538
+
539
+ try:
540
+ url = await self.get_url_file(file_id)
541
+ if not url:
542
+ raise ValueError("Download URL not found in response.")
543
+ except Exception as e:
544
+ raise ValueError(f"Failed to get download URL: {e}")
545
+
546
+ timeout = aiohttp.ClientTimeout(total=timeout_sec)
547
+
548
+ try:
549
+ async with aiohttp.ClientSession(timeout=timeout) as session:
550
+ async with session.get(url) as resp:
551
+ if resp.status != 200:
552
+ raise aiohttp.ClientResponseError(
553
+ request_info=resp.request_info,
554
+ history=resp.history,
555
+ status=resp.status,
556
+ message="Failed to download file.",
557
+ headers=resp.headers
558
+ )
559
+
560
+ if not save_as:
561
+ content_disp = resp.headers.get("Content-Disposition", "")
562
+ import re
563
+ match = re.search(r'filename="?([^\";]+)"?', content_disp)
564
+ if match:
565
+ save_as = match.group(1)
566
+ else:
567
+ content_type = resp.headers.get("Content-Type", "").split(";")[0]
568
+ extension = mimetypes.guess_extension(content_type) or ".bin"
569
+ save_as = f"{file_id}{extension}"
570
+
571
+ total_size = int(resp.headers.get("Content-Length", 0))
572
+ progress = tqdm(total=total_size, unit="B", unit_scale=True, disable=not verbose)
573
+
574
+ async with aiofiles.open(save_as, "wb") as f:
575
+ async for chunk in resp.content.iter_chunked(chunk_size):
576
+ await f.write(chunk)
577
+ progress.update(len(chunk))
578
+
579
+ progress.close()
580
+ if verbose:
581
+ print(f"✅ File saved as: {save_as}")
582
+
583
+ return True
584
+
585
+ except aiohttp.ClientError as e:
586
+ raise aiohttp.ClientError(f"HTTP error occurred: {e}")
587
+ except asyncio.TimeoutError:
588
+ raise asyncio.TimeoutError("Download timed out.")
589
+ except Exception as e:
590
+ raise Exception(f"Error downloading file: {e}")
591
+
592
+ except aiohttp.ClientError as e:
593
+ raise aiohttp.ClientError(f"HTTP error occurred: {e}")
594
+ except asyncio.TimeoutError:
595
+ raise asyncio.TimeoutError("The download operation timed out.")
596
+ except Exception as e:
597
+ raise Exception(f"An error occurred while downloading the file: {e}")
598
+
599
+ except aiohttp.ClientError as e:
600
+ raise aiohttp.ClientError(f"HTTP error occurred: {e}")
601
+ except asyncio.TimeoutError:
602
+ raise asyncio.TimeoutError("The download operation timed out.")
603
+ except Exception as e:
604
+ raise Exception(f"An error occurred while downloading the file: {e}")
605
+
484
606
  async def get_upload_url(self, media_type: Literal['File', 'Image', 'Voice', 'Music', 'Gif', 'Video']) -> str:
485
607
  allowed = ['File', 'Image', 'Voice', 'Music', 'Gif', 'Video']
486
608
  if media_type not in allowed:
@@ -504,22 +626,25 @@ class Robot:
504
626
  raise ValueError("Either path or file_id must be provided.")
505
627
  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)
506
628
 
507
- 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"]] = "New") -> Dict[str, Any]:
629
+ 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]:
508
630
  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)
509
-
510
- async def send_music(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"]] = "New") -> Dict[str, Any]:
631
+ 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]:
632
+ 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)
633
+ 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]:
634
+ 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)
635
+ async def send_music(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]:
511
636
  return await self._send_file_generic("Music", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
512
637
 
513
- 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"]] = "New") -> Dict[str, Any]:
638
+ 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]:
514
639
  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)
515
640
 
516
- 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"]] = "New") -> Dict[str, Any]:
641
+ 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]:
517
642
  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)
518
643
 
519
- 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"]] = "New") -> Dict[str, Any]:
644
+ 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]:
520
645
  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)
521
646
 
522
- async def send_gif(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"]] = "New") -> Dict[str, Any]:
647
+ async def send_gif(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]:
523
648
  return await self._send_file_generic("Gif", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
524
649
 
525
650
  async def forward_message(self, from_chat_id: str, message_id: str, to_chat_id: str, disable_notification: bool = False) -> Dict[str, Any]:
rubka/context.py CHANGED
@@ -242,6 +242,31 @@ class Message:
242
242
  chat_keypad_type: Optional[str] = "None",
243
243
  disable_notification: bool = False
244
244
  ):
245
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
246
+ return self.bot.send_document(
247
+ chat_id=self.chat_id,
248
+ path=path,
249
+ file_id=file_id,
250
+ text=text,
251
+ chat_keypad=chat_keypad,
252
+ inline_keypad=inline_keypad,
253
+ chat_keypad_type=chat_keypad_type,
254
+ disable_notification=disable_notification,
255
+ reply_to_message_id=self.message_id
256
+ )
257
+ def reply_file(
258
+ self,
259
+ path: Optional[Union[str, Path]] = None,
260
+ file_id: Optional[str] = None,
261
+ text: Optional[str] = None,
262
+ chat_keypad: Optional[Dict[str, Any]] = None,
263
+ inline_keypad: Optional[Dict[str, Any]] = None,
264
+ chat_keypad_type: Optional[str] = "None",
265
+ disable_notification: bool = False
266
+ ):
267
+ if chat_keypad and chat_keypad_type == "none":
268
+ chat_keypad_type == "New"
269
+
245
270
  return self.bot.send_document(
246
271
  chat_id=self.chat_id,
247
272
  path=path,
@@ -264,6 +289,8 @@ class Message:
264
289
  chat_keypad_type: Optional[str] = "None",
265
290
  disable_notification: bool = False
266
291
  ):
292
+ if chat_keypad and chat_keypad_type == "none":
293
+ chat_keypad_type == "New"
267
294
  return self.bot.send_image(
268
295
  chat_id=self.chat_id,
269
296
  path=path,
@@ -286,6 +313,8 @@ class Message:
286
313
  chat_keypad_type: Optional[str] = "None",
287
314
  disable_notification: bool = False
288
315
  ):
316
+ if chat_keypad and chat_keypad_type == "none":
317
+ chat_keypad_type == "New"
289
318
  return self.bot.send_music(
290
319
  chat_id=self.chat_id,
291
320
  path=path,
@@ -308,6 +337,8 @@ class Message:
308
337
  chat_keypad_type: Optional[str] = "None",
309
338
  disable_notification: bool = False
310
339
  ):
340
+ if chat_keypad and chat_keypad_type == "none":
341
+ chat_keypad_type == "New"
311
342
  return self.bot.send_voice(
312
343
  chat_id=self.chat_id,
313
344
  path=path,
@@ -330,6 +361,7 @@ class Message:
330
361
  chat_keypad_type: Optional[str] = "None",
331
362
  disable_notification: bool = False
332
363
  ):
364
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
333
365
  return self.bot.send_gif(
334
366
  chat_id=self.chat_id,
335
367
  path=path,
@@ -388,14 +420,6 @@ class Message:
388
420
  **kwargs
389
421
  })
390
422
 
391
- def reply_file(self, file_id: str, **kwargs) -> Dict[str, Any]:
392
- return self.bot._post("sendFile", {
393
- "chat_id": self.chat_id,
394
- "file_id": file_id,
395
- "reply_to_message_id": self.message_id,
396
- **kwargs
397
- })
398
-
399
423
  def edit(self, new_text: str) -> Dict[str, Any]:
400
424
  return self.bot.edit_message_text(
401
425
  chat_id=self.chat_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 4.5.2
3
+ Version: 4.5.11
4
4
  Summary: 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/blob/main/project_library.zip
@@ -1,9 +1,9 @@
1
1
  rubka/__init__.py,sha256=TR1DABU5Maz2eO62ZEFiwOqNU0dH6l6HZfqRUxeo4eY,194
2
- rubka/api.py,sha256=gzaH2nfZjpxlMwzNsgA4FFBR38bAfQK2-2oTPs555Xw,35160
3
- rubka/asynco.py,sha256=m3WztgmkzK6Jvrko8HxqLlIigWTbtJkdbDdQq3NtbMo,31994
2
+ rubka/api.py,sha256=0gj52uxIGmLCVRUxnvjIHF6MVBiXnVBdVr_SRXp2I4M,39416
3
+ rubka/asynco.py,sha256=DDAeES9qDQ9vegHT-7X7RL72G510YObFN7qqJ948NEQ,37647
4
4
  rubka/button.py,sha256=4fMSZR7vUADxSmw1R3_pZ4dw5uMLZX5sOkwPPyNTBDE,8437
5
5
  rubka/config.py,sha256=Bck59xkOiqioLv0GkQ1qPGnBXVctz1hKk6LT4h2EPx0,78
6
- rubka/context.py,sha256=j1scXTy_wBY52MmMixfZyIQnB0sdYjRwx17-8ZZmyB4,17017
6
+ rubka/context.py,sha256=KXfDqn3vir6oIupF7piKD89Sqj1MjWoSerS4WyyHXBw,18062
7
7
  rubka/decorators.py,sha256=hGwUoE4q2ImrunJIGJ_kzGYYxQf1ueE0isadqraKEts,1157
8
8
  rubka/exceptions.py,sha256=tujZt1XrhWaw-lmdeVadVceUptpw4XzNgE44sAAY0gs,90
9
9
  rubka/jobs.py,sha256=GvLMLsVhcSEzRTgkvnPISPEBN71suW2xXI0hUaUZPTo,378
@@ -33,7 +33,7 @@ rubka/adaptorrubka/types/socket/message.py,sha256=0WgLMZh4eow8Zn7AiSX4C3GZjQTkIg
33
33
  rubka/adaptorrubka/utils/__init__.py,sha256=OgCFkXdNFh379quNwIVOAWY2NP5cIOxU5gDRRALTk4o,54
34
34
  rubka/adaptorrubka/utils/configs.py,sha256=nMUEOJh1NqDJsf9W9PurkN_DLYjO6kKPMm923i4Jj_A,492
35
35
  rubka/adaptorrubka/utils/utils.py,sha256=5-LioLNYX_TIbQGDeT50j7Sg9nAWH2LJUUs-iEXpsUY,8816
36
- rubka-4.5.2.dist-info/METADATA,sha256=xgwDJfrcrmaI2Hr9YEugIt8_3OzJiAXBHx2sldoW7ZU,33216
37
- rubka-4.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- rubka-4.5.2.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
39
- rubka-4.5.2.dist-info/RECORD,,
36
+ rubka-4.5.11.dist-info/METADATA,sha256=_9gtchOWeb6ROIeF58OO4Egk7uDSL6Rc-xvcvAasyKg,33217
37
+ rubka-4.5.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ rubka-4.5.11.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
39
+ rubka-4.5.11.dist-info/RECORD,,
File without changes