Opera8 commited on
Commit
52bd98e
·
verified ·
1 Parent(s): 7447518

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +145 -41
main.py CHANGED
@@ -703,17 +703,132 @@ HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
703
  # 🟢 پارت 11: آپلودر دوگانه هوشمند (آپلود در بله + بکاپ خودکار در روبیکا)
704
  # ==============================================================================
705
  BALE_BOT_TOKEN = os.environ.get("BALE_BOT_TOKEN", "").strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
706
 
707
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
708
  abs_path = os.path.abspath(file_name)
709
- error_logs =[]
710
 
711
  # ==========================================
712
  # فاز 1: تلاش برای آپلود در بله (ساخت لینک)
713
  # ==========================================
714
  if BALE_BOT_TOKEN:
715
  bale_chat_id = BALE_BOT_TOKEN.split(":")[0]
716
- for attempt in range(3): # ۳ بار تلاش در سرور بله
717
  try:
718
  bale_url = f"https://tapi.bale.ai/bot{BALE_BOT_TOKEN}/sendDocument"
719
  with open(abs_path, "rb") as f:
@@ -738,60 +853,49 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
738
  continue
739
 
740
  download_url = f"https://tapi.bale.ai/file/bot{BALE_BOT_TOKEN}/{file_id}"
741
- final_text = f"""{caption}\n\n━━━━━━━━━━━━━━━━━━━\n🌐 لینک دانلود فایل شما:\n\n{download_url}\n\n━━━━━━━━━━━━━━━━━━━\n⚠️ **راهنمای دانلود:**\nلطفاً لینک بالا را کپی کرده و در **مرورگر گوشی خود** باز کنید.\n*(مستقیماً کلیک نکنید)*"""
 
 
742
 
743
  send_res = await send_with_keyboard(client, chat_id, final_text, True)
744
- if send_res: return True
 
 
 
 
 
 
 
 
 
 
 
 
745
  else:
746
  error_logs.append(f"Bale API Err: {bale_data.get('description')}")
747
  else:
748
  error_logs.append(f"Bale HTTP Error: {resp.status}")
749
- if resp.status in[500, 502, 503]: await asyncio.sleep(2)
750
  except Exception as e:
751
  error_logs.append(f"Bale Err: {str(e)[:100]}")
752
  await asyncio.sleep(2)
753
 
754
  # ==========================================
755
- # فاز 2: سیستم نجات! (آپلود مستقیم در روبیکا)
756
- # (اگر بله قطع بود، فایل مستقیما تو روبیکا ار��ال میشه)
757
  # ==========================================
758
- api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
759
- if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'): api_file_type = "Music"
760
- if api_file_type == "File" and abs_path.lower().endswith('.mp3'): api_file_type = "Music"
761
-
762
- fallback_caption = f"{caption}\n\n⚠️ (به دلیل اختلال سرورهای بله، فایل موقتاً به صورت مستقیم در روبیکا ارسال شد)"
763
 
764
- for attempt in range(5):
 
 
765
  try:
766
- sent_success = False
767
-
768
- if api_file_type == "Image" and hasattr(client, "send_photo"):
769
- try: await client.send_photo(chat_id, photo=abs_path, caption=fallback_caption); sent_success = True
770
- except: await client.send_photo(chat_id, abs_path, caption=fallback_caption); sent_success = True
771
- elif api_file_type == "Voice" and hasattr(client, "send_voice"):
772
- try: await client.send_voice(chat_id, abs_path, caption=fallback_caption); sent_success = True
773
- except: await client.send_voice(chat_id, file=abs_path, caption=fallback_caption); sent_success = True
774
- elif api_file_type == "Music" and hasattr(client, "send_music"):
775
- try: await client.send_music(chat_id, abs_path, caption=fallback_caption); sent_success = True
776
- except: await client.send_music(chat_id, music=abs_path, caption=fallback_caption); sent_success = True
777
-
778
- if not sent_success:
779
- if hasattr(client, "send_document"):
780
- try: await client.send_document(chat_id, document=abs_path, caption=fallback_caption); sent_success = True
781
- except: await client.send_document(chat_id, abs_path, caption=fallback_caption); sent_success = True
782
- elif hasattr(client, "send_file"):
783
- try: await client.send_file(chat_id, file=abs_path)
784
- except: await client.send_file(chat_id, abs_path)
785
- if fallback_caption: await send_with_keyboard(client, chat_id, fallback_caption, True)
786
- sent_success = True
787
-
788
- if sent_success:
789
- return True
790
-
791
- except Exception as e:
792
- error_logs.append(f"Rubpy Send Err: {str(e)[:100]}")
793
- await asyncio.sleep(3)
794
 
 
 
 
 
795
  return "\n".join(error_logs[-5:])
796
 
797
  # ==============================================================================
 
703
  # 🟢 پارت 11: آپلودر دوگانه هوشمند (آپلود در بله + بکاپ خودکار در روبیکا)
704
  # ==============================================================================
705
  BALE_BOT_TOKEN = os.environ.get("BALE_BOT_TOKEN", "").strip()
706
+ import shutil
707
+ import uuid
708
+ import asyncio
709
+ import os
710
+ import aiohttp
711
+ from pydub import AudioSegment
712
+
713
+ async def official_rubika_upload(chat_id, target_path, file_type, caption):
714
+ """اجرای دقیق 3 مرحله مستندات رسمی روبیکا به همراه تشخیص و تبدیل فرمت‌های تقلبی"""
715
+ global bot_token
716
+ if not bot_token: return False, "توکن ربات یافت نشد", target_path
717
+
718
+ api_file_type = "File"
719
+ if file_type in ["photo", "Image", "image"]: api_file_type = "Image"
720
+ elif file_type in ["voice", "Voice", "audio", "Music", "music"]: api_file_type = "Music"
721
+
722
+ original_path = target_path
723
+
724
+ # 🟢 تشخیص فایل‌های صوتی که پسوند mp3 دارند اما در واقع wav هستند
725
+ if api_file_type == "Music":
726
+ base_name, ext = os.path.splitext(target_path)
727
+ needs_conversion = (ext.lower() != '.mp3')
728
+
729
+ if not needs_conversion:
730
+ try:
731
+ with open(target_path, 'rb') as f:
732
+ header = f.read(4)
733
+ if header.startswith(b'RIFF') or header.startswith(b'OggS') or header.startswith(b'fLaC'):
734
+ needs_conversion = True
735
+ except:
736
+ pass
737
+
738
+ if needs_conversion:
739
+ mp3_path = f"{base_name}_conv_{uuid.uuid4().hex[:4]}.mp3"
740
+ def convert_to_mp3():
741
+ try:
742
+ audio = AudioSegment.from_file(original_path)
743
+ audio.export(mp3_path, format="mp3", bitrate="128k")
744
+ return True
745
+ except Exception as e:
746
+ print(f"Error converting to MP3: {e}")
747
+ return False
748
+
749
+ # 🚀 استفاده از تردپول عظیم برای جلوگیری از کندی سرور در تعداد کاربر بالا
750
+ is_converted = await asyncio.to_thread(convert_to_mp3)
751
+ if is_converted and os.path.exists(mp3_path):
752
+ target_path = mp3_path
753
+
754
+ try:
755
+ async with aiohttp.ClientSession() as session:
756
+ # 1️⃣ مرحله اول: requestSendFile (درخواست لینک آپلود)
757
+ req_url = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
758
+ async with session.post(req_url, json={"type": api_file_type}, timeout=30) as r1:
759
+ if r1.status != 200: return False, f"خطا در ارتباط با سرور: HTTP {r1.status}", target_path
760
+ d1 = await r1.json()
761
+ upload_url = d1.get("data", {}).get("upload_url")
762
+ if not upload_url: return False, "آدرس آپلود در سرور یافت نشد", target_path
763
+
764
+ # 2️⃣ مرحله دوم: آپلود فایل در لینک دریافتی
765
+ with open(target_path, 'rb') as f:
766
+ form = aiohttp.FormData()
767
+ form.add_field('file', f, filename=os.path.basename(target_path))
768
+ async with session.post(upload_url, data=form, timeout=120) as r2:
769
+ if r2.status != 200: return False, "خطا در آپلود فایل", target_path
770
+ d2 = await r2.json()
771
+ file_id = d2.get("data", {}).get("file_id")
772
+ if not file_id: return False, "فایل آیدی دریافت نشد", target_path
773
+
774
+ # 3️⃣ مرحله سوم: sendFile (ارسال فایل نهایی به چت کاربر)
775
+ send_url = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
776
+ payload = {
777
+ "chat_id": str(chat_id),
778
+ "file_id": str(file_id),
779
+ "text": caption
780
+ }
781
+ async with session.post(send_url, json=payload, timeout=30) as r3:
782
+ if r3.status != 200: return False, "خطا در ارسال پیام نهایی", target_path
783
+ d3 = await r3.json()
784
+ if d3.get("status") == "OK" or d3.get("status_det") == "OK":
785
+ return True, "موفق", target_path
786
+ else:
787
+ return False, f"ارور ارسال پیام: {d3.get('status_det')}", target_path
788
+
789
+ except Exception as e:
790
+ return False, str(e), target_path
791
+
792
+
793
+ async def background_rubika_upload(client, chat_id, target_path, file_type, caption):
794
+ """تسک (کارگر) پس‌زمینه که کاملا مستقل عمل کرده و هیچ کندی در ربات ایجاد نمی‌کند"""
795
+ final_path = target_path
796
+ new_path = target_path
797
+ try:
798
+ await asyncio.sleep(2.0)
799
+
800
+ if not os.path.exists(final_path): return
801
+
802
+ # 🚀 ارسال با کپشن اصلی کاربر بدون هیچ متن اضافی (دقیقاً مشابه اطلاعات فایل)
803
+ success, err_msg, new_path = await official_rubika_upload(chat_id, final_path, file_type, caption)
804
+
805
+ if not success:
806
+ debug_txt = f"❌ [دیباگ کارگر]: آپلود مستقیم با API روبیکا شکست خورد.\nارور:\n`{err_msg[:600]}`"
807
+ try: await send_with_keyboard(client, chat_id, debug_txt, True)
808
+ except: pass
809
+
810
+ except Exception:
811
+ pass
812
+ finally:
813
+ # پاکسازی هوشمند فایل‌های موقت بدون ایجاد اختلال
814
+ try:
815
+ if os.path.exists(final_path): os.remove(final_path)
816
+ except: pass
817
+ try:
818
+ if new_path != final_path and os.path.exists(new_path): os.remove(new_path)
819
+ except: pass
820
+
821
 
822
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
823
  abs_path = os.path.abspath(file_name)
824
+ error_logs = []
825
 
826
  # ==========================================
827
  # فاز 1: تلاش برای آپلود در بله (ساخت لینک)
828
  # ==========================================
829
  if BALE_BOT_TOKEN:
830
  bale_chat_id = BALE_BOT_TOKEN.split(":")[0]
831
+ for attempt in range(3):
832
  try:
833
  bale_url = f"https://tapi.bale.ai/bot{BALE_BOT_TOKEN}/sendDocument"
834
  with open(abs_path, "rb") as f:
 
853
  continue
854
 
855
  download_url = f"https://tapi.bale.ai/file/bot{BALE_BOT_TOKEN}/{file_id}"
856
+
857
+ # حذف متن اضافه در انتهای لینک بله و برگشت به حالت قبل
858
+ final_text = f"{caption}\n\n━━━━━━━━━━━━━━━━━━━\n🌐 لینک دانلود فایل شما:\n\n{download_url}\n\n━━━━━━━━━━━━━━━━━━━\n⚠️ **راهنمای دانلود:**\nلطفاً لینک بالا را کپی کرده و در **مرورگر گوشی خود** باز کنید.\n*(مستقیماً کلیک نکنید)*"
859
 
860
  send_res = await send_with_keyboard(client, chat_id, final_text, True)
861
+
862
+ if send_res:
863
+ try:
864
+ # گرفتن کپی از فایل به صورت غیرهمزمان (آزاد کردن هسته پردازشی برای ترافیک بالا)
865
+ base_name, ext = os.path.splitext(abs_path)
866
+ bg_target_path = f"{base_name}_bg_{uuid.uuid4().hex[:6]}{ext}"
867
+ await asyncio.to_thread(shutil.copy2, abs_path, bg_target_path)
868
+
869
+ # 🟢 ایجاد یک کارگر پس‌زمینه کاملاً مستقل برای هزاران کاربر همزمان
870
+ asyncio.create_task(background_rubika_upload(client, chat_id, bg_target_path, file_type, caption))
871
+ except Exception:
872
+ pass
873
+ return True
874
  else:
875
  error_logs.append(f"Bale API Err: {bale_data.get('description')}")
876
  else:
877
  error_logs.append(f"Bale HTTP Error: {resp.status}")
878
+ if resp.status in [500, 502, 503]: await asyncio.sleep(2)
879
  except Exception as e:
880
  error_logs.append(f"Bale Err: {str(e)[:100]}")
881
  await asyncio.sleep(2)
882
 
883
  # ==========================================
884
+ # فاز 2: سیستم نجات! (اگر بله قطع بود، مستقیم ارسال شود)
 
885
  # ==========================================
886
+ fallback_caption = f"{caption}\n\n⚠️ (به دلیل اختلال سرورهای بله، فایل مستقیماً ارسال شد)"
 
 
 
 
887
 
888
+ success, err_msg, new_path = await official_rubika_upload(chat_id, abs_path, file_type, fallback_caption)
889
+
890
+ if new_path != abs_path:
891
  try:
892
+ if os.path.exists(new_path): os.remove(new_path)
893
+ except: pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894
 
895
+ if success:
896
+ return True
897
+
898
+ error_logs.append(f"Rubika API Err: {err_msg}")
899
  return "\n".join(error_logs[-5:])
900
 
901
  # ==============================================================================