Reooiq commited on
Commit
4ab3da1
·
verified ·
1 Parent(s): 6d42634

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +64 -31
bot.py CHANGED
@@ -1,4 +1,5 @@
1
  import os
 
2
  import asyncio
3
  import sqlite3
4
  import time
@@ -10,12 +11,13 @@ from pyrogram.errors import FloodWait
10
  from pyrogram.enums import ChatType
11
  from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
12
 
13
- # --- 1. إعداد مساحات التخزين والتنظيف الأولية ---
14
  DATA_DIR = "./data"
15
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
16
  DB_PATH = os.path.join(DATA_DIR, 'bot_archiver.db')
17
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
18
 
 
19
  for f in os.listdir(DOWNLOAD_DIR):
20
  try: os.remove(os.path.join(DOWNLOAD_DIR, f))
21
  except: pass
@@ -23,6 +25,8 @@ for f in os.listdir(DOWNLOAD_DIR):
23
  conn = sqlite3.connect(DB_PATH, check_same_thread=False)
24
  cursor = conn.cursor()
25
 
 
 
26
  cursor.execute('''
27
  CREATE TABLE IF NOT EXISTS queue (
28
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -40,12 +44,15 @@ CREATE TABLE IF NOT EXISTS queue (
40
  cursor.execute('''CREATE TABLE IF NOT EXISTS scan_progress (chat_id INTEGER PRIMARY KEY, last_msg_id INTEGER)''')
41
  conn.commit()
42
 
43
- # --- 2. سيرفر الويب الوهمي ---
 
 
 
44
  class RequestHandler(BaseHTTPRequestHandler):
45
  def do_GET(self):
46
  self.send_response(200)
47
  self.end_headers()
48
- self.wfile.write(b"Industrial Grade Archiver Active!")
49
  def log_message(self, format, *args): pass
50
 
51
  Thread(target=lambda: HTTPServer(('0.0.0.0', 7860), RequestHandler).serve_forever(), daemon=True).start()
@@ -65,15 +72,14 @@ app = Client(
65
  max_concurrent_transmissions=2
66
  )
67
 
68
- # --- 4. فحص مساحة القرص ---
69
  def check_disk_space():
70
  total, used, free = shutil.disk_usage(DATA_DIR)
71
- return (free / (1024 * 1024)) > 500 # إرجاع True إذا كان المتبقي أكبر من 500 ميجابايت
72
 
73
- # --- 5. دالة التنزيل الآمن المتقدمة ---
74
  async def download_media_safe(message):
75
  while not check_disk_space():
76
- print("⚠️ المساحة المتبقية منخفضة! انتظار محرك الرفع لتنظيف القرص...")
77
  await asyncio.sleep(15)
78
 
79
  cursor.execute("SELECT status FROM queue WHERE chat_id=? AND msg_id=?", (message.chat.id, message.id))
@@ -84,7 +90,6 @@ async def download_media_safe(message):
84
 
85
  for attempt in range(3):
86
  try:
87
- # تنزيل مع مهلة 5 دقائق للملفات الكبيرة
88
  file_path = await asyncio.wait_for(message.download(file_name=unique_name), timeout=300)
89
 
90
  if file_path and os.path.exists(file_path) and os.path.getsize(file_path) > 0:
@@ -104,24 +109,44 @@ async def download_media_safe(message):
104
  (message.chat.id, message.id, group_id, m_type, caption, file_path, time.time())
105
  )
106
  conn.commit()
107
- print(f"⚡ [صائد فوري] تم تنزيل الوسيط: ID {message.id}")
108
  return file_path
109
  else:
110
  if file_path and os.path.exists(file_path): os.remove(file_path)
111
  except Exception:
112
- await asyncio.sleep(3)
113
 
114
  return None
115
 
116
- # --- 6. صائد الرسائل اللحظي ---
117
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
118
  async def catch_incoming(client, message):
119
  if message.chat.id != TARGET_CHAT:
120
  await download_media_safe(message)
121
 
122
- # --- 7. حاصد السجل التراكمي ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  async def scan_history_worker():
124
- print("🔎 بدء المسح الذكي لبيانات الأرشيف...")
125
  async for dialog in app.get_dialogs():
126
  if dialog.chat.type in [ChatType.CHANNEL, ChatType.SUPERGROUP, ChatType.GROUP] and dialog.chat.id != TARGET_CHAT:
127
  try:
@@ -140,22 +165,22 @@ async def scan_history_worker():
140
 
141
  except Exception:
142
  pass
143
- await asyncio.sleep(4)
144
- print("✅ اكتمل مسح جميع السجلات المتاحة.")
145
 
146
- # --- 8. النسخ الاحتياطي السحابي لقاعدة البيانات ---
147
  async def db_backup_worker():
148
  while True:
149
  await asyncio.sleep(43200) # كل 12 ساعة
150
  try:
151
  if os.path.exists(DB_PATH):
152
  await app.send_document(TARGET_CHAT, document=DB_PATH, caption="📦 نسخة احتياطية لسجل الأرشيف")
153
- print("💾 تم إرسال نسخة احتياطية من قاعدة البيانات إلى القناة.")
154
- except Exception as e:
155
- print(f"❌ خطأ بالنسخ الاحتياطي: {e}")
156
 
157
- # --- 9. محرك الرفع الشامل والألبومات ---
158
  async def upload_worker():
 
159
  while True:
160
  try:
161
  cursor.execute("SELECT id, chat_id, msg_id, media_group_id, media_type, caption, file_path, timestamp FROM queue WHERE status='DOWNLOADED' ORDER BY id ASC LIMIT 1")
@@ -172,7 +197,7 @@ async def upload_worker():
172
  conn.commit()
173
  continue
174
 
175
- # تجميع الألبومات وتقسيمها إذا زادت عن 10
176
  if group_id:
177
  time_passed = time.time() - ts
178
  if time_passed < 15:
@@ -185,7 +210,6 @@ async def upload_worker():
185
  group_rows = cursor.fetchall()
186
 
187
  if group_rows:
188
- # تقسيم الألبوم كل 10 عناصر
189
  for i in range(0, len(group_rows), 10):
190
  chunk = group_rows[i:i+10]
191
  media_list = []
@@ -205,7 +229,7 @@ async def upload_worker():
205
  files_to_delete.append(g_path)
206
 
207
  if media_list:
208
- print(f"📦 رفع ألبوم فرعي ({len(media_list)} عناصر)...")
209
  await app.send_media_group(TARGET_CHAT, media=media_list)
210
 
211
  for item_id in ids_to_update:
@@ -215,11 +239,12 @@ async def upload_worker():
215
  for f_path in files_to_delete:
216
  if os.path.exists(f_path): os.remove(f_path)
217
 
218
- await asyncio.sleep(10)
 
219
  continue
220
 
221
- # رفع الوسائط المنفردة حسب نوعها
222
- print(f"⬆️ رفع ملف منفرد (ID: {msg_id}) نوع: {m_type}...")
223
  if m_type == "photo": await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
224
  elif m_type == "video": await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
225
  elif m_type == "doc": await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
@@ -232,20 +257,28 @@ async def upload_worker():
232
  conn.commit()
233
 
234
  if os.path.exists(file_path): os.remove(file_path)
 
 
 
 
 
 
235
  print(f"✅ تم الرفع والتنظيف (ID: {msg_id})!")
236
- await asyncio.sleep(10)
237
 
238
  except FloodWait as e:
239
- print(f"🛑 [FloodWait] انتظار إجباري {e.value} ثانية...")
 
 
240
  await asyncio.sleep(e.value + 5)
241
  except Exception as e:
242
- print(f"❌ خطأ الرفع: {e}")
243
  await asyncio.sleep(8)
244
 
245
- # --- 10. نقطة التشغيل ---
246
  async def main():
247
  await app.start()
248
- print("🚀 تشغيل نظام الأرشيف الصناعي المتكامل (النسخة الفائقة)...")
249
 
250
  asyncio.create_task(upload_worker())
251
  asyncio.create_task(scan_history_worker())
 
1
  import os
2
+ import gc
3
  import asyncio
4
  import sqlite3
5
  import time
 
11
  from pyrogram.enums import ChatType
12
  from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
13
 
14
+ # --- 1. إعداد مساحات التخزين وتحسين SQLite للمزامنة السريعة ---
15
  DATA_DIR = "./data"
16
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
17
  DB_PATH = os.path.join(DATA_DIR, 'bot_archiver.db')
18
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
19
 
20
+ # تنظيف التخزين المؤقت السابق
21
  for f in os.listdir(DOWNLOAD_DIR):
22
  try: os.remove(os.path.join(DOWNLOAD_DIR, f))
23
  except: pass
 
25
  conn = sqlite3.connect(DB_PATH, check_same_thread=False)
26
  cursor = conn.cursor()
27
 
28
+ # تفعيل وضع WAL لمنع تضارب الكتابة والقراءة تكسيراً للأخطاء
29
+ cursor.execute("PRAGMA journal_mode=WAL;")
30
  cursor.execute('''
31
  CREATE TABLE IF NOT EXISTS queue (
32
  id INTEGER PRIMARY KEY AUTOINCREMENT,
 
44
  cursor.execute('''CREATE TABLE IF NOT EXISTS scan_progress (chat_id INTEGER PRIMARY KEY, last_msg_id INTEGER)''')
45
  conn.commit()
46
 
47
+ # متغيرة ديناميكية للتحكم بالفواصل الزمنية للحماية من الحظر
48
+ DYNAMIC_UPLOAD_DELAY = 10
49
+
50
+ # --- 2. سيرفر الويب الوهمي للحفاظ على التشغيل ---
51
  class RequestHandler(BaseHTTPRequestHandler):
52
  def do_GET(self):
53
  self.send_response(200)
54
  self.end_headers()
55
+ self.wfile.write(b"Nuclear Grade Telegram Archiver Active!")
56
  def log_message(self, format, *args): pass
57
 
58
  Thread(target=lambda: HTTPServer(('0.0.0.0', 7860), RequestHandler).serve_forever(), daemon=True).start()
 
72
  max_concurrent_transmissions=2
73
  )
74
 
75
+ # --- 4. فحص مساحة القرص والذاكرة ---
76
  def check_disk_space():
77
  total, used, free = shutil.disk_usage(DATA_DIR)
78
+ return (free / (1024 * 1024)) > 500 # 500MB حد أدنى للأمان
79
 
80
+ # --- 5. دالة التنزيل الفولاذية ---
81
  async def download_media_safe(message):
82
  while not check_disk_space():
 
83
  await asyncio.sleep(15)
84
 
85
  cursor.execute("SELECT status FROM queue WHERE chat_id=? AND msg_id=?", (message.chat.id, message.id))
 
90
 
91
  for attempt in range(3):
92
  try:
 
93
  file_path = await asyncio.wait_for(message.download(file_name=unique_name), timeout=300)
94
 
95
  if file_path and os.path.exists(file_path) and os.path.getsize(file_path) > 0:
 
109
  (message.chat.id, message.id, group_id, m_type, caption, file_path, time.time())
110
  )
111
  conn.commit()
112
+ print(f"⚡ [صائد فوري] تم التنزيل: ID {message.id}")
113
  return file_path
114
  else:
115
  if file_path and os.path.exists(file_path): os.remove(file_path)
116
  except Exception:
117
+ await asyncio.sleep(2)
118
 
119
  return None
120
 
121
+ # --- 6. صائد الرسائل الحية ---
122
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
123
  async def catch_incoming(client, message):
124
  if message.chat.id != TARGET_CHAT:
125
  await download_media_safe(message)
126
 
127
+ # --- 7. أوامر الأدمن والمراقبة الحية ---
128
+ @app.on_message(filters.me & filters.command("status"))
129
+ async def status_command(client, message):
130
+ cursor.execute("SELECT COUNT(*) FROM queue WHERE status='DOWNLOADED'")
131
+ pending = cursor.fetchone()[0]
132
+ cursor.execute("SELECT COUNT(*) FROM queue WHERE status='UPLOADED'")
133
+ uploaded = cursor.fetchone()[0]
134
+
135
+ total, used, free = shutil.disk_usage(DATA_DIR)
136
+ free_mb = round(free / (1024 * 1024), 2)
137
+
138
+ report = (
139
+ f"📊 **حالة البوت الحالية:**\n\n"
140
+ f"⏳ مقاطع في طابور الرفع: `{pending}`\n"
141
+ f"✅ مقاطع تم رفعها بنجاح: `{uploaded}`\n"
142
+ f"💾 المساحة المتبقية: `{free_mb} MB`\n"
143
+ f"⏱️ التأخير الديناميكي الحالي: `{DYNAMIC_UPLOAD_DELAY} ثانية`"
144
+ )
145
+ await message.reply_text(report)
146
+
147
+ # --- 8. حاصد السجل التراكمي ---
148
  async def scan_history_worker():
149
+ print("🔎 مسح السجلات القديمة...")
150
  async for dialog in app.get_dialogs():
151
  if dialog.chat.type in [ChatType.CHANNEL, ChatType.SUPERGROUP, ChatType.GROUP] and dialog.chat.id != TARGET_CHAT:
152
  try:
 
165
 
166
  except Exception:
167
  pass
168
+ await asyncio.sleep(3)
169
+ print("✅ اكتمل سحب كافة الأرشيفات القديمة.")
170
 
171
+ # --- 9. النسخ الاحتياطي التلقائي ---
172
  async def db_backup_worker():
173
  while True:
174
  await asyncio.sleep(43200) # كل 12 ساعة
175
  try:
176
  if os.path.exists(DB_PATH):
177
  await app.send_document(TARGET_CHAT, document=DB_PATH, caption="📦 نسخة احتياطية لسجل الأرشيف")
178
+ except Exception:
179
+ pass
 
180
 
181
+ # --- 10. محرك الرفع الذكي المقاوم للحظر وقاطع التسريبات ---
182
  async def upload_worker():
183
+ global DYNAMIC_UPLOAD_DELAY
184
  while True:
185
  try:
186
  cursor.execute("SELECT id, chat_id, msg_id, media_group_id, media_type, caption, file_path, timestamp FROM queue WHERE status='DOWNLOADED' ORDER BY id ASC LIMIT 1")
 
197
  conn.commit()
198
  continue
199
 
200
+ # معالجة وتقسيم الألبومات
201
  if group_id:
202
  time_passed = time.time() - ts
203
  if time_passed < 15:
 
210
  group_rows = cursor.fetchall()
211
 
212
  if group_rows:
 
213
  for i in range(0, len(group_rows), 10):
214
  chunk = group_rows[i:i+10]
215
  media_list = []
 
229
  files_to_delete.append(g_path)
230
 
231
  if media_list:
232
+ print(f"📦 رفع ألبوم ({len(media_list)} عناصر)...")
233
  await app.send_media_group(TARGET_CHAT, media=media_list)
234
 
235
  for item_id in ids_to_update:
 
239
  for f_path in files_to_delete:
240
  if os.path.exists(f_path): os.remove(f_path)
241
 
242
+ gc.collect() # تفريغ الذاكرة المؤقتة فوراً
243
+ await asyncio.sleep(DYNAMIC_UPLOAD_DELAY)
244
  continue
245
 
246
+ # رفع الوسائط المنفردة
247
+ print(f"⬆️ رفع (ID: {msg_id}) | نوع: {m_type}...")
248
  if m_type == "photo": await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
249
  elif m_type == "video": await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
250
  elif m_type == "doc": await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
 
257
  conn.commit()
258
 
259
  if os.path.exists(file_path): os.remove(file_path)
260
+
261
+ # تقليل التأخير تدريجياً إذا كان النظام مستقراً
262
+ if DYNAMIC_UPLOAD_DELAY > 8:
263
+ DYNAMIC_UPLOAD_DELAY -= 0.5
264
+
265
+ gc.collect() # تفريغ الذاكرة الرام
266
  print(f"✅ تم الرفع والتنظيف (ID: {msg_id})!")
267
+ await asyncio.sleep(DYNAMIC_UPLOAD_DELAY)
268
 
269
  except FloodWait as e:
270
+ # زيادة التأخير التلقائي عند مواجهة أي حظر زمني
271
+ DYNAMIC_UPLOAD_DELAY += 5
272
+ print(f"🛑 [FloodWait] انتظار {e.value} ثانية. رفع التأخير الديناميكي إلى {DYNAMIC_UPLOAD_DELAY} ثانية.")
273
  await asyncio.sleep(e.value + 5)
274
  except Exception as e:
275
+ print(f"❌ خطأ بالرفع: {e}")
276
  await asyncio.sleep(8)
277
 
278
+ # --- 11. نقطة التشغيل الرئيسية ---
279
  async def main():
280
  await app.start()
281
+ print("🚀 تم إطلاق النسخة النووية الكاملة بنجاح!")
282
 
283
  asyncio.create_task(upload_worker())
284
  asyncio.create_task(scan_history_worker())