Spaces:
Sleeping
Sleeping
| import os | |
| import asyncio | |
| import aiohttp | |
| import threading | |
| import uuid | |
| import urllib.parse | |
| import traceback | |
| import subprocess | |
| import shutil | |
| import time | |
| import re | |
| from flask import Flask | |
| from rubpy.bot import BotClient, filters | |
| from pyrogram import Client | |
| # ============================================================================== | |
| # 🟢 تنظیمات اصلی ربات | |
| # ============================================================================== | |
| app = Flask(__name__) | |
| def home(): | |
| return "🚀 ربات هوشمند انتقال به فضای ابری (تلگرام + وب) فعال است!" | |
| def run_flask(): | |
| app.run(host="0.0.0.0", port=7860, threaded=True) | |
| bot_token = os.environ.get("RUBIKA_AUTH", "توکن_روبیکا").strip() | |
| GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "توکن_گیتهاب").strip() | |
| TG_BOT_TOKEN = os.environ.get("TG_BOT_TOKEN", "توکن_تلگرام").strip() | |
| GITHUB_REPO = "hajiliker6-source/internet-melli" | |
| TG_API_ID = 6 | |
| TG_API_HASH = "eb06d4abfb49dc3eeb1aeb98ae0f581e" | |
| bot = BotClient(bot_token) | |
| BOT_GUID = None | |
| git_lock = asyncio.Lock() | |
| # ============================================================================== | |
| # 🟢 تنظیمات کلاینت تلگرام | |
| # ============================================================================== | |
| tg_client = None | |
| is_tg_started = False | |
| if TG_BOT_TOKEN and TG_BOT_TOKEN != "توکن_تلگرام": | |
| tg_client = Client( | |
| "tg_bot_session", | |
| api_id=TG_API_ID, | |
| api_hash=TG_API_HASH, | |
| bot_token=TG_BOT_TOKEN, | |
| in_memory=True | |
| ) | |
| async def ensure_tg_started(): | |
| global is_tg_started | |
| if tg_client and not is_tg_started: | |
| await tg_client.start() | |
| is_tg_started = True | |
| # ============================================================================== | |
| # 🟢 سیستم هوشمند مدیریت فضای ابری (بدون محدودیت فضا) | |
| # ============================================================================== | |
| async def get_or_create_repo(session, owner, base_name, token): | |
| """ | |
| بررسی حجم مخازن. اگر حجم به 4.5 گیگ رسیده بود، | |
| مخزن بعدی (مثلاً نام-1) را میسازد یا انتخاب میکند. | |
| """ | |
| headers = { | |
| "Authorization": f"token {token}", | |
| "Accept": "application/vnd.github.v3+json" | |
| } | |
| repo_index = 0 | |
| while True: | |
| repo_name = base_name if repo_index == 0 else f"{base_name}-{repo_index}" | |
| full_repo = f"{owner}/{repo_name}" | |
| url = f"https://api.github.com/repos/{full_repo}" | |
| async with session.get(url, headers=headers) as resp: | |
| if resp.status == 200: | |
| data = await resp.json() | |
| size_kb = data.get("size", 0) | |
| if size_kb < 4500000: | |
| return full_repo | |
| elif resp.status == 404: | |
| create_url = "https://api.github.com/user/repos" | |
| payload = { | |
| "name": repo_name, | |
| "private": False, | |
| "auto_init": True | |
| } | |
| async with session.post(create_url, headers=headers, json=payload) as post_resp: | |
| if post_resp.status in [201, 200]: | |
| await asyncio.sleep(2) | |
| return full_repo | |
| else: | |
| error_log = await post_resp.text() | |
| raise Exception(f"خطا در ساخت فضای جدید ({repo_name}): {error_log}") | |
| else: | |
| resp_log = await resp.text() | |
| raise Exception(f"خطای دسترسی به سرور: {resp_log}") | |
| repo_index += 1 | |
| # ============================================================================== | |
| # 🟢 تابع دانلود از تلگرام | |
| # ============================================================================== | |
| async def download_from_telegram(url, chat_id, message_id, client): | |
| status_msg_id = None | |
| try: | |
| status_msg = await client.send_message(chat_id, "⏳ در حال برقراری ارتباط با سرورهای تلگرام...", reply_to_message_id=message_id) | |
| status_msg_id = getattr(status_msg, 'message_id', None) | |
| if not status_msg_id and isinstance(status_msg, dict): | |
| status_msg_id = status_msg.get('message_update', {}).get('message_id') or status_msg.get('message_id') | |
| except: pass | |
| try: | |
| if not tg_client: raise Exception("توکن تلگرام تنظیم نشده است.") | |
| await ensure_tg_started() | |
| match = re.search(r"t\.me/([^/]+)/(\d+)", url) | |
| if not match: raise Exception("لینک تلگرام نامعتبر است.") | |
| channel_username, msg_id = match.group(1), int(match.group(2)) | |
| if status_msg_id: | |
| try: await client.edit_message_text(chat_id, status_msg_id, "⏳ در حال دریافت فایل از تلگرام...") | |
| except: pass | |
| msg = await tg_client.get_messages(channel_username, msg_id) | |
| if not msg or not msg.media: raise Exception("فایلی یافت نشد.") | |
| filename = None | |
| if getattr(msg, 'document', None): filename = msg.document.file_name | |
| elif getattr(msg, 'video', None): filename = msg.video.file_name | |
| elif getattr(msg, 'audio', None): filename = msg.audio.file_name | |
| elif getattr(msg, 'photo', None): filename = f"photo_{uuid.uuid4().hex[:6]}.jpg" | |
| if not filename: filename = f"tg_file_{uuid.uuid4().hex[:6]}.dat" | |
| temp_dir = "/app/downloads" | |
| os.makedirs(temp_dir, exist_ok=True) | |
| file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}") | |
| await tg_client.download_media(msg, file_name=file_path) | |
| return file_path, filename, status_msg_id | |
| except Exception as e: | |
| if status_msg_id: | |
| try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای تلگرام: {str(e)[:100]}") | |
| except: pass | |
| return None, None, status_msg_id | |
| # ============================================================================== | |
| # 🟢 تابع دانلود مستقیم (وب) | |
| # ============================================================================== | |
| async def download_large_file(url, chat_id, message_id, client): | |
| if "dropbox.com" in url: | |
| url = url.replace("dl=0", "dl=1") if "dl=0" in url else (url + ("&dl=1" if "?" in url else "?dl=1")) | |
| temp_dir = "/app/downloads" | |
| os.makedirs(temp_dir, exist_ok=True) | |
| parsed_url = urllib.parse.urlparse(url) | |
| filename = os.path.basename(parsed_url.path) | |
| if not filename or '.' not in filename: filename = f"file_{uuid.uuid4().hex[:8]}.dat" | |
| file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}") | |
| status_msg_id = None | |
| try: | |
| status_msg = await client.send_message(chat_id, "⏳ در حال دانلود در سرور...", reply_to_message_id=message_id) | |
| status_msg_id = getattr(status_msg, 'message_id', None) | |
| except: pass | |
| try: | |
| headers = {"User-Agent": "Mozilla/5.0"} | |
| async with aiohttp.ClientSession(headers=headers) as session: | |
| async with session.get(url, timeout=0) as resp: | |
| if resp.status != 200: | |
| raise Exception(f"سرور مبدا خطای {resp.status} برگرداند.") | |
| with open(file_path, 'wb') as f: | |
| async for chunk in resp.content.iter_chunked(2 * 1024 * 1024): | |
| if chunk: f.write(chunk) | |
| return file_path, filename, status_msg_id | |
| except Exception as e: | |
| if status_msg_id: | |
| try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای دانلود وب: {str(e)[:100]}") | |
| except: pass | |
| return None, None, status_msg_id | |
| # ============================================================================== | |
| # 🟢 توابع انتقال به فضای ابری و پردازش نهایی | |
| # ============================================================================== | |
| def split_file_for_winrar(file_path, dest_dir, base_filename): | |
| chunk_size = 95 * 1024 * 1024 | |
| part_num = 1 | |
| os.makedirs(dest_dir, exist_ok=True) | |
| with open(file_path, 'rb') as f: | |
| while True: | |
| chunk = f.read(chunk_size) | |
| if not chunk: break | |
| part_path = os.path.join(dest_dir, f"{base_filename}.{part_num:03d}") | |
| with open(part_path, 'wb') as p: p.write(chunk) | |
| part_num += 1 | |
| async def process_and_commit_to_cloud(client, chat_id, message_id, url): | |
| url_l = url.lower() | |
| if "t.me/" in url_l: | |
| file_path, filename, status_msg_id = await download_from_telegram(url, chat_id, message_id, client) | |
| else: | |
| file_path, filename, status_msg_id = await download_large_file(url, chat_id, message_id, client) | |
| if not file_path or not os.path.exists(file_path): | |
| return | |
| try: | |
| if status_msg_id: | |
| try: await client.edit_message_text(chat_id, status_msg_id, "✅ فایل با موفقیت دریافت شد.\n✂️ در حال انتقال به سرورهای پرسرعت...") | |
| except: pass | |
| async with git_lock: | |
| repo_owner, repo_base_name = GITHUB_REPO.split('/') | |
| async with aiohttp.ClientSession() as session: | |
| active_repo = await get_or_create_repo(session, repo_owner, repo_base_name, GITHUB_TOKEN) | |
| current_timestamp = int(time.time()) | |
| branch_name = f"DL-{current_timestamp}-{uuid.uuid4().hex[:4]}" | |
| repo_url = f"https://oauth2:{GITHUB_TOKEN}@github.com/{active_repo}.git" | |
| work_dir = "/app/git_workspace" | |
| if os.path.exists(work_dir): shutil.rmtree(work_dir) | |
| subprocess.run(["git", "clone", repo_url, work_dir], check=True, capture_output=True) | |
| subprocess.run(["git", "config", "user.email", "bot@alpha.io"], cwd=work_dir) | |
| subprocess.run(["git", "config", "user.name", "AI Alpha Bot"], cwd=work_dir) | |
| subprocess.run(["git", "checkout", "--orphan", branch_name], cwd=work_dir, check=True) | |
| subprocess.run(["git", "rm", "-rf", "."], cwd=work_dir, capture_output=True) | |
| file_size = os.path.getsize(file_path) | |
| is_split = False | |
| if file_size >= 100 * 1024 * 1024: | |
| is_split = True | |
| file_folder = os.path.join(work_dir, filename + "_parts") | |
| split_file_for_winrar(file_path, file_folder, filename) | |
| else: | |
| # کمتر از ۱۰۰ مگابایت: مستقیما کپی میشود | |
| shutil.copy2(file_path, os.path.join(work_dir, filename)) | |
| subprocess.run(["git", "add", "."], cwd=work_dir, check=True) | |
| subprocess.run(["git", "commit", "-m", f"Upload: {filename}"], cwd=work_dir, check=True) | |
| subprocess.run(["git", "push", "origin", branch_name], cwd=work_dir, check=True) | |
| # 🟢 تمامی فایلها (چه پارتبندی شده، چه تکی) از طریق این لینک ZIP قابل دریافت هستند | |
| download_link = f"https://codeload.github.com/{active_repo}/zip/refs/heads/{branch_name}" | |
| if is_split: | |
| extract_guide = ( | |
| "🛑 **راهنمای استخراج :**\n\n" | |
| "برای جلوگیری از ارور، حتماً طبق این مراحل عمل کنید:\n" | |
| "1️⃣ فایل ZIP را دانلود کرده و آن را Extract کنید.\n" | |
| "2️⃣ حالا پارت اول یعنی فایلی که آخرش `001.` است را پیدا کنید.\n" | |
| "3️⃣ روی پارت اول کلیک راست کرده (یا نگه دارید) و گزینه Extract Here را بزنید.\n\n" | |
| "💡 نرمافزار پیشنهادی :\n" | |
| "📱 در موبایل: rar\n" | |
| "💻 در کامپیوتر: 7-Zip" | |
| ) | |
| else: | |
| extract_guide = ( | |
| "💡 **راهنمای استخراج :**\n" | |
| "این فایل نیاز به پارتبندی نداشته است. برای دانلود سریعتر، در یک فایل ZIP قرار داده شده است. فقط کافیست فایل ZIP را دانلود کرده و فایل اصلی خود را از درون آن خارج کنید." | |
| ) | |
| success_text = ( | |
| f"✅ فایل شما با موفقیت آماده شد.\n\n" | |
| f"🔗 **لینک دانلود مستقیم:**\n" | |
| f"{download_link}\n\n" | |
| f"⚠️ مهلت دانلود: این لینک فقط ۲ ساعت فعال است.\n\n" | |
| f"{extract_guide}" | |
| ) | |
| if status_msg_id: | |
| try: await client.edit_message_text(chat_id, status_msg_id, success_text) | |
| except: await client.send_message(chat_id, success_text) | |
| else: await client.send_message(chat_id, success_text) | |
| except Exception as e: | |
| if status_msg_id: | |
| try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای انتقال ابری:\n{str(e)[:150]}") | |
| except: pass | |
| finally: | |
| if file_path and os.path.exists(file_path): os.remove(file_path) | |
| if os.path.exists("/app/git_workspace"): shutil.rmtree("/app/git_workspace") | |
| # ============================================================================== | |
| # 🟢 سیستم حذف خودکار | |
| # ============================================================================== | |
| async def cleanup_expired_branches(): | |
| while True: | |
| try: | |
| repo_owner, repo_base_name = GITHUB_REPO.split('/') | |
| headers = {"Authorization": f"token {GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json"} | |
| async with aiohttp.ClientSession() as session: | |
| for i in range(20): | |
| repo_name = repo_base_name if i == 0 else f"{repo_base_name}-{i}" | |
| api_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/git/refs/heads" | |
| async with session.get(api_url, headers=headers) as resp: | |
| if resp.status == 200: | |
| refs = await resp.json() | |
| current_time = int(time.time()) | |
| for ref in refs: | |
| ref_name = ref.get("ref", "") | |
| if "refs/heads/DL-" in ref_name: | |
| branch_name = ref_name.split("/")[-1] | |
| parts = branch_name.split("-") | |
| if len(parts) >= 2 and parts[1].isdigit(): | |
| if current_time - int(parts[1]) > 7200: | |
| del_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/git/refs/heads/{branch_name}" | |
| await session.delete(del_url, headers=headers) | |
| elif resp.status == 404: | |
| break | |
| except: pass | |
| await asyncio.sleep(1800) | |
| async def main_handler(client, update): | |
| global BOT_GUID | |
| try: | |
| if not BOT_GUID: | |
| me = await client.get_me() | |
| if me and hasattr(me, 'user'): BOT_GUID = getattr(me.user, 'user_guid', None) | |
| msg_obj = getattr(update, "message", None) or getattr(update, "new_message", None) | |
| author_id = getattr(update, 'author_guid', None) | |
| if not author_id and msg_obj: author_id = msg_obj.get('author_object_guid') if isinstance(msg_obj, dict) else getattr(msg_obj, 'author_object_guid', None) | |
| if BOT_GUID and author_id == BOT_GUID: return | |
| chat_id = getattr(update, 'object_guid', None) or getattr(update, 'author_guid', None) or getattr(update, "chat_id", None) | |
| if not chat_id: return | |
| msg_id = getattr(update, "message_id", None) | |
| user_text = getattr(update, "text", "") or getattr(msg_obj, "text", "") | |
| user_text_str = str(user_text).strip() | |
| if not user_text_str: return | |
| if user_text_str.lower() in ["/start", "سلام", "شروع"]: | |
| start_text = ( | |
| "👋 **سلام! به ربات تبدیل لینک پرسرعت خوش آمدید.** 🚀\n\n" | |
| "❓ **این ربات چه کار میکند؟**\n" | |
| "دانلود مستقیم فایلهای تلگرام یا سایتهای خارجی معمولاً کند، سخت یا نیازمند فیلترشکن است. این ربات هر فایلی را برای شما به یک **لینک مستقیم (با اینترنت ملی)** تبدیل میکند!\n\n" | |
| "📥 **راهنمای استفاده برای تلگرام:**\n" | |
| "۱. ابتدا یک **کانال عمومی (Public)** در تلگرام بسازید.\n" | |
| "۲. فایل خود را درون آن کانال آپلود یا فوروارد کنید.\n" | |
| "۳. روی فایل کلیک راست کرده (یا نگه دارید) و گزینه **Copy Post Link** (کپی لینک پست) را بزنید.\n" | |
| "۴. آن لینک (مثلاً `t.me/mychannel/12`) را در اینجا برای من بفرستید.\n\n" | |
| "🔗 **راهنمای استفاده برای سایتها:**\n" | |
| "اگر از سایت دیگری لینک دانلود دارید، فقط کافیست آن لینک را اینجا ارسال کنید.\n\n" | |
| "🎯 پس از ارسال لینک، من فایل را پردازش کرده و یک فایل فشرده (ZIP) آمادهی دانلود به شما تحویل میدهم.\n\n" | |
| "👇 **همین الان لینک خود را بفرستید...**" | |
| ) | |
| await client.send_message(chat_id, start_text) | |
| return | |
| if user_text_str.lower().startswith("http"): | |
| asyncio.create_task(process_and_commit_to_cloud(client, chat_id, msg_id, user_text_str)) | |
| except Exception: traceback.print_exc() | |
| if __name__ == "__main__": | |
| threading.Thread(target=run_flask, daemon=True).start() | |
| threading.Thread(target=lambda: asyncio.run(cleanup_expired_branches()), daemon=True).start() | |
| print("🚀 آماده به کار (حل مشکل فیلترینگ با ارائه لینک فشرده یکپارچه)...") | |
| bot.run() | |