Reooiq commited on
Commit
9f77bc0
·
verified ·
1 Parent(s): 319bd25

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +114 -87
bot.py CHANGED
@@ -4,60 +4,31 @@ import asyncio
4
  import aiosqlite
5
  import time
6
  import shutil
7
- import urllib.request
8
  import random
9
- from threading import Thread
10
- from http.server import BaseHTTPRequestHandler, HTTPServer
11
  from pyrogram import Client, filters, idle
12
  from pyrogram.errors import FloodWait
13
  from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
14
  from pyrogram.enums import ChatAction
 
15
 
16
- # --- 1. الإعدادات الأساسية ---
17
  DATA_DIR = "./data"
18
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
19
  DB_PATH = os.path.join(DATA_DIR, 'bot_archiver.db')
20
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
21
 
22
- HEALTHCHECK_URL = os.environ.get("HEALTHCHECK_URL", "")
23
- MAX_FILE_SIZE = 2000 * 1024 * 1024 # 2GB
24
- BASE_UPLOAD_DELAY = 4 # زيادة الأمان الافتراضي للرفع
25
 
26
- download_queue = asyncio.Queue()
27
-
28
- # --- 2. سيرفر الحفاظ على التشغيل ---
29
- class RequestHandler(BaseHTTPRequestHandler):
30
- def do_GET(self):
31
- self.send_response(200)
32
- self.end_headers()
33
- self.wfile.write(b"Ultimate Radar Archiver Engine Active!")
34
- def log_message(self, format, *args): pass
35
-
36
- Thread(target=lambda: HTTPServer(('0.0.0.0', 7860), RequestHandler).serve_forever(), daemon=True).start()
37
-
38
- # --- 3. إعدادات الحساب (تم إصلاح المعاملات وتعديل البصمة) ---
39
  API_ID = int(os.environ.get("API_ID", 0))
40
  API_HASH = os.environ.get("API_HASH", "")
41
  SESSION_STRING = os.environ.get("SESSION_STRING", "")
42
  TARGET_CHAT = int(os.environ.get("TARGET_CHAT", 0))
43
 
44
- app = Client(
45
- "memory_session",
46
- api_id=API_ID,
47
- api_hash=API_HASH,
48
- session_string=SESSION_STRING,
49
- in_memory=True,
50
- device_model="Samsung Galaxy S23 Ultra",
51
- system_version="Android 14.0",
52
- app_version="10.14.1",
53
- lang_code="ar"
54
- )
55
-
56
- # --- 4. أدوات النظام وقاعدة البيانات ---
57
- def check_disk_space():
58
- total, used, free = shutil.disk_usage(DATA_DIR)
59
- return (free / (1024 * 1024)) > 500
60
 
 
61
  async def init_db():
62
  async with aiosqlite.connect(DB_PATH) as db:
63
  await db.execute("PRAGMA journal_mode=WAL;")
@@ -80,7 +51,8 @@ async def init_db():
80
 
81
  def get_media_details(message):
82
  media = message.photo or message.video or message.document or message.audio or message.voice or message.video_note or message.animation
83
- if not media: return None, None, 0
 
84
 
85
  m_type = "doc"
86
  if message.photo: m_type = "photo"
@@ -94,12 +66,12 @@ def get_media_details(message):
94
  file_size = getattr(media, "file_size", 0)
95
  return unique_id, m_type, file_size
96
 
97
- # --- 5. محرك التنزيل المتوازي ---
98
  async def download_worker_task(worker_id):
99
  while True:
100
  message = await download_queue.get()
101
  try:
102
- while not check_disk_space():
103
  await asyncio.sleep(15)
104
 
105
  unique_id, m_type, file_size = get_media_details(message)
@@ -128,10 +100,11 @@ async def download_worker_task(worker_id):
128
  (message.chat.id, message.id, unique_id, group_id, m_type, final_caption, file_path, file_size, time.time())
129
  )
130
  await db.commit()
131
- print(f"⚡ [Worker-{worker_id}] تم تنزيل رسالة بنجاح: {message.id}")
132
  break
133
  else:
134
- if file_path and os.path.exists(file_path): os.remove(file_path)
 
135
  except Exception:
136
  await asyncio.sleep(2)
137
  except Exception as e:
@@ -139,13 +112,24 @@ async def download_worker_task(worker_id):
139
  finally:
140
  download_queue.task_done()
141
 
142
- # --- 6. صائد الرسائل الحية ---
 
 
 
 
 
 
 
 
 
 
 
 
143
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
144
  async def catch_incoming(client, message):
145
  if message.chat.id != TARGET_CHAT:
146
  await download_queue.put(message)
147
 
148
- # --- 7. لوحة المراقبة ---
149
  @app.on_message(filters.me & filters.command("status"))
150
  async def status_command(client, message):
151
  async with aiosqlite.connect(DB_PATH) as db:
@@ -158,21 +142,23 @@ async def status_command(client, message):
158
  free_mb = round(free / (1024 * 1024), 2)
159
 
160
  report = (
161
- f"👑 **حالة رادار الأرشفة المحترف:**\n\n"
162
  f"📥 جاهز للرفع: `{pending}`\n"
163
- f"📤 تم رفعه بأمان: `{uploaded}`\n"
164
  f"🔄 قيد التنزيل: `{download_queue.qsize()}`\n"
165
- f"💾 المساحة المتاحة: `{free_mb} MB`"
166
  )
167
  await message.reply_text(report)
168
 
169
- # --- 8. محرك الرفع الذكي العالي الأمان ---
170
  async def upload_worker():
171
  global BASE_UPLOAD_DELAY
172
  while True:
173
  try:
174
  async with aiosqlite.connect(DB_PATH) as db:
175
- async with db.execute("SELECT id, chat_id, msg_id, media_group_id, media_type, caption, file_path, file_size, timestamp FROM queue WHERE status='DOWNLOADED' ORDER BY id ASC LIMIT 1") as cursor:
 
 
176
  row = await cursor.fetchone()
177
 
178
  if not row:
@@ -188,16 +174,22 @@ async def upload_worker():
188
  continue
189
 
190
  try:
191
- if m_type == "photo": await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_PHOTO)
192
- elif m_type in ["video", "animation"]: await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_VIDEO)
193
- elif m_type == "doc": await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_DOCUMENT)
194
- elif m_type in ["audio", "voice"]: await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_AUDIO)
 
 
 
 
195
  await asyncio.sleep(random.uniform(1.0, 2.0))
196
- except: pass
 
197
 
198
  if group_id:
199
  time_passed = time.time() - ts
200
- if time_passed < 10: await asyncio.sleep(10 - time_passed)
 
201
 
202
  async with aiosqlite.connect(DB_PATH) as db:
203
  async with db.execute(
@@ -215,10 +207,14 @@ async def upload_worker():
215
  g_id, g_type, g_cap, g_path = g_item
216
  item_caption = g_cap if idx == 0 else ""
217
 
218
- if g_type == "photo": media_list.append(InputMediaPhoto(media=g_path, caption=item_caption))
219
- elif g_type == "video": media_list.append(InputMediaVideo(media=g_path, caption=item_caption, supports_streaming=True))
220
- elif g_type == "doc": media_list.append(InputMediaDocument(media=g_path, caption=item_caption))
221
- elif g_type == "audio": media_list.append(InputMediaAudio(media=g_path, caption=item_caption))
 
 
 
 
222
 
223
  ids_to_update.append(g_id)
224
  files_to_delete.append(g_path)
@@ -231,25 +227,34 @@ async def upload_worker():
231
  await db.commit()
232
 
233
  for f_path in files_to_delete:
234
- if os.path.exists(f_path): os.remove(f_path)
 
235
 
236
  gc.collect()
237
  await asyncio.sleep(BASE_UPLOAD_DELAY + random.uniform(2.0, 4.0))
238
  continue
239
 
240
- if m_type == "photo": await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
241
- elif m_type == "video": await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
242
- elif m_type == "doc": await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
243
- elif m_type == "audio": await app.send_audio(TARGET_CHAT, audio=file_path, caption=caption)
244
- elif m_type == "voice": await app.send_voice(TARGET_CHAT, voice=file_path, caption=caption)
245
- elif m_type == "video_note": await app.send_video_note(TARGET_CHAT, video_note=file_path)
246
- elif m_type == "animation": await app.send_animation(TARGET_CHAT, animation=file_path, caption=caption)
 
 
 
 
 
 
 
247
 
248
  async with aiosqlite.connect(DB_PATH) as db:
249
  await db.execute("UPDATE queue SET status='UPLOADED' WHERE id=?", (q_id,))
250
  await db.commit()
251
 
252
- if os.path.exists(file_path): os.remove(file_path)
 
253
 
254
  size_factor = min(file_size / (10 * 1024 * 1024), 10)
255
  safe_sleep = BASE_UPLOAD_DELAY + size_factor + random.uniform(1.0, 3.0)
@@ -258,52 +263,74 @@ async def upload_worker():
258
  await asyncio.sleep(safe_sleep)
259
 
260
  except FloodWait as e:
261
- print(f"⚠️ تليجرام فرض حماية FloodWait لمدة {e.value} ثانية. جاري التهدئة...")
262
  BASE_UPLOAD_DELAY += 5
263
  await asyncio.sleep(e.value + random.uniform(10, 20))
264
  except Exception as e:
265
- print(f"⚠️ خطأ غير متوقع، تجاوز الملف: {e}")
266
  async with aiosqlite.connect(DB_PATH) as db:
267
  await db.execute("UPDATE queue SET status='FAILED' WHERE id=?", (q_id,))
268
  await db.commit()
269
- if os.path.exists(file_path): os.remove(file_path)
 
270
  await asyncio.sleep(5)
271
 
272
- async def healthcheck_ping():
273
- while True:
274
- await asyncio.sleep(300)
275
- if HEALTHCHECK_URL:
276
- try: urllib.request.urlopen(HEALTHCHECK_URL, timeout=10)
277
- except: pass
278
-
279
  async def main():
280
  await init_db()
281
  await app.start()
282
 
283
- print("🔄 جاري مزامنة بصمة الهاتف مع مراكز بيانات تليجرام...")
284
  try:
285
  me = await app.get_me()
286
- print(f"✅ تم الاتصال بنجاح بالحساب: {me.first_name} (معرف الجلسة مستقر)")
287
  async for _ in app.get_dialogs(limit=150):
288
  pass
289
  except Exception as e:
290
- print(f"⚠️ تحذير الاتصال: {e}")
291
 
292
- print("🚀 تم تشغيل الرادار الحي بنسخة الأمان القصوى والمحاكاة التامة!")
293
 
294
  for i in range(2):
295
  asyncio.create_task(download_worker_task(i + 1))
296
 
297
  asyncio.create_task(upload_worker())
298
- asyncio.create_task(healthcheck_ping())
299
 
300
  await idle()
301
  await app.stop()
302
 
303
- if __name__ == "__main__":
 
 
 
304
  while True:
305
  try:
306
- app.run(main())
307
- except Exception as crash_error:
308
- print(f"⚠️ إعادة تشغيل ذكية: {crash_error}")
309
- time.sleep(10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import aiosqlite
5
  import time
6
  import shutil
 
7
  import random
8
+ import threading
 
9
  from pyrogram import Client, filters, idle
10
  from pyrogram.errors import FloodWait
11
  from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
12
  from pyrogram.enums import ChatAction
13
+ import gradio as gr
14
 
15
+ # ============ الإعدادات ============
16
  DATA_DIR = "./data"
17
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
18
  DB_PATH = os.path.join(DATA_DIR, 'bot_archiver.db')
19
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
20
 
21
+ MAX_FILE_SIZE = 2000 * 1024 * 1024 # 2GB
22
+ BASE_UPLOAD_DELAY = 4
 
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  API_ID = int(os.environ.get("API_ID", 0))
25
  API_HASH = os.environ.get("API_HASH", "")
26
  SESSION_STRING = os.environ.get("SESSION_STRING", "")
27
  TARGET_CHAT = int(os.environ.get("TARGET_CHAT", 0))
28
 
29
+ download_queue = asyncio.Queue()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # ============ قاعدة البيانات ============
32
  async def init_db():
33
  async with aiosqlite.connect(DB_PATH) as db:
34
  await db.execute("PRAGMA journal_mode=WAL;")
 
51
 
52
  def get_media_details(message):
53
  media = message.photo or message.video or message.document or message.audio or message.voice or message.video_note or message.animation
54
+ if not media:
55
+ return None, None, 0
56
 
57
  m_type = "doc"
58
  if message.photo: m_type = "photo"
 
66
  file_size = getattr(media, "file_size", 0)
67
  return unique_id, m_type, file_size
68
 
69
+ # ============ محرك التنزيل ============
70
  async def download_worker_task(worker_id):
71
  while True:
72
  message = await download_queue.get()
73
  try:
74
+ while shutil.disk_usage(DATA_DIR).free / (1024 * 1024) <= 500:
75
  await asyncio.sleep(15)
76
 
77
  unique_id, m_type, file_size = get_media_details(message)
 
100
  (message.chat.id, message.id, unique_id, group_id, m_type, final_caption, file_path, file_size, time.time())
101
  )
102
  await db.commit()
103
+ print(f"⚡ [Worker-{worker_id}] تم تنزيل: {message.id}")
104
  break
105
  else:
106
+ if file_path and os.path.exists(file_path):
107
+ os.remove(file_path)
108
  except Exception:
109
  await asyncio.sleep(2)
110
  except Exception as e:
 
112
  finally:
113
  download_queue.task_done()
114
 
115
+ # ============ صائد الرسائل ============
116
+ app = Client(
117
+ "memory_session",
118
+ api_id=API_ID,
119
+ api_hash=API_HASH,
120
+ session_string=SESSION_STRING,
121
+ in_memory=True,
122
+ device_model="Samsung Galaxy S23 Ultra",
123
+ system_version="Android 14.0",
124
+ app_version="10.14.1",
125
+ lang_code="ar"
126
+ )
127
+
128
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
129
  async def catch_incoming(client, message):
130
  if message.chat.id != TARGET_CHAT:
131
  await download_queue.put(message)
132
 
 
133
  @app.on_message(filters.me & filters.command("status"))
134
  async def status_command(client, message):
135
  async with aiosqlite.connect(DB_PATH) as db:
 
142
  free_mb = round(free / (1024 * 1024), 2)
143
 
144
  report = (
145
+ f"👑 **حالة الأرشفة:**\n\n"
146
  f"📥 جاهز للرفع: `{pending}`\n"
147
+ f"📤 تم رفعه: `{uploaded}`\n"
148
  f"🔄 قيد التنزيل: `{download_queue.qsize()}`\n"
149
+ f"💾 مساحة متاحة: `{free_mb} MB`"
150
  )
151
  await message.reply_text(report)
152
 
153
+ # ============ محرك الرفع ============
154
  async def upload_worker():
155
  global BASE_UPLOAD_DELAY
156
  while True:
157
  try:
158
  async with aiosqlite.connect(DB_PATH) as db:
159
+ async with db.execute(
160
+ "SELECT id, chat_id, msg_id, media_group_id, media_type, caption, file_path, file_size, timestamp FROM queue WHERE status='DOWNLOADED' ORDER BY id ASC LIMIT 1"
161
+ ) as cursor:
162
  row = await cursor.fetchone()
163
 
164
  if not row:
 
174
  continue
175
 
176
  try:
177
+ if m_type == "photo":
178
+ await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_PHOTO)
179
+ elif m_type in ["video", "animation"]:
180
+ await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_VIDEO)
181
+ elif m_type == "doc":
182
+ await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_DOCUMENT)
183
+ elif m_type in ["audio", "voice"]:
184
+ await app.send_chat_action(TARGET_CHAT, ChatAction.UPLOAD_AUDIO)
185
  await asyncio.sleep(random.uniform(1.0, 2.0))
186
+ except:
187
+ pass
188
 
189
  if group_id:
190
  time_passed = time.time() - ts
191
+ if time_passed < 10:
192
+ await asyncio.sleep(10 - time_passed)
193
 
194
  async with aiosqlite.connect(DB_PATH) as db:
195
  async with db.execute(
 
207
  g_id, g_type, g_cap, g_path = g_item
208
  item_caption = g_cap if idx == 0 else ""
209
 
210
+ if g_type == "photo":
211
+ media_list.append(InputMediaPhoto(media=g_path, caption=item_caption))
212
+ elif g_type == "video":
213
+ media_list.append(InputMediaVideo(media=g_path, caption=item_caption, supports_streaming=True))
214
+ elif g_type == "doc":
215
+ media_list.append(InputMediaDocument(media=g_path, caption=item_caption))
216
+ elif g_type == "audio":
217
+ media_list.append(InputMediaAudio(media=g_path, caption=item_caption))
218
 
219
  ids_to_update.append(g_id)
220
  files_to_delete.append(g_path)
 
227
  await db.commit()
228
 
229
  for f_path in files_to_delete:
230
+ if os.path.exists(f_path):
231
+ os.remove(f_path)
232
 
233
  gc.collect()
234
  await asyncio.sleep(BASE_UPLOAD_DELAY + random.uniform(2.0, 4.0))
235
  continue
236
 
237
+ if m_type == "photo":
238
+ await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
239
+ elif m_type == "video":
240
+ await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
241
+ elif m_type == "doc":
242
+ await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
243
+ elif m_type == "audio":
244
+ await app.send_audio(TARGET_CHAT, audio=file_path, caption=caption)
245
+ elif m_type == "voice":
246
+ await app.send_voice(TARGET_CHAT, voice=file_path, caption=caption)
247
+ elif m_type == "video_note":
248
+ await app.send_video_note(TARGET_CHAT, video_note=file_path)
249
+ elif m_type == "animation":
250
+ await app.send_animation(TARGET_CHAT, animation=file_path, caption=caption)
251
 
252
  async with aiosqlite.connect(DB_PATH) as db:
253
  await db.execute("UPDATE queue SET status='UPLOADED' WHERE id=?", (q_id,))
254
  await db.commit()
255
 
256
+ if os.path.exists(file_path):
257
+ os.remove(file_path)
258
 
259
  size_factor = min(file_size / (10 * 1024 * 1024), 10)
260
  safe_sleep = BASE_UPLOAD_DELAY + size_factor + random.uniform(1.0, 3.0)
 
263
  await asyncio.sleep(safe_sleep)
264
 
265
  except FloodWait as e:
266
+ print(f"⚠️ FloodWait: {e.value} ثانية")
267
  BASE_UPLOAD_DELAY += 5
268
  await asyncio.sleep(e.value + random.uniform(10, 20))
269
  except Exception as e:
270
+ print(f"⚠️ خطأ: {e}")
271
  async with aiosqlite.connect(DB_PATH) as db:
272
  await db.execute("UPDATE queue SET status='FAILED' WHERE id=?", (q_id,))
273
  await db.commit()
274
+ if os.path.exists(file_path):
275
+ os.remove(file_path)
276
  await asyncio.sleep(5)
277
 
278
+ # ============ التشغيل الرئيسي ============
 
 
 
 
 
 
279
  async def main():
280
  await init_db()
281
  await app.start()
282
 
283
+ print("🔄 جاري الاتصال...")
284
  try:
285
  me = await app.get_me()
286
+ print(f"✅ متصل: {me.first_name}")
287
  async for _ in app.get_dialogs(limit=150):
288
  pass
289
  except Exception as e:
290
+ print(f"⚠️ تحذير: {e}")
291
 
292
+ print("🚀 البوت يعمل!")
293
 
294
  for i in range(2):
295
  asyncio.create_task(download_worker_task(i + 1))
296
 
297
  asyncio.create_task(upload_worker())
 
298
 
299
  await idle()
300
  await app.stop()
301
 
302
+ def run_bot():
303
+ """تشغيل البوت في thread منفصلة"""
304
+ loop = asyncio.new_event_loop()
305
+ asyncio.set_event_loop(loop)
306
  while True:
307
  try:
308
+ loop.run_until_complete(main())
309
+ except Exception as e:
310
+ print(f"💥 إعادة تشغيل: {e}")
311
+ time.sleep(10)
312
+
313
+ # ============ Gradio Interface ============
314
+ bot_status = {"running": False, "logs": "⏳ جاري التشغيل..."}
315
+
316
+ def start_bot():
317
+ if not bot_status["running"]:
318
+ bot_status["running"] = True
319
+ bot_status["logs"] = "🟢 البوت يعمل في الخلفية"
320
+ thread = threading.Thread(target=run_bot, daemon=True)
321
+ thread.start()
322
+ return "✅ تم تشغيل البوت!"
323
+ return "⚠️ البوت يعمل بالفعل!"
324
+
325
+ # تشغيل البوت تلقائياً
326
+ start_bot()
327
+
328
+ with gr.Blocks(title="Telegram Archiver") as demo:
329
+ gr.Markdown("# 📡 Telegram Archiver Bot")
330
+ gr.Markdown("البوت يعمل في الخلفية ويقوم بأرشفة الملفات تلقائياً")
331
+
332
+ status_box = gr.Textbox(label="الحالة", value="🟢 البوت يعمل", interactive=False)
333
+ gr.Markdown("### المتغيرات المطلوبة في Settings:")
334
+ gr.Markdown("- `API_ID`\n- `API_HASH`\n- `SESSION_STRING`\n- `TARGET_CHAT`")
335
+
336
+ demo.launch(server_name="0.0.0.0", server_port=7860)