Opera8 commited on
Commit
ec5a198
·
verified ·
1 Parent(s): 4fa6ca4

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +64 -53
main.py CHANGED
@@ -7,6 +7,7 @@ import urllib.parse
7
  import traceback
8
  import subprocess
9
  import shutil
 
10
  from flask import Flask
11
  from rubpy.bot import BotClient, filters
12
 
@@ -33,7 +34,6 @@ if not bot_token or not GITHUB_TOKEN:
33
  bot = BotClient(bot_token)
34
  BOT_GUID = None
35
 
36
- # قفل برای جلوگیری از تداخل کامیت‌های همزمان گیت
37
  git_lock = asyncio.Lock()
38
 
39
  # ==============================================================================
@@ -77,7 +77,7 @@ async def download_large_file(url, chat_id, message_id, client):
77
  # 🟢 تابع خرد کردن فایل برای WinRAR
78
  # ==============================================================================
79
  def split_file_for_winrar(file_path, dest_dir, base_filename):
80
- chunk_size = 95 * 1024 * 1024 # محدودیت 95 مگابایتی برای گیت‌هاب
81
  part_num = 1
82
 
83
  os.makedirs(dest_dir, exist_ok=True)
@@ -96,7 +96,7 @@ def split_file_for_winrar(file_path, dest_dir, base_filename):
96
  part_num += 1
97
 
98
  # ==============================================================================
99
- # 🟢 پردازش و کامیت در شاخه مجزا (Orphan Branch) گیت‌هاب
100
  # ==============================================================================
101
  async def process_and_commit_to_github(client, chat_id, message_id, url):
102
  file_path, filename, status_msg_id = await download_large_file(url, chat_id, message_id, client)
@@ -113,8 +113,9 @@ async def process_and_commit_to_github(client, chat_id, message_id, url):
113
  except: pass
114
 
115
  async with git_lock:
116
- # استفاده از نام شاخه مجزا برای هر فایل
117
- branch_name = f"DL-{uuid.uuid4().hex[:6]}"
 
118
  repo_url = f"https://oauth2:{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
119
  work_dir = "/app/git_workspace"
120
 
@@ -126,28 +127,27 @@ async def process_and_commit_to_github(client, chat_id, message_id, url):
126
  subprocess.run(["git", "config", "user.email", "bot@aialpha.local"], cwd=work_dir)
127
  subprocess.run(["git", "config", "user.name", "AI Alpha Bot"], cwd=work_dir)
128
 
129
- # ایجاد یک شاخه کاملاً خالی (بدون تاریخچه و فایل‌های قبلی)
130
  subprocess.run(["git", "checkout", "--orphan", branch_name], cwd=work_dir, check=True)
131
  subprocess.run(["git", "rm", "-rf", "."], cwd=work_dir, stderr=subprocess.DEVNULL)
132
 
133
- # خرد کردن فایل و قرار دادن در پوشه‌ای همنام فایل
134
  file_folder = os.path.join(work_dir, filename)
135
  split_file_for_winrar(file_path, file_folder, filename)
136
 
137
- # کامیت و پوش کردن شاخه جدید به سرور
138
  subprocess.run(["git", "add", "."], cwd=work_dir, check=True)
139
  subprocess.run(["git", "commit", "-m", f"Add parts for {filename}"], cwd=work_dir, check=True)
140
  subprocess.run(["git", "push", "origin", branch_name], cwd=work_dir, check=True)
141
 
142
- # لینک آرشیو مخصوص این شاخه (فقط حاوی همین فایل)
143
  zip_download_link = f"https://github.com/{GITHUB_REPO}/archive/refs/heads/{branch_name}.zip"
144
 
 
145
  success_text = (
146
- f"🎉 فایل با موفقیت ذخیره شد!\n\n"
147
- f"📁 نام: {filename}\n"
148
- f"🔗 لینک دانلود مستقیم (بدون فایلهای اضافه):\n{zip_download_link}\n\n"
149
- f"💡 راهنما: فایل Zip بالا را دانلود و Extract کنید تا به پارت‌های اصلی برسید.\n\n"
150
- f"🗑 **برای حذف این فایل از سرور و آزادسازی فضا، کافیست لینک بالا را مجدداً برای من ارسال کنید.**"
 
 
151
  )
152
 
153
  if status_msg_id:
@@ -168,41 +168,53 @@ async def process_and_commit_to_github(client, chat_id, message_id, url):
168
  try: shutil.rmtree("/app/git_workspace")
169
  except: pass
170
 
 
171
  # ==============================================================================
172
- # 🟢 تابع حذف فایل از گیت‌هاب از طریق API
173
  # ==============================================================================
174
- async def delete_github_branch(client, chat_id, message_id, url):
175
- try:
176
- # استخراج نام شاخه از لینک ربات
177
- branch_name = url.split("/archive/refs/heads/")[1].replace(".zip", "").strip()
178
-
179
- status_msg = await client.send_message(chat_id, "🗑 در حال پاکسازی فایل از سرور گیت‌هاب...", reply_to_message_id=message_id)
180
- status_msg_id = getattr(status_msg, 'message_id', None)
181
- if not status_msg_id and isinstance(status_msg, dict):
182
- status_msg_id = status_msg.get('message_update', {}).get('message_id') or status_msg.get('message_id')
183
 
184
- api_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads/{branch_name}"
185
- headers = {
186
- "Authorization": f"token {GITHUB_TOKEN}",
187
- "Accept": "application/vnd.github.v3+json"
188
- }
189
-
190
- # درخواست حذف شاخه (و فایل‌های داخلش)
191
- async with aiohttp.ClientSession() as session:
192
- async with session.delete(api_url, headers=headers) as resp:
193
- if resp.status == 204:
194
- result_text = "✅ فایل و تمامی پارت‌های آن با موفقیت از ریپازیتوری حذف شدند و فضای سرور آزاد شد!"
195
- elif resp.status == 422 or resp.status == 404:
196
- result_text = "❌ این فایل قبلاً حذف شده است یا وجود ندارد."
197
- else:
198
- result_text = f"❌ خطا در حذف فایل. کد وضعیت: {resp.status}"
199
-
200
- if status_msg_id:
201
- try: await client.edit_message_text(chat_id, status_msg_id, result_text)
202
- except: await client.send_message(chat_id, result_text)
 
 
 
 
 
203
 
204
- except Exception as e:
205
- await client.send_message(chat_id, f"❌ خطا در پردازش لینک حذف:\n{str(e)[:150]}")
 
 
 
 
 
 
206
 
207
  # ==============================================================================
208
  # 🟢 هندلر روبیکا
@@ -229,21 +241,20 @@ async def main_handler(client, update):
229
  if not user_text_str: return
230
 
231
  if user_text_str.lower() in ["/start", "سلام"]:
232
- await client.send_message(chat_id, "👋 سلام! لینک مستقیم هر فایلی رو بفرست تا برات خرد کنم و بفرستم روی گیت‌هاب (قابل دانلود با اینترنت ملی).\nبرای حذف فایل‌های قبلی، کافیه لینک گیتهابی که بهت دادم رو برام بفرستی.")
233
  return
234
 
235
- # اگر کاربر لینک گیت‌هابی که قبلا خود ربات ساخته را فرستاد (جهت حذف)
236
- if f"github.com/{GITHUB_REPO}/archive/refs/heads/DL-" in user_text_str:
237
- asyncio.create_task(delete_github_branch(client, chat_id, msg_id, user_text_str))
238
- return
239
-
240
- # اگر لینک دانلود معمولی بود
241
  if user_text_str.lower().startswith("http"):
242
  asyncio.create_task(process_and_commit_to_github(client, chat_id, msg_id, user_text_str))
243
 
244
  except Exception: traceback.print_exc()
245
 
246
  if __name__ == "__main__":
 
247
  threading.Thread(target=run_flask, daemon=True).start()
248
- print("🚀 ربات کلاستر گیت‌هاب روشن شد...")
 
 
 
 
249
  bot.run()
 
7
  import traceback
8
  import subprocess
9
  import shutil
10
+ import time
11
  from flask import Flask
12
  from rubpy.bot import BotClient, filters
13
 
 
34
  bot = BotClient(bot_token)
35
  BOT_GUID = None
36
 
 
37
  git_lock = asyncio.Lock()
38
 
39
  # ==============================================================================
 
77
  # 🟢 تابع خرد کردن فایل برای WinRAR
78
  # ==============================================================================
79
  def split_file_for_winrar(file_path, dest_dir, base_filename):
80
+ chunk_size = 95 * 1024 * 1024
81
  part_num = 1
82
 
83
  os.makedirs(dest_dir, exist_ok=True)
 
96
  part_num += 1
97
 
98
  # ==============================================================================
99
+ # 🟢 پردازش و کامیت در گیت‌هاب (با درج زمان در نام شاخه)
100
  # ==============================================================================
101
  async def process_and_commit_to_github(client, chat_id, message_id, url):
102
  file_path, filename, status_msg_id = await download_large_file(url, chat_id, message_id, client)
 
113
  except: pass
114
 
115
  async with git_lock:
116
+ # جاسازی Timestamp (زمان فعلی) در نام شاخه برای بررسی‌های آینده
117
+ current_timestamp = int(time.time())
118
+ branch_name = f"DL-{current_timestamp}-{uuid.uuid4().hex[:6]}"
119
  repo_url = f"https://oauth2:{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
120
  work_dir = "/app/git_workspace"
121
 
 
127
  subprocess.run(["git", "config", "user.email", "bot@aialpha.local"], cwd=work_dir)
128
  subprocess.run(["git", "config", "user.name", "AI Alpha Bot"], cwd=work_dir)
129
 
 
130
  subprocess.run(["git", "checkout", "--orphan", branch_name], cwd=work_dir, check=True)
131
  subprocess.run(["git", "rm", "-rf", "."], cwd=work_dir, stderr=subprocess.DEVNULL)
132
 
 
133
  file_folder = os.path.join(work_dir, filename)
134
  split_file_for_winrar(file_path, file_folder, filename)
135
 
 
136
  subprocess.run(["git", "add", "."], cwd=work_dir, check=True)
137
  subprocess.run(["git", "commit", "-m", f"Add parts for {filename}"], cwd=work_dir, check=True)
138
  subprocess.run(["git", "push", "origin", branch_name], cwd=work_dir, check=True)
139
 
 
140
  zip_download_link = f"https://github.com/{GITHUB_REPO}/archive/refs/heads/{branch_name}.zip"
141
 
142
+ # پیغام زیبای اطلاع‌رسانی به کاربر
143
  success_text = (
144
+ f"🎉 فایل شما با موفقیت آماده شد!\n\n"
145
+ f"📁 **نام فایل:** {filename}\n"
146
+ f"🔗 **لینک دانلود مستقیم (بدون مصرف ترافیک بین‌الملل):**\n{zip_download_link}\n\n"
147
+ f"💡 **راهنما:** فایل بالا را دانلود کرده و استخراج (Extract) کنید.\n\n"
148
+ f"⚠️ **توجه مهم:**\n"
149
+ f"جهت حفظ کیفیت خدمات و آزادسازی فضای سرور، این فایل **دقیقاً ۲ ساعت دیگر به صورت خودکار حذف خواهد شد.** ⏳\n"
150
+ f"لطفاً در این بازه زمانی نسبت به دانلود فایل خود اقدام نمایید."
151
  )
152
 
153
  if status_msg_id:
 
168
  try: shutil.rmtree("/app/git_workspace")
169
  except: pass
170
 
171
+
172
  # ==============================================================================
173
+ # 🟢 سیستم هوشمند حذف خودکار فایل‌های منقضی شده (بیش از ۲ ساعت)
174
  # ==============================================================================
175
+ async def cleanup_expired_branches():
176
+ """این تابع هر ۳۰ دقیقه ران می‌شود و شاخه‌های قدیمی‌تر از ۲ ساعت را مستقیم از گیت‌هاب پاک می‌کند."""
177
+ while True:
178
+ try:
179
+ api_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads"
180
+ headers = {
181
+ "Authorization": f"token {GITHUB_TOKEN}",
182
+ "Accept": "application/vnd.github.v3+json"
183
+ }
184
 
185
+ async with aiohttp.ClientSession() as session:
186
+ async with session.get(api_url, headers=headers) as resp:
187
+ if resp.status == 200:
188
+ refs = await resp.json()
189
+ current_time = int(time.time())
190
+
191
+ for ref in refs:
192
+ ref_name = ref.get("ref", "")
193
+ # بررسی اینکه آیا شاخه مربوط به فایل‌های دانلودی ماست
194
+ if "refs/heads/DL-" in ref_name:
195
+ branch_name = ref_name.split("/")[-1]
196
+ parts = branch_name.split("-")
197
+
198
+ # استخراج Timestamp از نام شاخه
199
+ if len(parts) >= 3 and parts[1].isdigit():
200
+ creation_time = int(parts[1])
201
+
202
+ # اگر بیش از ۷۲۰۰ ثانیه (۲ ساعت) گذشته بود، حذف شود
203
+ if current_time - creation_time > 7200:
204
+ delete_url = f"https://api.github.com/repos/{GITHUB_REPO}/git/refs/heads/{branch_name}"
205
+ await session.delete(delete_url, headers=headers)
206
+ print(f"🗑 Branch {branch_name} automatically deleted (Expired).")
207
+ except Exception as e:
208
+ print(f"❌ Error in Auto-Cleanup: {e}")
209
 
210
+ # صبر برای ۳۰ دقیقه تا اجرای دور بعدی پاکسازی
211
+ await asyncio.sleep(1800)
212
+
213
+ def run_cleanup_system():
214
+ """اجرای حلقه ایزوله برای تسک حذف خودکار در پس‌زمینه"""
215
+ loop = asyncio.new_event_loop()
216
+ asyncio.set_event_loop(loop)
217
+ loop.run_until_complete(cleanup_expired_branches())
218
 
219
  # ==============================================================================
220
  # 🟢 هندلر روبیکا
 
241
  if not user_text_str: return
242
 
243
  if user_text_str.lower() in ["/start", "سلام"]:
244
+ await client.send_message(chat_id, "👋 سلام! لینک مستقیم هر فایلی رو بفرست تا برات خرد کنم و بفرستم روی گیت‌هاب (قابل دانلود با اینترنت ملی).\n\n⏳ **فایل‌ها جهت مدیریت سرور، دو ساعت بعد از ساخته‌شدن به صورت کاملاً خودکار حذف میشن.**")
245
  return
246
 
 
 
 
 
 
 
247
  if user_text_str.lower().startswith("http"):
248
  asyncio.create_task(process_and_commit_to_github(client, chat_id, msg_id, user_text_str))
249
 
250
  except Exception: traceback.print_exc()
251
 
252
  if __name__ == "__main__":
253
+ # اجرای Flask در یک Thread مجزا
254
  threading.Thread(target=run_flask, daemon=True).start()
255
+
256
+ # اجرای سیستم پاکسازی خودکار در یک Thread مجزا
257
+ threading.Thread(target=run_cleanup_system, daemon=True).start()
258
+
259
+ print("🚀 ربات کلاستر گیت‌هاب همراه با سیستم پاکسازی خودکار روشن شد...")
260
  bot.run()