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

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +81 -103
main.py CHANGED
@@ -698,27 +698,32 @@ 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: آپلودر خالص و مستقیم بر اساس مستندات رسمی 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
 
@@ -733,124 +738,99 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
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:
@@ -861,15 +841,13 @@ async def background_general_uploader(client, chat_id, file_name, file_type, cap
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
-
872
-
873
  # ==============================================================================
874
  # 🟢 پارت 12: توابع تغییر صدا و لیست گویندگان
875
  # ==============================================================================
 
698
  HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
699
 
700
  # ==============================================================================
701
+ # 🟢 پارت 11: سیستم آپلود ابری نوین (استفاده از سرورهای بله به عنوان S3 پرسرعت)
702
  # ==============================================================================
703
  import asyncio
704
  import os
705
  import aiohttp
706
 
707
+ # توکن ربات تستی بله شما (آپلودسنتر)
708
+ BALE_TOKEN = "2030030646:ioHMqrCsw0PwK5hTg_1Av1rsXZMiu-LETBI"
709
+ # در پیام‌رسان‌های تلگرام و بله، آیدی عددی ربات همان بخش اول توکن است
710
+ BALE_CHAT_ID = BALE_TOKEN.split(":")[0]
711
+
712
+ # 🟢 ۱. مدیریت صف آپلود ابری
713
  _upload_lock = None
714
  _shared_session = None
715
 
716
  def get_upload_lock():
717
  global _upload_lock
718
  if _upload_lock is None:
719
+ # ظرفیت روی 20 تنظیم شد (ارسال موشکی و بدون ارور)
720
+ _upload_lock = asyncio.Semaphore(20)
721
  return _upload_lock
722
 
723
  async def get_shared_session():
724
  global _shared_session
725
  if _shared_session is None or _shared_session.closed:
726
+ connector = aiohttp.TCPConnector(limit=100, keepalive_timeout=60)
727
  _shared_session = aiohttp.ClientSession(connector=connector)
728
  return _shared_session
729
 
 
738
  return f"File Read Error: {e}"
739
 
740
  error_logs = []
741
+ rubika_bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
742
+
 
 
 
 
 
 
 
743
  async with get_upload_lock():
744
  session = await get_shared_session()
745
+ download_link = None
746
 
747
+ # 🚀 فاز اول: آپلود فایل به سرورهای بله و دریافت لینک مستقیم
748
+ for attempt in range(3):
749
  try:
750
+ # ارسال فایل به چت خودِ ربات در بله
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
751
  form = aiohttp.FormData()
752
+ form.add_field('chat_id', BALE_CHAT_ID)
753
+ form.add_field('document', file_bytes, filename=os.path.basename(abs_path))
754
 
755
+ bale_upload_url = f"https://tapi.bale.ai/bot{BALE_TOKEN}/sendDocument"
756
+ async with session.post(bale_upload_url, data=form, timeout=aiohttp.ClientTimeout(total=60)) as resp:
757
+ if resp.status == 200:
758
+ b_data = await resp.json()
759
+ file_id = b_data.get('result', {}).get('document', {}).get('file_id')
760
+
761
+ if file_id:
762
+ # درخواست گرفتن مسیر فایل از سرور بله
763
+ bale_file_url = f"https://tapi.bale.ai/bot{BALE_TOKEN}/getFile?file_id={file_id}"
764
+ async with session.get(bale_file_url) as f_resp:
765
+ if f_resp.status == 200:
766
+ f_data = await f_resp.json()
767
+ file_path = f_data.get('result', {}).get('file_path')
768
+ if file_path:
769
+ # ساخت لینک دانلود مستقیم نهایی
770
+ download_link = f"https://tapi.bale.ai/file/bot{BALE_TOKEN}/{file_path}"
771
+ break
772
+ except Exception as e:
773
+ error_logs.append(f"Bale Upload Error (Attempt {attempt+1}): {str(e)[:30]}")
774
+ await asyncio.sleep(2)
775
 
776
+ # 🚀 فاز دوم: ارسال پیام متنی زیبا به کاربر در روبیکا
777
+ if download_link:
778
+ # 🟢 دیزاین جدید پیام با خطوط جداکننده و توضیحات کامل
779
+ final_caption = f"""{caption}
 
 
780
 
781
+ ➖➖➖➖➖➖➖➖➖➖
782
+ 🌐 **لینک دانلود مستقیم فایل:**
783
+ `{download_link}`
784
+ ➖➖➖➖➖➖➖➖➖➖
785
+
786
+ ⚠️ **راهنمای دانلود:**
787
+ لطفاً لینک بالا را کپی کرده و در مرورگر گوشی خود (مثل کروم، فایرفاکس یا سافاری) باز کنید تا فایلتان دانلود شود. (چون روبیکا اجازه نمی‌دهد، مستقیماً از اینجا روی لینک کلیک نکنید).
788
+
789
+ 🇮🇷 این لینک روی دامنه سایت پیام‌رسان داخلی «بله» قرار دارد و به راحتی با اینترنت ملی (بدون فیلترشکن) با بالاترین سرعت دانلود می‌شود.
790
+
791
+ *پ.ن: در صورتی که محدودیت‌های روبیکا در دریافت مستقیم فایل برطرف شود، سیستم را تغییر می‌دهیم تا دوباره فایل‌ها را به صورت مستقیم داخل همین ربات دریافت کنید.*"""
792
+
793
+ # ارسال مستقیم متنی از طریق API خام روبیکا
794
+ send_payload = {
795
+ "chat_id": str(chat_id),
796
+ "text": final_caption,
797
+ "chat_keypad_type": "New",
798
+ "chat_keypad": MAIN_KEYPAD_DICT
799
+ }
800
+
801
+ for attempt in range(3):
802
+ try:
803
  send_resp = await session.post(
804
+ f"https://botapi.rubika.ir/v3/{rubika_bot_token}/sendMessage",
805
  json=send_payload,
806
+ timeout=aiohttp.ClientTimeout(total=15)
807
  )
808
  s_data = await send_resp.json()
809
 
810
  if s_data.get("status") == "OK":
 
811
  return True
 
 
 
 
 
812
  else:
813
+ error_logs.append(f"Rubika Send API Error: {s_data.get('status')}")
814
+ except Exception as e:
815
+ error_logs.append(f"Rubika Send HTTP Error: {str(e)[:30]}")
816
+ await asyncio.sleep(2)
 
817
 
818
+ # بک‌آپ با کتابخانه در صورت کار نکردن API خام
819
+ try:
820
+ await client.send_message(chat_id, final_caption)
821
+ return True
822
  except Exception as e:
823
+ error_logs.append(f"Rubika Fallback Error: {str(e)[:30]}")
824
+
825
+ else:
826
+ error_logs.append("خطا در دریافت لینک دانلود از سرور ابری بله.")
827
 
828
+ return "❌ خطا در سیستم آپلود ابری:\n" + "\n".join(error_logs[-3:])
829
 
830
  # ==============================================================================
831
  # 🟢 ۲. تعریف کارگرهای پس‌زمینه عمومی (مشترک برای همه بخش‌ها)
832
  # ==============================================================================
833
+ _general_upload_workers = asyncio.Semaphore(20) # ظرفیت 20 عملیات پس‌زمینه همزمان
834
 
835
  async def background_general_uploader(client, chat_id, file_name, file_type, caption_text, str_chat_id, credit_key=None):
836
  async with _general_upload_workers:
 
841
  if not creds.get("is_premium") and credit_key:
842
  user_credits_db[str_chat_id][credit_key] += 1
843
  save_db(user_credits_db)
844
+ await send_with_keyboard(client, chat_id, f"❌ سیستم توزیع ابری گزارش داد:\nمتأسفانه ایجاد لینک دانلود با مشکل مواجه شد و اعتبار شما بازگردانده شد.\n`{str(res)[:500]}`", True)
845
  except: pass
846
  finally:
847
  if os.path.exists(file_name): os.remove(file_name)
848
 
849
 
850
 
 
 
851
  # ==============================================================================
852
  # 🟢 پارت 12: توابع تغییر صدا و لیست گویندگان
853
  # ==============================================================================