Opera8 commited on
Commit
ff1cec7
·
verified ·
1 Parent(s): 3d5d60c

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +120 -81
main.py CHANGED
@@ -15,13 +15,13 @@ 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,11 +32,12 @@ TG_BOT_TOKEN = os.environ.get("TG_BOT_TOKEN", "توکن_تلگرام").strip()
32
 
33
  GITHUB_REPO = "hajiliker6-source/internet-melli"
34
 
 
35
  TG_API_ID = 6
36
  TG_API_HASH = "eb06d4abfb49dc3eeb1aeb98ae0f581e"
37
 
38
  if bot_token == "توکن_روبیکا" or GITHUB_TOKEN == "توکن_گیت‌هاب":
39
- print("❌ خطا: توکن‌های اصلی تنظیم نشدهاند!")
40
  exit()
41
 
42
  bot = BotClient(bot_token)
@@ -65,52 +66,34 @@ async def ensure_tg_started():
65
  is_tg_started = True
66
 
67
  # ==============================================================================
68
- # 🟢 توابع دانلود پیشرفته (آپدیت ضد-ربات)
69
  # ==============================================================================
70
 
 
71
  def sync_download_ytdlp(url, temp_dir):
 
72
  ydl_opts = {
73
  'outtmpl': f'{temp_dir}/{uuid.uuid4().hex[:6]}_%(title)s.%(ext)s',
74
  'quiet': True,
75
  'no_warnings': True,
76
- 'format': 'b',
77
- 'nocheckcertificate': True, # حل مشکل قطعی SSL
78
- 'source_address': '0.0.0.0', # اجبار به استفاده از IPv4 برای جلوگیری از بلاک شدن دیتاسنتر
79
- 'http_headers': {
80
- # شبیه‌سازی مرورگر سافاری در آیفون برای دور زدن دیوار امنیتی اینستاگرام
81
- 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1',
82
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
83
- 'Accept-Language': 'en-us,en;q=0.5',
84
- 'Sec-Fetch-Mode': 'navigate'
85
- },
86
- 'extractor_args': {
87
- 'youtube': {
88
- # استفاده از کلاینت‌های مختلف برای دور زدن ربات یوتیوب
89
- 'player_client': ['ios', 'android', 'web']
90
- }
91
- }
92
  }
93
-
94
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
95
  info = ydl.extract_info(url, download=True)
96
  file_path = ydl.prepare_filename(info)
97
  filename = os.path.basename(file_path)
 
98
  clean_filename = re.sub(r'[\\/*?:"<>|]', "", filename)
99
-
100
  if clean_filename != filename:
101
  clean_path = os.path.join(temp_dir, clean_filename)
102
  os.rename(file_path, clean_path)
103
  return clean_path, clean_filename
104
  return file_path, filename
105
 
106
- async def download_via_ytdlp(url, chat_id, message_id, client):
107
  status_msg_id = None
108
- source_name = "شبکه‌های اجتماعی"
109
- if "youtube" in url or "youtu.be" in url: source_name = "یوتیوب"
110
- elif "instagram" in url: source_name = "اینستاگرام"
111
-
112
  try:
113
- status_msg = await client.send_message(chat_id, f"⏳ در حال استخراج و دور زدن تحریم‌های {source_name}...\n(ممکن است کمی طول بکشد)", reply_to_message_id=message_id)
114
  status_msg_id = getattr(status_msg, 'message_id', None)
115
  if not status_msg_id and isinstance(status_msg, dict):
116
  status_msg_id = status_msg.get('message_update', {}).get('message_id') or status_msg.get('message_id')
@@ -120,10 +103,11 @@ async def download_via_ytdlp(url, chat_id, message_id, client):
120
  temp_dir = "/app/downloads"
121
  os.makedirs(temp_dir, exist_ok=True)
122
 
 
123
  file_path, filename = await asyncio.to_thread(sync_download_ytdlp, url, temp_dir)
124
  return file_path, filename, status_msg_id
125
  except Exception as e:
126
- error_msg = f"❌ متأسفانه سرور توسط {source_name} مسدود شده است:\n{str(e)[:150]}"
127
  if status_msg_id:
128
  try: await client.edit_message_text(chat_id, status_msg_id, error_msg)
129
  except: pass
@@ -140,76 +124,89 @@ async def download_from_telegram(url, chat_id, message_id, client):
140
  except: pass
141
 
142
  try:
143
- if not tg_client: raise Exception("توکن تلگرام تنظیم نشده است.")
 
 
144
  await ensure_tg_started()
145
 
146
  match = re.search(r"t\.me/([^/]+)/(\d+)", url)
147
- if not match: raise Exception("لینک تلگرام نامعتبر است.")
 
148
 
149
- channel_username, msg_id = match.group(1), int(match.group(2))
 
150
 
151
  if status_msg_id:
152
- try: await client.edit_message_text(chat_id, status_msg_id, "⏳ در حال دریافت اطلاعات فایل از تلگرام...")
153
  except: pass
154
 
155
  msg = await tg_client.get_messages(channel_username, msg_id)
156
- if not msg or not msg.media: raise Exception("فایلی یافت نشد.")
 
157
 
158
  filename = None
159
  if getattr(msg, 'document', None): filename = msg.document.file_name
160
  elif getattr(msg, 'video', None): filename = msg.video.file_name
161
  elif getattr(msg, 'audio', None): filename = msg.audio.file_name
162
- elif getattr(msg, 'photo', None): filename = f"photo_{uuid.uuid4().hex[:6]}.jpg"
163
 
164
- if not filename: filename = f"tg_file_{uuid.uuid4().hex[:6]}.dat"
165
 
166
  temp_dir = "/app/downloads"
167
  os.makedirs(temp_dir, exist_ok=True)
168
  file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}")
169
 
170
  if status_msg_id:
171
- try: await client.edit_message_text(chat_id, status_msg_id, "📥 در حال انتقال فایل از تلگرام به سرور...")
172
  except: pass
173
 
174
  await tg_client.download_media(msg, file_name=file_path)
175
  return file_path, filename, status_msg_id
 
176
  except Exception as e:
 
177
  if status_msg_id:
178
- try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای تلگرام: {str(e)[:100]}")
179
  except: pass
180
  return None, None, status_msg_id
181
 
182
  # 3. تابع دانلود وب (لینک مستقیم)
183
  async def download_large_file(url, chat_id, message_id, client):
184
  if "dropbox.com" in url:
185
- url = url.replace("dl=0", "dl=1") if "dl=0" in url else (url + ("&dl=1" if "?" in url else "?dl=1"))
 
186
 
187
  temp_dir = "/app/downloads"
188
  os.makedirs(temp_dir, exist_ok=True)
 
189
  parsed_url = urllib.parse.urlparse(url)
190
  filename = os.path.basename(parsed_url.path)
191
  if not filename or '.' not in filename: filename = f"file_{uuid.uuid4().hex[:8]}.dat"
 
192
  file_path = os.path.join(temp_dir, f"{uuid.uuid4().hex[:6]}_{filename}")
193
-
194
  status_msg_id = None
 
195
  try:
196
- status_msg = await client.send_message(chat_id, "⏳ در حال دانلود لینک مستقیم در سرور...", reply_to_message_id=message_id)
197
  status_msg_id = getattr(status_msg, 'message_id', None)
198
- except: pass
 
 
199
 
200
  try:
201
- headers = {"User-Agent": "Mozilla/5.0"}
202
  async with aiohttp.ClientSession(headers=headers) as session:
203
- async with session.get(url, timeout=0) as resp:
204
- if resp.status != 200: return None, None, status_msg_id
 
205
  with open(file_path, 'wb') as f:
206
- async for chunk in resp.content.iter_chunked(2 * 1024 * 1024):
207
  if chunk: f.write(chunk)
208
  return file_path, filename, status_msg_id
209
- except: return None, None, status_msg_id
210
 
211
  # ==============================================================================
212
- # 🟢 توابع گیت‌هاب و پردازش نهایی
213
  # ==============================================================================
214
  def split_file_for_winrar(file_path, dest_dir, base_filename):
215
  chunk_size = 95 * 1024 * 1024
@@ -219,98 +216,127 @@ def split_file_for_winrar(file_path, dest_dir, base_filename):
219
  while True:
220
  chunk = f.read(chunk_size)
221
  if not chunk: break
222
- part_path = os.path.join(dest_dir, f"{base_filename}.{part_num:03d}")
223
- with open(part_path, 'wb') as p: p.write(chunk)
 
 
224
  part_num += 1
225
 
 
 
 
226
  async def process_and_commit_to_github(client, chat_id, message_id, url):
227
- url_l = url.lower()
228
 
229
- if any(x in url_l for x in ["youtube.com", "youtu.be", "instagram.com", "twitter.com", "x.com", "tiktok.com"]):
230
- file_path, filename, status_msg_id = await download_via_ytdlp(url, chat_id, message_id, client)
231
- elif "t.me/" in url_l:
 
 
 
232
  file_path, filename, status_msg_id = await download_from_telegram(url, chat_id, message_id, client)
233
  else:
234
  file_path, filename, status_msg_id = await download_large_file(url, chat_id, message_id, client)
235
 
236
  if not file_path or not os.path.exists(file_path):
237
  if status_msg_id:
238
- try: await client.edit_message_text(chat_id, status_msg_id, "❌ پردازش لینک با خطا مواجه شد.")
239
  except: pass
240
  return
241
 
242
  try:
243
  if status_msg_id:
244
- try: await client.edit_message_text(chat_id, status_msg_id, "✅ فایل با موفقیت دریافت شد.\n✂️ در حال پارت‌بندی و انتقال به گیت‌هاب...")
245
  except: pass
246
 
247
  async with git_lock:
248
  current_timestamp = int(time.time())
249
- branch_name = f"DL-{current_timestamp}-{uuid.uuid4().hex[:4]}"
250
  repo_url = f"https://oauth2:{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
251
  work_dir = "/app/git_workspace"
252
 
253
  if os.path.exists(work_dir): shutil.rmtree(work_dir)
254
- subprocess.run(["git", "clone", repo_url, work_dir], check=True, capture_output=True)
255
- subprocess.run(["git", "config", "user.email", "bot@alpha.io"], cwd=work_dir)
 
256
  subprocess.run(["git", "config", "user.name", "AI Alpha Bot"], cwd=work_dir)
257
  subprocess.run(["git", "checkout", "--orphan", branch_name], cwd=work_dir, check=True)
258
- subprocess.run(["git", "rm", "-rf", "."], cwd=work_dir, capture_output=True)
259
 
260
  file_folder = os.path.join(work_dir, filename)
261
  split_file_for_winrar(file_path, file_folder, filename)
262
 
263
  subprocess.run(["git", "add", "."], cwd=work_dir, check=True)
264
- subprocess.run(["git", "commit", "-m", f"Upload: {filename}"], cwd=work_dir, check=True)
265
  subprocess.run(["git", "push", "origin", branch_name], cwd=work_dir, check=True)
266
 
267
- zip_link = f"https://github.com/{GITHUB_REPO}/archive/refs/heads/{branch_name}.zip"
268
 
269
  success_text = (
270
- f"🎉 فایل شما آماده دانلود است!\n\n"
271
- f"📁 **نام:** {filename}\n"
272
- f"🔗 **لینک دانلود مستقیم (اینترنت ملی):**\n{zip_link}\n\n"
273
- f" **مهلت دانلود:** این لینک دقیقاً ۲ ساعت دیگر برای همیشه حذف می‌شود."
 
 
274
  )
 
275
  if status_msg_id:
276
  try: await client.edit_message_text(chat_id, status_msg_id, success_text)
277
  except: await client.send_message(chat_id, success_text)
278
- else: await client.send_message(chat_id, success_text)
 
279
 
280
  except Exception as e:
 
281
  if status_msg_id:
282
- try: await client.edit_message_text(chat_id, status_msg_id, f"❌ خطای گیت‌هاب:\n{str(e)[:150]}")
283
- except: pass
284
  finally:
285
- if file_path and os.path.exists(file_path): os.remove(file_path)
286
- if os.path.exists("/app/git_workspace"): shutil.rmtree("/app/git_workspace")
 
 
 
287
 
288
  # ==============================================================================
289
- # 🟢 پاکسازی و اجرا
290
  # ==============================================================================
291
  async def cleanup_expired_branches():
292
  while True:
293
  try:
294
  api_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads"
295
  headers = {"Authorization": f"token {GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json"}
 
296
  async with aiohttp.ClientSession() as session:
297
  async with session.get(api_url, headers=headers) as resp:
298
  if resp.status == 200:
299
  refs = await resp.json()
300
  current_time = int(time.time())
 
301
  for ref in refs:
302
  ref_name = ref.get("ref", "")
303
  if "refs/heads/DL-" in ref_name:
304
  branch_name = ref_name.split("/")[-1]
305
  parts = branch_name.split("-")
306
- if len(parts) >= 2 and parts[1].isdigit():
307
- if current_time - int(parts[1]) > 7200:
308
- del_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads/{branch_name}"
309
- await session.delete(del_url, headers=headers)
310
- print(f"🗑 Deleted expired branch: {branch_name}")
311
- except: pass
 
 
 
312
  await asyncio.sleep(1800)
313
 
 
 
 
 
 
 
 
 
314
  @bot.on_update(filters.private)
315
  async def main_handler(client, update):
316
  global BOT_GUID
@@ -333,7 +359,16 @@ async def main_handler(client, update):
333
  if not user_text_str: return
334
 
335
  if user_text_str.lower() in ["/start", "سلام"]:
336
- await client.send_message(chat_id, "👋 سلام! لینک مورد نظرت رو بفرست:\n\n🎥 **یوتیوب / اینستاگرام / تیک‌تاک**\n✈️ **تلگرام (کانال عمومی)**\n🌐 **لینک مستقیم وب**\n\nفایل‌ها پارت‌بندی شده و روی گیت‌هاب (اینترنت ملی) آپلود میشن و ۲ ساعت بعد خودکار حذف میشن.")
 
 
 
 
 
 
 
 
 
337
  return
338
 
339
  if user_text_str.lower().startswith("http"):
@@ -342,7 +377,11 @@ async def main_handler(client, update):
342
  except Exception: traceback.print_exc()
343
 
344
  if __name__ == "__main__":
 
 
 
345
  threading.Thread(target=run_flask, daemon=True).start()
346
- threading.Thread(target=lambda: asyncio.run(cleanup_expired_branches()), daemon=True).start()
347
- print("🚀 ربات با پشتیبانی کامل از یوتیوب و اینستاگرام روشن شد...")
 
348
  bot.run()
 
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
 
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)
 
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')
 
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
 
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
  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
  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
  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()