Opera8 commited on
Commit
499390c
·
verified ·
1 Parent(s): 3c50a88

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +122 -59
main.py CHANGED
@@ -698,111 +698,174 @@ HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
698
  HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
699
 
700
  # ==============================================================================
701
- # 🟢 پارت 11: آپلودر با استفاده انحصاری از کتابخانه رسمی روب‌پای (Rubpy)
702
  # ==============================================================================
703
  import asyncio
704
  import os
 
705
 
706
- # 🟢 ۱. مدیریت صف آپلود
707
  _upload_lock = None
 
708
 
709
  def get_upload_lock():
710
  global _upload_lock
711
  if _upload_lock is None:
712
- # برای اینکه کتابخانه کرش نکند، فایل‌ها را 2 تا 2 تا به کتابخانه می‌سپاریم
713
- _upload_lock = asyncio.Semaphore(10)
714
  return _upload_lock
715
 
 
 
 
 
 
 
 
716
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
717
  abs_path = os.path.abspath(file_name)
718
  if not os.path.exists(abs_path):
719
  return "File Not Found"
720
 
 
 
 
 
 
721
  error_logs = []
 
722
 
723
- # تشخیص نوع فایل
724
  api_file_type = "Image" if file_type in ["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
725
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
726
  api_file_type = "Music"
727
  if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
728
  api_file_type = "Music"
729
-
730
  async with get_upload_lock():
731
- backoff_time = 10 # زمان صبر اولیه در صورت برخورد به محدودیت
 
732
 
733
- # ربات ۵ بار تلاش می‌کند تا کتابخانه کار را انجام دهد
734
- for attempt in range(5):
735
  try:
736
- if api_file_type == "Image":
737
- if hasattr(client, "send_photo"):
738
- try:
739
- await client.send_photo(chat_id, photo=abs_path, caption=caption)
740
- except TypeError:
741
- await client.send_photo(chat_id, abs_path, caption=caption)
742
- return True
743
-
744
- elif api_file_type in ["Music", "Voice"]:
745
- if hasattr(client, "send_music"):
746
- try:
747
- await client.send_music(chat_id, abs_path, caption=caption)
748
- except TypeError:
749
- await client.send_music(chat_id, music=abs_path, caption=caption)
750
- return True
751
-
752
- else:
753
- if hasattr(client, "send_document"):
754
- try:
755
- await client.send_document(chat_id, document=abs_path, caption=caption)
756
- except TypeError:
757
- await client.send_document(chat_id, abs_path, caption=caption)
758
- return True
759
- elif hasattr(client, "send_file"):
760
- try:
761
- await client.send_file(chat_id, file=abs_path)
762
- except TypeError:
763
- await client.send_file(chat_id, abs_path)
764
- if caption:
765
- await send_with_keyboard(client, chat_id, caption, True)
766
- return True
767
-
768
- error_logs.append("متد مناسب در کتابخانه یافت نشد.")
769
- break # اگر متد کلاً وجود نداشت، از حلقه خارج می‌شویم
770
-
771
- except Exception as e:
772
- err_str = str(e)
773
- error_logs.append(f"تلاش {attempt+1} با کتابخانه: {err_str[:40]}")
774
 
775
- # اگر کتابخانه ارور TOO_REQUESTS داد، صبر می‌کنیم
776
- if "TOO_REQ" in err_str.upper() or "429" in err_str:
 
 
 
 
 
 
 
 
 
 
 
777
  await asyncio.sleep(backoff_time)
778
- backoff_time += 15 # دفعه بعد بیشتر صبر می‌کند
 
 
 
 
 
 
 
 
 
779
  else:
780
- await asyncio.sleep(4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
781
 
782
- return "❌ خطا در آپلود با کتابخانه روب‌پای:\n" + "\n".join(error_logs[-3:])
 
 
783
 
 
784
 
785
  # ==============================================================================
786
  # 🟢 ۲. تعریف کارگرهای پس‌زمینه عمومی (مشترک برای همه بخش‌ها)
787
  # ==============================================================================
788
- _general_upload_workers = asyncio.Semaphore(10) # ظرفیت پردازش پس‌زمینه
789
 
790
  async def background_general_uploader(client, chat_id, file_name, file_type, caption_text, str_chat_id, credit_key=None):
791
  async with _general_upload_workers:
792
  try:
793
  res = await helper_upload_file(client, chat_id, file_name, file_type, caption_text)
794
  if res is not True:
795
- # عودت اعتبار در صورت شکست قطعی آپلود
796
  creds = get_user_credits(str_chat_id)
797
  if not creds.get("is_premium") and credit_key:
798
  user_credits_db[str_chat_id][credit_key] += 1
799
  save_db(user_credits_db)
800
- await send_with_keyboard(client, chat_id, f"❌ سرور ارسال گزارش داد:\nآپلود {file_type} انجام نشد و اعتبار شما برگشت داده شد.\n`{str(res)[:500]}`", True)
801
- except Exception as e:
802
- pass
803
  finally:
804
- if os.path.exists(file_name):
805
- os.remove(file_name)
806
 
807
 
808
 
 
698
  HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
699
 
700
  # ==============================================================================
701
+ # 🟢 پارت 11: آپلودر خالص و مستقیم بر اساس مستندات رسمی API روبیکا (بدون باگ کتابخانه)
702
  # ==============================================================================
703
  import asyncio
704
  import os
705
+ import aiohttp
706
 
707
+ # 🟢 ۱. مدیریت صف آپلود برای جلوگیری از خطای TOO_REQUESTS
708
  _upload_lock = None
709
+ _shared_session = None
710
 
711
  def get_upload_lock():
712
  global _upload_lock
713
  if _upload_lock is None:
714
+ # قفل ارسال را روی 3 می‌گذاریم تا فایل‌ها با نظم و طبق استاندارد سرور روبیکا ارسال شوند
715
+ _upload_lock = asyncio.Semaphore(3)
716
  return _upload_lock
717
 
718
+ async def get_shared_session():
719
+ global _shared_session
720
+ if _shared_session is None or _shared_session.closed:
721
+ connector = aiohttp.TCPConnector(limit=50, keepalive_timeout=60)
722
+ _shared_session = aiohttp.ClientSession(connector=connector)
723
+ return _shared_session
724
+
725
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
726
  abs_path = os.path.abspath(file_name)
727
  if not os.path.exists(abs_path):
728
  return "File Not Found"
729
 
730
+ try:
731
+ file_bytes = await asyncio.to_thread(sync_read_file, abs_path)
732
+ except Exception as e:
733
+ return f"File Read Error: {e}"
734
+
735
  error_logs = []
736
+ bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
737
 
738
+ # تعیین نوع دقیق فایل طبق Enum مستندات روبیکا (FileTypeEnum)
739
  api_file_type = "Image" if file_type in ["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
740
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
741
  api_file_type = "Music"
742
  if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
743
  api_file_type = "Music"
744
+
745
  async with get_upload_lock():
746
+ session = await get_shared_session()
747
+ backoff_time = 5
748
 
749
+ # 🚀 فاز اصلی: استفاده ۱۰۰ درصدی از API خام روبیکا طبق مستندات
750
+ for attempt in range(15):
751
  try:
752
+ # ---------------------------------------------------------
753
+ # مرحله ۱: متد requestSendFile (دریافت آدرس آپلود)
754
+ # ---------------------------------------------------------
755
+ req_resp = await session.post(
756
+ f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile",
757
+ json={"type": api_file_type},
758
+ timeout=aiohttp.ClientTimeout(total=20)
759
+ )
760
+ if req_resp.status != 200:
761
+ error_logs.append(f"reqSend HTTP {req_resp.status}")
762
+ await asyncio.sleep(3)
763
+ continue
764
+
765
+ req_data = await req_resp.json()
766
+ if req_data.get("status") in ["TOO_REQUESTS", "TOO_REQ"]:
767
+ error_logs.append(f"TOO_REQ (گرفتن لینک - صبر {backoff_time}s)")
768
+ await asyncio.sleep(backoff_time)
769
+ backoff_time += 5
770
+ continue
771
+
772
+ upload_url = req_data.get("data", {}).get("upload_url")
773
+ if not upload_url:
774
+ error_logs.append("لینک آپلود دریافت نشد")
775
+ await asyncio.sleep(3)
776
+ continue
777
+
778
+ # ---------------------------------------------------------
779
+ # مرحله ۲: آپلود فایل (multipart/form-data)
780
+ # ---------------------------------------------------------
781
+ form = aiohttp.FormData()
782
+ form.add_field('file', file_bytes, filename=os.path.basename(abs_path))
 
 
 
 
 
 
 
783
 
784
+ up_resp = await session.post(
785
+ upload_url,
786
+ data=form,
787
+ timeout=aiohttp.ClientTimeout(total=120)
788
+ )
789
+ if up_resp.status != 200:
790
+ error_logs.append(f"Upload HTTP {up_resp.status}")
791
+ await asyncio.sleep(3)
792
+ continue
793
+
794
+ up_data = await up_resp.json()
795
+ if up_data.get("status") in ["TOO_REQUESTS", "TOO_REQ"]:
796
+ error_logs.append(f"TOO_REQ (آپلود - صبر {backoff_time}s)")
797
  await asyncio.sleep(backoff_time)
798
+ backoff_time += 5
799
+ continue
800
+
801
+ final_file_id = None
802
+ if up_data.get("status") in ["OK", "OK_DET"]:
803
+ # استخراج file_id با توجه به تفاوت‌های ساختاری سرور روبیکا
804
+ if "data" in up_data and isinstance(up_data["data"], dict):
805
+ final_file_id = up_data["data"].get("file_id") or up_data["data"].get("id")
806
+ else:
807
+ final_file_id = up_data.get("file_id")
808
  else:
809
+ error_logs.append(f"Up Error: {up_data.get('status')}")
810
+
811
+ # ---------------------------------------------------------
812
+ # مرحله ۳: متد sendFile (ارسال فایل نهایی به کاربر)
813
+ # ---------------------------------------------------------
814
+ if final_file_id:
815
+ send_payload = {
816
+ "chat_id": str(chat_id),
817
+ "file_id": str(final_file_id),
818
+ "text": caption, # طبق مستندات شما، نام فیلد متن text است نه caption
819
+ "chat_keypad_type": "New",
820
+ "chat_keypad": MAIN_KEYPAD_DICT
821
+ }
822
+ send_resp = await session.post(
823
+ f"https://botapi.rubika.ir/v3/{bot_token}/sendFile",
824
+ json=send_payload,
825
+ timeout=aiohttp.ClientTimeout(total=20)
826
+ )
827
+ s_data = await send_resp.json()
828
+
829
+ if s_data.get("status") == "OK":
830
+ await asyncio.sleep(1)
831
+ return True
832
+ elif s_data.get("status") in ["TOO_REQUESTS", "TOO_REQ"]:
833
+ error_logs.append(f"TOO_REQ (ارسال نهایی - صبر {backoff_time}s)")
834
+ await asyncio.sleep(backoff_time)
835
+ backoff_time += 5
836
+ continue
837
+ else:
838
+ error_logs.append(f"Send Error: {s_data.get('status')}")
839
+ else:
840
+ if not final_file_id and "INVALID_INPUT" in str(up_data):
841
+ api_file_type = "File"
842
+ error_logs.append("تغییر اجباری نوع فایل")
843
 
844
+ except Exception as e:
845
+ error_logs.append(f"تلاش {attempt+1} خطا: {str(e)[:25]}")
846
+ await asyncio.sleep(3)
847
 
848
+ return "❌ خطا در آپلود (API خام):\n" + "\n".join(error_logs[-5:])
849
 
850
  # ==============================================================================
851
  # 🟢 ۲. تعریف کارگرهای پس‌زمینه عمومی (مشترک برای همه بخش‌ها)
852
  # ==============================================================================
853
+ _general_upload_workers = asyncio.Semaphore(50) # هسته ربات آزاد است، ظرفیت روی 50 تنظیم شد
854
 
855
  async def background_general_uploader(client, chat_id, file_name, file_type, caption_text, str_chat_id, credit_key=None):
856
  async with _general_upload_workers:
857
  try:
858
  res = await helper_upload_file(client, chat_id, file_name, file_type, caption_text)
859
  if res is not True:
 
860
  creds = get_user_credits(str_chat_id)
861
  if not creds.get("is_premium") and credit_key:
862
  user_credits_db[str_chat_id][credit_key] += 1
863
  save_db(user_credits_db)
864
+ await send_with_keyboard(client, chat_id, f"❌ سرور ارسال گزارش داد:\nمتأسفانه روبیکا اجازه آپلود را نداد و سهمیه شما عودت داده شد.\n`{str(res)[:500]}`", True)
865
+ except: pass
 
866
  finally:
867
+ if os.path.exists(file_name): os.remove(file_name)
868
+
869
 
870
 
871