Opera8 commited on
Commit
0889af5
·
verified ·
1 Parent(s): 9329b10

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +122 -150
main.py CHANGED
@@ -12,16 +12,15 @@ import re
12
  from flask import Flask
13
  from rubpy.bot import BotClient, filters
14
  from pyrogram import Client
15
- import yt_dlp
16
 
17
  # ==============================================================================
18
- # 🟢 تنظیمات اصلی ربات (توکن‌ها را اینجا وارد کنید)
19
  # ==============================================================================
20
  app = Flask(__name__)
21
 
22
  @app.route('/')
23
  def home():
24
- return "🚀 ربات انتقال به گیت‌هاب (پشتیبانی از وب، تلگرام و اینستاگرام) روشن است!"
25
 
26
  def run_flask():
27
  app.run(host="0.0.0.0", port=7860, threaded=True)
@@ -32,20 +31,15 @@ TG_BOT_TOKEN = os.environ.get("TG_BOT_TOKEN", "توکن_تلگرام").strip()
32
 
33
  GITHUB_REPO = "hajiliker6-source/internet-melli"
34
 
35
- # مقادیر عمومی API تلگرام
36
  TG_API_ID = 6
37
  TG_API_HASH = "eb06d4abfb49dc3eeb1aeb98ae0f581e"
38
 
39
- if bot_token == "توکن_روبیکا" or GITHUB_TOKEN == "توکن_گیت‌هاب":
40
- print("❌ توکن روبیکا یا گیت‌هاب تنظیم نشده است! لطفاً تنظیمات بالای کد را بررسی کنید.")
41
- exit()
42
-
43
  bot = BotClient(bot_token)
44
  BOT_GUID = None
45
  git_lock = asyncio.Lock()
46
 
47
  # ==============================================================================
48
- # 🟢 تنظیمات کلاینت تلگرام (Pyrogram)
49
  # ==============================================================================
50
  tg_client = None
51
  is_tg_started = False
@@ -66,54 +60,93 @@ async def ensure_tg_started():
66
  is_tg_started = True
67
 
68
  # ==============================================================================
69
- # 🟢 توابع دانلود (اینستاگرام، تلگرام و وب)
70
  # ==============================================================================
71
 
72
- # 1. تابع دانلود از اینستاگرام (و سایت‌های مشابه) با yt-dlp
73
- def sync_download_ytdlp(url, temp_dir):
74
- """این تابع همگام است و در یک ترد مجزا اجرا می‌شود"""
75
- ydl_opts = {
76
- 'outtmpl': f'{temp_dir}/{uuid.uuid4().hex[:6]}_%(title)s.%(ext)s',
77
- 'quiet': True,
78
- 'no_warnings': True,
79
- 'format': 'best'
 
 
 
 
 
 
 
80
  }
81
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
82
- info = ydl.extract_info(url, download=True)
83
- file_path = ydl.prepare_filename(info)
84
- filename = os.path.basename(file_path)
85
- # پاکسازی نام فایل از کاراکترهای عجیب برای گیت‌هاب
86
- clean_filename = re.sub(r'[\\/*?:"<>|]', "", filename)
87
- if clean_filename != filename:
88
- clean_path = os.path.join(temp_dir, clean_filename)
89
- os.rename(file_path, clean_path)
90
- return clean_path, clean_filename
91
- return file_path, filename
92
-
93
- async def download_from_instagram(url, chat_id, message_id, client):
 
 
 
 
 
94
  status_msg_id = None
 
 
 
 
95
  try:
96
- status_msg = await client.send_message(chat_id, "⏳ در حال استخراج و دانلود رسانه از اینستاگرام...", reply_to_message_id=message_id)
 
97
  status_msg_id = getattr(status_msg, 'message_id', None)
98
  if not status_msg_id and isinstance(status_msg, dict):
99
  status_msg_id = status_msg.get('message_update', {}).get('message_id') or status_msg.get('message_id')
100
  except: pass
101
 
102
  try:
 
 
 
 
 
 
 
 
 
 
103
  temp_dir = "/app/downloads"
104
  os.makedirs(temp_dir, exist_ok=True)
105
-
106
- # اجرای کتابخانه همگام در یک ترد مجزا برای جلوگیری از قفل شدن ربات
107
- file_path, filename = await asyncio.to_thread(sync_download_ytdlp, url, temp_dir)
 
 
 
 
 
 
 
 
 
108
  return file_path, filename, status_msg_id
 
109
  except Exception as e:
110
- error_msg = f"❌ خطا در دانلود از اینستاگرام (احتمالاً پیج پرایوت است یا پست حذف شده):\n{str(e)[:150]}"
111
  if status_msg_id:
112
  try: await client.edit_message_text(chat_id, status_msg_id, error_msg)
113
  except: pass
114
  return None, None, status_msg_id
115
 
116
- # 2. تابع دانلود از تلگرام
 
 
117
  async def download_from_telegram(url, chat_id, message_id, client):
118
  status_msg_id = None
119
  try:
@@ -124,89 +157,74 @@ async def download_from_telegram(url, chat_id, message_id, client):
124
  except: pass
125
 
126
  try:
127
- if not tg_client:
128
- raise Exception("ربات تلگرام متصل نیست. لطفاً توکن تلگرام را در سورس کد قرار دهید.")
129
-
130
  await ensure_tg_started()
131
 
132
  match = re.search(r"t\.me/([^/]+)/(\d+)", url)
133
- if not match:
134
- raise Exception("لینک تلگرام نامعتبر است.")
135
 
136
- channel_username = match.group(1)
137
- msg_id = int(match.group(2))
138
 
139
  if status_msg_id:
140
- try: await client.edit_message_text(chat_id, status_msg_id, "⏳ در حال دریافت اطلاعات فایل از کانال عمومی تلگرام...")
141
  except: pass
142
 
143
  msg = await tg_client.get_messages(channel_username, msg_id)
144
- if not msg or not msg.media:
145
- raise Exception("فایلی در این پیام یافت نشد یا پیام از کانال حذف شده است.")
146
 
147
  filename = None
148
  if getattr(msg, 'document', None): filename = msg.document.file_name
149
  elif getattr(msg, 'video', None): filename = msg.video.file_name
150
  elif getattr(msg, 'audio', None): filename = msg.audio.file_name
151
- elif getattr(msg, 'photo', None): filename = f"tg_photo_{uuid.uuid4().hex[:6]}.jpg" # پشتیبانی از عکس تلگرام
152
 
153
- if not filename: filename = f"tg_media_{uuid.uuid4().hex[:6]}.dat"
154
 
155
  temp_dir = "/app/downloads"
156
  os.makedirs(temp_dir, exist_ok=True)
157
  file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}")
158
 
159
- if status_msg_id:
160
- try: await client.edit_message_text(chat_id, status_msg_id, "📥 در حال دانلود فایل از تلگرام به سرور واسط...")
161
- except: pass
162
-
163
  await tg_client.download_media(msg, file_name=file_path)
164
  return file_path, filename, status_msg_id
165
-
166
  except Exception as e:
167
- error_msg = f"❌ خطای تلگرام:\n{str(e)[:150]}"
168
  if status_msg_id:
169
- try: await client.edit_message_text(chat_id, status_msg_id, error_msg)
170
  except: pass
171
  return None, None, status_msg_id
172
 
173
- # 3. تابع دانلود وب (لینک مستقیم)
 
 
174
  async def download_large_file(url, chat_id, message_id, client):
175
  if "dropbox.com" in url:
176
- if "dl=0" in url: url = url.replace("dl=0", "dl=1")
177
- elif "?dl=" not in url and "&dl=" not in url: url += "&dl=1" if "?" in url else "?dl=1"
178
 
179
  temp_dir = "/app/downloads"
180
  os.makedirs(temp_dir, exist_ok=True)
181
-
182
  parsed_url = urllib.parse.urlparse(url)
183
  filename = os.path.basename(parsed_url.path)
184
  if not filename or '.' not in filename: filename = f"file_{uuid.uuid4().hex[:8]}.dat"
185
-
186
  file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}")
187
- status_msg_id = None
188
 
 
189
  try:
190
- status_msg = await client.send_message(chat_id, "⏳ در حال دانلود فایل وب در سرور واسط...", reply_to_message_id=message_id)
191
  status_msg_id = getattr(status_msg, 'message_id', None)
192
- if not status_msg_id and isinstance(status_msg, dict):
193
- status_msg_id = status_msg.get('message_update', {}).get('message_id') or status_msg.get('message_id')
194
- except Exception: pass
195
 
196
  try:
197
- headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
198
  async with aiohttp.ClientSession(headers=headers) as session:
199
- async with session.get(url, timeout=0) as response:
200
- if response.status != 200:
201
- return None, None, status_msg_id
202
  with open(file_path, 'wb') as f:
203
- async for chunk in response.content.iter_chunked(2 * 1024 * 1024):
204
  if chunk: f.write(chunk)
205
  return file_path, filename, status_msg_id
206
- except Exception: return None, None, status_msg_id
207
 
208
  # ==============================================================================
209
- # 🟢 تابع خرد کردن فایل
210
  # ==============================================================================
211
  def split_file_for_winrar(file_path, dest_dir, base_filename):
212
  chunk_size = 95 * 1024 * 1024
@@ -216,127 +234,94 @@ def split_file_for_winrar(file_path, dest_dir, base_filename):
216
  while True:
217
  chunk = f.read(chunk_size)
218
  if not chunk: break
219
- part_name = f"{base_filename}.{part_num:03d}"
220
- part_path = os.path.join(dest_dir, part_name)
221
- with open(part_path, 'wb') as p:
222
- p.write(chunk)
223
  part_num += 1
224
 
225
- # ==============================================================================
226
- # 🟢 پردازش و آپلود در گیت‌هاب
227
- # ==============================================================================
228
  async def process_and_commit_to_github(client, chat_id, message_id, url):
 
229
 
230
- url_lower = url.lower()
231
-
232
- # سیستم تشخیص هوشمند لینک
233
- if "instagram.com/" in url_lower:
234
- file_path, filename, status_msg_id = await download_from_instagram(url, chat_id, message_id, client)
235
- elif "t.me/" in url_lower:
236
  file_path, filename, status_msg_id = await download_from_telegram(url, chat_id, message_id, client)
237
  else:
238
  file_path, filename, status_msg_id = await download_large_file(url, chat_id, message_id, client)
239
 
240
  if not file_path or not os.path.exists(file_path):
241
- if status_msg_id:
242
- try: await client.edit_message_text(chat_id, status_msg_id, "❌ پردازش فایل ناموفق بود. لطفاً لینک را بررسی کنید.")
243
- except: pass
244
  return
245
 
246
  try:
247
  if status_msg_id:
248
- try: await client.edit_message_text(chat_id, status_msg_id, "✅ رسانه با موفقیت دریافت شد.\n✂️ در حال پارت‌بندی و انتقال به گیت‌هاب...")
249
  except: pass
250
 
251
  async with git_lock:
252
  current_timestamp = int(time.time())
253
- branch_name = f"DL-{current_timestamp}-{uuid.uuid4().hex[:6]}"
254
  repo_url = f"https://oauth2:{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
255
  work_dir = "/app/git_workspace"
256
 
257
  if os.path.exists(work_dir): shutil.rmtree(work_dir)
258
-
259
- subprocess.run(["git", "clone", repo_url, work_dir], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
260
- subprocess.run(["git", "config", "user.email", "bot@aialpha.local"], cwd=work_dir)
261
  subprocess.run(["git", "config", "user.name", "AI Alpha Bot"], cwd=work_dir)
262
  subprocess.run(["git", "checkout", "--orphan", branch_name], cwd=work_dir, check=True)
263
- subprocess.run(["git", "rm", "-rf", "."], cwd=work_dir, stderr=subprocess.DEVNULL)
264
 
265
  file_folder = os.path.join(work_dir, filename)
266
  split_file_for_winrar(file_path, file_folder, filename)
267
 
268
  subprocess.run(["git", "add", "."], cwd=work_dir, check=True)
269
- subprocess.run(["git", "commit", "-m", f"Add parts for {filename}"], cwd=work_dir, check=True)
270
  subprocess.run(["git", "push", "origin", branch_name], cwd=work_dir, check=True)
271
 
272
- zip_download_link = f"https://github.com/{GITHUB_REPO}/archive/refs/heads/{branch_name}.zip"
273
 
274
  success_text = (
275
- f"🎉 فایل شما با موفقیت آماده شد!\n\n"
276
- f"📁 **نام فایل:** {filename}\n"
277
- f"🔗 **لینک دانلود مستقیم (بدون مصرف ترافیک بین‌الملل):**\n{zip_download_link}\n\n"
278
- f"💡 **راهنما:** فایل بالا را دانلود کرده و استخراج (Extract) کنید.\n\n"
279
- f"⚠️ **توجه مهم:**\n"
280
- f"جهت حفظ کیفیت خدمات و آزادسازی فضای سرور، این فایل **دقیقاً ۲ ساعت دیگر به صورت خودکار حذف خواهد شد.** ⏳"
281
  )
282
-
283
  if status_msg_id:
284
  try: await client.edit_message_text(chat_id, status_msg_id, success_text)
285
  except: await client.send_message(chat_id, success_text)
286
- else:
287
- await client.send_message(chat_id, success_text)
288
 
289
  except Exception as e:
290
- error_txt = f"❌ خطای گیت‌هاب:\n{str(e)[:150]}"
291
  if status_msg_id:
292
- try: await client.edit_message_text(chat_id, status_msg_id, error_txt)
293
- except: await client.send_message(chat_id, error_txt)
294
- finally:
295
- try: os.remove(file_path)
296
- except: pass
297
- if os.path.exists("/app/git_workspace"):
298
- try: shutil.rmtree("/app/git_workspace")
299
  except: pass
 
 
 
300
 
301
  # ==============================================================================
302
- # 🟢 سیستم هوشمند حذف خودکار فایل‌های منقضی شده
303
  # ==============================================================================
304
  async def cleanup_expired_branches():
305
  while True:
306
  try:
307
  api_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads"
308
  headers = {"Authorization": f"token {GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json"}
309
-
310
  async with aiohttp.ClientSession() as session:
311
  async with session.get(api_url, headers=headers) as resp:
312
  if resp.status == 200:
313
  refs = await resp.json()
314
  current_time = int(time.time())
315
-
316
  for ref in refs:
317
  ref_name = ref.get("ref", "")
318
  if "refs/heads/DL-" in ref_name:
319
  branch_name = ref_name.split("/")[-1]
320
  parts = branch_name.split("-")
321
-
322
- if len(parts) >= 3 and parts[1].isdigit():
323
- creation_time = int(parts[1])
324
- if current_time - creation_time > 7200:
325
- delete_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads/{branch_name}"
326
- await session.delete(delete_url, headers=headers)
327
- print(f"🗑 Branch {branch_name} automatically deleted (Expired).")
328
- except Exception as e:
329
- pass
330
  await asyncio.sleep(1800)
331
 
332
- def run_cleanup_system():
333
- loop = asyncio.new_event_loop()
334
- asyncio.set_event_loop(loop)
335
- loop.run_until_complete(cleanup_expired_branches())
336
-
337
- # ==============================================================================
338
- # 🟢 هندلر پیام‌های روبیکا
339
- # ==============================================================================
340
  @bot.on_update(filters.private)
341
  async def main_handler(client, update):
342
  global BOT_GUID
@@ -359,16 +344,7 @@ async def main_handler(client, update):
359
  if not user_text_str: return
360
 
361
  if user_text_str.lower() in ["/start", "سلام"]:
362
- welcome_msg = (
363
- "👋 سلام!\n\n"
364
- "من یک ربات انتقال‌دهنده هوشمند هستم. لینک‌های زیر را پشتیبانی می‌کنم:\n\n"
365
- "🌐 **لینک دانلود مستقیم** از سایت‌ها\n"
366
- "✈️ **لینک پست یا عکس کانال تلگرام** (مثال: `t.me/channel/123`)\n"
367
- "📸 **لینک ریلز یا پست اینستاگرام**\n\n"
368
- "لینک خود را بفرستید تا با نهایت سرعت آن را روی سرور گیت‌هاب (با اینترنت ملی) برایتان آماده کنم.\n\n"
369
- "⏳ **فایل‌ها جهت مدیریت سرور، دقیقاً دو ساعت بعد از ساخته‌شدن به صورت کاملاً خودکار پاک خواهند شد.**"
370
- )
371
- await client.send_message(chat_id, welcome_msg)
372
  return
373
 
374
  if user_text_str.lower().startswith("http"):
@@ -377,11 +353,7 @@ async def main_handler(client, update):
377
  except Exception: traceback.print_exc()
378
 
379
  if __name__ == "__main__":
380
- if not TG_BOT_TOKEN or TG_BOT_TOKEN == "توکن_تلگرام":
381
- print("⚠️ هشدار: توکن ربات تلگرام تنظیم نشده است! دانلود از تلگرام کار نخواهد کرد.")
382
-
383
  threading.Thread(target=run_flask, daemon=True).start()
384
- threading.Thread(target=run_cleanup_system, daemon=True).start()
385
-
386
- print("🚀 ربات کلاستر گیت‌هاب (پشتیبانی اینستاگرام، تلگرام و وب) روشن شد...")
387
  bot.run()
 
12
  from flask import Flask
13
  from rubpy.bot import BotClient, filters
14
  from pyrogram import Client
 
15
 
16
  # ==============================================================================
17
+ # 🟢 تنظیمات اصلی ربات
18
  # ==============================================================================
19
  app = Flask(__name__)
20
 
21
  @app.route('/')
22
  def home():
23
+ return "🚀 ربات هوشمند انتقال به گیت‌هاب (مجهز به API رایگان ضد-تحریم) فعال است!"
24
 
25
  def run_flask():
26
  app.run(host="0.0.0.0", port=7860, threaded=True)
 
31
 
32
  GITHUB_REPO = "hajiliker6-source/internet-melli"
33
 
 
34
  TG_API_ID = 6
35
  TG_API_HASH = "eb06d4abfb49dc3eeb1aeb98ae0f581e"
36
 
 
 
 
 
37
  bot = BotClient(bot_token)
38
  BOT_GUID = None
39
  git_lock = asyncio.Lock()
40
 
41
  # ==============================================================================
42
+ # 🟢 تنظیمات کلاینت تلگرام
43
  # ==============================================================================
44
  tg_client = None
45
  is_tg_started = False
 
60
  is_tg_started = True
61
 
62
  # ==============================================================================
63
+ # 🟢 توابع دانلود با API رایگان (بدون نیاز به کوکی و yt-dlp)
64
  # ==============================================================================
65
 
66
+ async def get_direct_link_from_free_api(url):
67
+ """استفاده از سرورهای واسط رایگان برای استخراج لینک مستقیم اینستاگرام و یوتیوب"""
68
+
69
+ # لیست سرورهای API رایگان (اگر یکی خراب بود می‌رود سراغ بعدی)
70
+ api_instances = [
71
+ "https://api.cobalt.tools/api/json",
72
+ "https://co.wuk.sh/api/json",
73
+ "https://api.cobalt.pw/api/json"
74
+ ]
75
+
76
+ headers = {
77
+ "Accept": "application/json",
78
+ "Content-Type": "application/json",
79
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
80
+ "Origin": "https://cobalt.tools"
81
  }
82
+
83
+ payload = {"url": url, "vQuality": "720"}
84
+
85
+ async with aiohttp.ClientSession() as session:
86
+ for api_url in api_instances:
87
+ try:
88
+ async with session.post(api_url, json=payload, headers=headers, timeout=15) as resp:
89
+ if resp.status in [200, 201]:
90
+ data = await resp.json()
91
+ if data.get("status") == "error":
92
+ continue
93
+ if "url" in data:
94
+ return data["url"] # لینک مستقیم استخراج شد
95
+ except:
96
+ continue
97
+ return None
98
+
99
+ async def download_via_free_api(url, chat_id, message_id, client):
100
  status_msg_id = None
101
+ source_name = "شبکه‌های اجتماعی"
102
+ if "youtube" in url or "youtu.be" in url: source_name = "یوتیوب"
103
+ elif "instagram" in url: source_name = "اینستاگرام"
104
+
105
  try:
106
+ msg_text = f"⏳ در حال دور زدن تحریم‌های {source_name} از طریق سرورهای واسط (API رایگان)..."
107
+ status_msg = await client.send_message(chat_id, msg_text, reply_to_message_id=message_id)
108
  status_msg_id = getattr(status_msg, 'message_id', None)
109
  if not status_msg_id and isinstance(status_msg, dict):
110
  status_msg_id = status_msg.get('message_update', {}).get('message_id') or status_msg.get('message_id')
111
  except: pass
112
 
113
  try:
114
+ # مرحله اول: گرفتن لینک مستقیم از API
115
+ direct_url = await get_direct_link_from_free_api(url)
116
+ if not direct_url:
117
+ raise Exception("سرورهای واسط قادر به استخراج این لینک نبودند (احتمالاً پیج پرایوت است یا پست حذف شده).")
118
+
119
+ if status_msg_id:
120
+ try: await client.edit_message_text(chat_id, status_msg_id, "📥 لینک مستقیم استخراج شد! در حال دانلود روی سرور...")
121
+ except: pass
122
+
123
+ # مرحله دوم: دانلود فایل با لینک مستقیمِ به دست آمده
124
  temp_dir = "/app/downloads"
125
  os.makedirs(temp_dir, exist_ok=True)
126
+ filename = f"{source_name}_video_{uuid.uuid4().hex[:6]}.mp4"
127
+ file_path = os.path.join(temp_dir, filename)
128
+
129
+ headers = {"User-Agent": "Mozilla/5.0"}
130
+ async with aiohttp.ClientSession(headers=headers) as session:
131
+ async with session.get(direct_url, timeout=0) as resp:
132
+ if resp.status != 200:
133
+ raise Exception("دانلود از لینک مستقیم با خطا مواجه شد.")
134
+ with open(file_path, 'wb') as f:
135
+ async for chunk in resp.content.iter_chunked(2 * 1024 * 1024):
136
+ if chunk: f.write(chunk)
137
+
138
  return file_path, filename, status_msg_id
139
+
140
  except Exception as e:
141
+ error_msg = f"❌ خطا در پردازش API واسط:\n{str(e)[:150]}"
142
  if status_msg_id:
143
  try: await client.edit_message_text(chat_id, status_msg_id, error_msg)
144
  except: pass
145
  return None, None, status_msg_id
146
 
147
+ # ==============================================================================
148
+ # 🟢 تابع دانلود از تلگرام
149
+ # ==============================================================================
150
  async def download_from_telegram(url, chat_id, message_id, client):
151
  status_msg_id = None
152
  try:
 
157
  except: pass
158
 
159
  try:
160
+ if not tg_client: raise Exception("توکن تلگرام تنظیم نشده است.")
 
 
161
  await ensure_tg_started()
162
 
163
  match = re.search(r"t\.me/([^/]+)/(\d+)", url)
164
+ if not match: raise Exception("لینک تلگرام نامعتبر است.")
 
165
 
166
+ channel_username, msg_id = match.group(1), int(match.group(2))
 
167
 
168
  if status_msg_id:
169
+ try: await client.edit_message_text(chat_id, status_msg_id, "⏳ در حال دریافت فایل از تلگرام...")
170
  except: pass
171
 
172
  msg = await tg_client.get_messages(channel_username, msg_id)
173
+ if not msg or not msg.media: raise Exception("فایلی یافت نشد.")
 
174
 
175
  filename = None
176
  if getattr(msg, 'document', None): filename = msg.document.file_name
177
  elif getattr(msg, 'video', None): filename = msg.video.file_name
178
  elif getattr(msg, 'audio', None): filename = msg.audio.file_name
179
+ elif getattr(msg, 'photo', None): filename = f"photo_{uuid.uuid4().hex[:6]}.jpg"
180
 
181
+ if not filename: filename = f"tg_file_{uuid.uuid4().hex[:6]}.dat"
182
 
183
  temp_dir = "/app/downloads"
184
  os.makedirs(temp_dir, exist_ok=True)
185
  file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}")
186
 
 
 
 
 
187
  await tg_client.download_media(msg, file_name=file_path)
188
  return file_path, filename, status_msg_id
 
189
  except Exception as e:
 
190
  if status_msg_id:
191
+ try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای تلگرام: {str(e)[:100]}")
192
  except: pass
193
  return None, None, status_msg_id
194
 
195
+ # ==============================================================================
196
+ # 🟢 تابع دانلود مستقیم (وب)
197
+ # ==============================================================================
198
  async def download_large_file(url, chat_id, message_id, client):
199
  if "dropbox.com" in url:
200
+ url = url.replace("dl=0", "dl=1") if "dl=0" in url else (url + ("&dl=1" if "?" in url else "?dl=1"))
 
201
 
202
  temp_dir = "/app/downloads"
203
  os.makedirs(temp_dir, exist_ok=True)
 
204
  parsed_url = urllib.parse.urlparse(url)
205
  filename = os.path.basename(parsed_url.path)
206
  if not filename or '.' not in filename: filename = f"file_{uuid.uuid4().hex[:8]}.dat"
 
207
  file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}")
 
208
 
209
+ status_msg_id = None
210
  try:
211
+ status_msg = await client.send_message(chat_id, "⏳ در حال دانلود در سرور...", reply_to_message_id=message_id)
212
  status_msg_id = getattr(status_msg, 'message_id', None)
213
+ except: pass
 
 
214
 
215
  try:
216
+ headers = {"User-Agent": "Mozilla/5.0"}
217
  async with aiohttp.ClientSession(headers=headers) as session:
218
+ async with session.get(url, timeout=0) as resp:
219
+ if resp.status != 200: return None, None, status_msg_id
 
220
  with open(file_path, 'wb') as f:
221
+ async for chunk in resp.content.iter_chunked(2 * 1024 * 1024):
222
  if chunk: f.write(chunk)
223
  return file_path, filename, status_msg_id
224
+ except: return None, None, status_msg_id
225
 
226
  # ==============================================================================
227
+ # 🟢 توابع گیت‌هاب و پردازش نهایی
228
  # ==============================================================================
229
  def split_file_for_winrar(file_path, dest_dir, base_filename):
230
  chunk_size = 95 * 1024 * 1024
 
234
  while True:
235
  chunk = f.read(chunk_size)
236
  if not chunk: break
237
+ part_path = os.path.join(dest_dir, f"{base_filename}.{part_num:03d}")
238
+ with open(part_path, 'wb') as p: p.write(chunk)
 
 
239
  part_num += 1
240
 
 
 
 
241
  async def process_and_commit_to_github(client, chat_id, message_id, url):
242
+ url_l = url.lower()
243
 
244
+ if any(x in url_l for x in ["youtube.com", "youtu.be", "instagram.com", "twitter.com", "x.com", "tiktok.com"]):
245
+ file_path, filename, status_msg_id = await download_via_free_api(url, chat_id, message_id, client)
246
+ elif "t.me/" in url_l:
 
 
 
247
  file_path, filename, status_msg_id = await download_from_telegram(url, chat_id, message_id, client)
248
  else:
249
  file_path, filename, status_msg_id = await download_large_file(url, chat_id, message_id, client)
250
 
251
  if not file_path or not os.path.exists(file_path):
 
 
 
252
  return
253
 
254
  try:
255
  if status_msg_id:
256
+ try: await client.edit_message_text(chat_id, status_msg_id, "✅ فایل با موفقیت دریافت شد.\n✂️ انتقال به گیت‌هاب...")
257
  except: pass
258
 
259
  async with git_lock:
260
  current_timestamp = int(time.time())
261
+ branch_name = f"DL-{current_timestamp}-{uuid.uuid4().hex[:4]}"
262
  repo_url = f"https://oauth2:{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
263
  work_dir = "/app/git_workspace"
264
 
265
  if os.path.exists(work_dir): shutil.rmtree(work_dir)
266
+ subprocess.run(["git", "clone", repo_url, work_dir], check=True, capture_output=True)
267
+ subprocess.run(["git", "config", "user.email", "bot@alpha.io"], cwd=work_dir)
 
268
  subprocess.run(["git", "config", "user.name", "AI Alpha Bot"], cwd=work_dir)
269
  subprocess.run(["git", "checkout", "--orphan", branch_name], cwd=work_dir, check=True)
270
+ subprocess.run(["git", "rm", "-rf", "."], cwd=work_dir, capture_output=True)
271
 
272
  file_folder = os.path.join(work_dir, filename)
273
  split_file_for_winrar(file_path, file_folder, filename)
274
 
275
  subprocess.run(["git", "add", "."], cwd=work_dir, check=True)
276
+ subprocess.run(["git", "commit", "-m", f"Upload: {filename}"], cwd=work_dir, check=True)
277
  subprocess.run(["git", "push", "origin", branch_name], cwd=work_dir, check=True)
278
 
279
+ zip_link = f"https://github.com/{GITHUB_REPO}/archive/refs/heads/{branch_name}.zip"
280
 
281
  success_text = (
282
+ f"🎉 فایل شما آماده دانلود است!\n\n"
283
+ f"📁 **نام:** {filename}\n"
284
+ f"🔗 **لینک دانلود مستقیم (اینترنت ملی):**\n{zip_link}\n\n"
285
+ f" **مهلت دانلود:** ۲ ساعت"
 
 
286
  )
 
287
  if status_msg_id:
288
  try: await client.edit_message_text(chat_id, status_msg_id, success_text)
289
  except: await client.send_message(chat_id, success_text)
290
+ else: await client.send_message(chat_id, success_text)
 
291
 
292
  except Exception as e:
 
293
  if status_msg_id:
294
+ try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای گیت‌هاب:\n{str(e)[:150]}")
 
 
 
 
 
 
295
  except: pass
296
+ finally:
297
+ if file_path and os.path.exists(file_path): os.remove(file_path)
298
+ if os.path.exists("/app/git_workspace"): shutil.rmtree("/app/git_workspace")
299
 
300
  # ==============================================================================
301
+ # 🟢 سیستم حذف خودکار
302
  # ==============================================================================
303
  async def cleanup_expired_branches():
304
  while True:
305
  try:
306
  api_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads"
307
  headers = {"Authorization": f"token {GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json"}
 
308
  async with aiohttp.ClientSession() as session:
309
  async with session.get(api_url, headers=headers) as resp:
310
  if resp.status == 200:
311
  refs = await resp.json()
312
  current_time = int(time.time())
 
313
  for ref in refs:
314
  ref_name = ref.get("ref", "")
315
  if "refs/heads/DL-" in ref_name:
316
  branch_name = ref_name.split("/")[-1]
317
  parts = branch_name.split("-")
318
+ if len(parts) >= 2 and parts[1].isdigit():
319
+ if current_time - int(parts[1]) > 7200:
320
+ del_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads/{branch_name}"
321
+ await session.delete(del_url, headers=headers)
322
+ except: pass
 
 
 
 
323
  await asyncio.sleep(1800)
324
 
 
 
 
 
 
 
 
 
325
  @bot.on_update(filters.private)
326
  async def main_handler(client, update):
327
  global BOT_GUID
 
344
  if not user_text_str: return
345
 
346
  if user_text_str.lower() in ["/start", "سلام"]:
347
+ await client.send_message(chat_id, "👋 سلام! لینک مورد نظرت رو بفرست:\n\n🎥 **یوتیوب / اینستاگرام / تیک‌تاک**\n✈️ **تلگرام (کانال عمومی)**\n🌐 **لینک مستقیم وب**")
 
 
 
 
 
 
 
 
 
348
  return
349
 
350
  if user_text_str.lower().startswith("http"):
 
353
  except Exception: traceback.print_exc()
354
 
355
  if __name__ == "__main__":
 
 
 
356
  threading.Thread(target=run_flask, daemon=True).start()
357
+ threading.Thread(target=lambda: asyncio.run(cleanup_expired_branches()), daemon=True).start()
358
+ print("🚀 آماده به کار با API ضد تحریم...")
 
359
  bot.run()