Reooiq commited on
Commit
485366f
·
verified ·
1 Parent(s): 08cebb1

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +62 -57
bot.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import asyncio
3
  import sqlite3
 
4
  from threading import Thread
5
  from http.server import BaseHTTPRequestHandler, HTTPServer
6
  from pyrogram import Client, filters, idle
@@ -8,16 +9,21 @@ from pyrogram.errors import FloodWait
8
  from pyrogram.enums import ChatType
9
  from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
10
 
11
- # --- 1. إعداد مساحات التخزين وقاعدة البيانات المستدامة ---
12
  DATA_DIR = "./data"
13
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
14
  DB_PATH = os.path.join(DATA_DIR, 'bot_archiver.db')
15
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
16
 
 
 
 
 
 
17
  conn = sqlite3.connect(DB_PATH, check_same_thread=False)
18
  cursor = conn.cursor()
19
 
20
- # جدول إدارة الطابور وحفظ الألبومات
21
  cursor.execute('''
22
  CREATE TABLE IF NOT EXISTS queue (
23
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -28,18 +34,19 @@ CREATE TABLE IF NOT EXISTS queue (
28
  caption TEXT,
29
  file_path TEXT,
30
  status TEXT DEFAULT 'DOWNLOADED',
31
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
32
  UNIQUE(chat_id, msg_id)
33
  )
34
  ''')
 
35
  conn.commit()
36
 
37
- # --- 2. سيرفر الويب لمنع إغلاق منصة Hugging Face ---
38
  class RequestHandler(BaseHTTPRequestHandler):
39
  def do_GET(self):
40
  self.send_response(200)
41
  self.end_headers()
42
- self.wfile.write(b"Dual-Engine Telegram Archiver Active!")
43
  def log_message(self, format, *args): pass
44
 
45
  Thread(target=lambda: HTTPServer(('0.0.0.0', 7860), RequestHandler).serve_forever(), daemon=True).start()
@@ -56,22 +63,21 @@ app = Client(
56
  api_hash=API_HASH,
57
  session_string=SESSION_STRING,
58
  in_memory=True,
59
- max_concurrent_transmissions=3 # تسريع التحميل المتوازي
60
  )
61
 
62
- # --- 4. دالة التنزيل الآمن مع إعادة المحاولة لكسر خطأ 0 بايت ---
63
  async def download_media_safe(message):
64
  cursor.execute("SELECT status FROM queue WHERE chat_id=? AND msg_id=?", (message.chat.id, message.id))
65
  if cursor.fetchone():
66
- return None # تم تنزيله سابقاً
67
 
68
  unique_name = f"{DOWNLOAD_DIR}/{message.chat.id}_{message.id}"
69
 
70
- for attempt in range(3): # 3 محاولات تنزيل عند حدوث خلل شبكي
71
  try:
72
  file_path = await message.download(file_name=unique_name)
73
  if file_path and os.path.exists(file_path) and os.path.getsize(file_path) > 0:
74
- # تحديد نوع الوسائط
75
  m_type = "doc"
76
  if message.photo: m_type = "photo"
77
  elif message.video: m_type = "video"
@@ -81,64 +87,73 @@ async def download_media_safe(message):
81
  caption = message.caption or ""
82
 
83
  cursor.execute(
84
- "INSERT OR IGNORE INTO queue (chat_id, msg_id, media_group_id, media_type, caption, file_path) VALUES (?, ?, ?, ?, ?, ?)",
85
- (message.chat.id, message.id, group_id, m_type, caption, file_path)
86
  )
87
  conn.commit()
88
- print(f"⚡ [صائد لحظي] تم سحب وحفظ الملف: ID {message.id}")
89
  return file_path
90
  else:
91
- if file_path and os.path.exists(file_path):
92
- os.remove(file_path)
93
  except Exception as e:
94
- print(f"⚠️ محاولة تنزيل فاشلة ({attempt+1}/3) للرسالة {message.id}: {e}")
95
  await asyncio.sleep(2)
96
 
97
  return None
98
 
99
- # --- 5. صائد الرسائل اللحظي (التقاط فوري قبل الحذف) ---
100
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
101
  async def catch_incoming(client, message):
102
  if message.chat.id != TARGET_CHAT:
103
  await download_media_safe(message)
104
 
105
- # --- 6. حاصد السجل القديم ---
106
  async def scan_history_worker():
107
- print("🔎 بدء مسح السجل القديم للمجموعات والقنوات...")
108
  async for dialog in app.get_dialogs():
109
  if dialog.chat.type in [ChatType.CHANNEL, ChatType.SUPERGROUP, ChatType.GROUP] and dialog.chat.id != TARGET_CHAT:
110
  try:
 
 
 
 
111
  async for message in app.get_chat_history(dialog.chat.id):
 
 
112
  if message.media:
113
  await download_media_safe(message)
 
 
 
 
114
  except Exception as e:
115
- print(f"تجاوز القناة {dialog.chat.title} بسبب: {e}")
116
- await asyncio.sleep(5)
117
- print("✅ اكتمل مسح كافة الأرشيفات القديمة.")
118
 
119
- # --- 7. محرك الرفع الذكي وتجميع الألبومات (Uploader & Album Engine) ---
120
  async def upload_worker():
121
  while True:
122
  try:
123
- # البحث عن أقدم عنصر نزل ولم يرفع بعد
124
- cursor.execute("SELECT id, chat_id, msg_id, media_group_id, media_type, caption, file_path FROM queue WHERE status='DOWNLOADED' ORDER BY id ASC LIMIT 1")
125
  row = cursor.fetchone()
126
 
127
  if not row:
128
  await asyncio.sleep(5)
129
  continue
130
 
131
- q_id, chat_id, msg_id, group_id, m_type, caption, file_path = row
132
 
133
- # التأكد من وجود الملف على القرص
134
  if not os.path.exists(file_path):
135
  cursor.execute("UPDATE queue SET status='FAILED' WHERE id=?", (q_id,))
136
  conn.commit()
137
  continue
138
 
139
- # معالجة الألبومات (Media Groups)
140
  if group_id:
141
- await asyncio.sleep(4) # مهلة زمنية للتأكد من اكتمال تنزيل جميع عناصر الألبوم
 
 
 
142
  cursor.execute(
143
  "SELECT id, media_type, caption, file_path FROM queue WHERE chat_id=? AND media_group_id=? AND status='DOWNLOADED' ORDER BY msg_id ASC",
144
  (chat_id, group_id)
@@ -150,28 +165,22 @@ async def upload_worker():
150
  ids_to_update = []
151
  files_to_delete = []
152
 
153
- for idx, g_item in enumerate(group_rows[:10]): # تيليجرام يدعم حتى 10 وسائط في الألبوم الواحد
154
  g_id, g_type, g_cap, g_path = g_item
155
- # وضع النص الوصفي على العنصر الأول فقط في الألبوم
156
  item_caption = g_cap if idx == 0 else ""
157
 
158
- if g_type == "photo":
159
- media_list.append(InputMediaPhoto(media=g_path, caption=item_caption))
160
- elif g_type == "video":
161
- media_list.append(InputMediaVideo(media=g_path, caption=item_caption, supports_streaming=True))
162
- elif g_type == "doc":
163
- media_list.append(InputMediaDocument(media=g_path, caption=item_caption))
164
- elif g_type == "audio":
165
- media_list.append(InputMediaAudio(media=g_path, caption=item_caption))
166
 
167
  ids_to_update.append(g_id)
168
  files_to_delete.append(g_path)
169
 
170
  if media_list:
171
- print(f"📦 جاري رفع ألبوم يحتوي على {len(media_list)} عناصر...")
172
  await app.send_media_group(TARGET_CHAT, media=media_list)
173
 
174
- # تحديث الحالة وحذف الملفات بعد نجاح الرفع
175
  for item_id in ids_to_update:
176
  cursor.execute("UPDATE queue SET status='UPLOADED' WHERE id=?", (item_id,))
177
  conn.commit()
@@ -179,39 +188,35 @@ async def upload_worker():
179
  for f_path in files_to_delete:
180
  if os.path.exists(f_path): os.remove(f_path)
181
 
182
- print("✅ تم رفع الألبوم بنجاح!")
183
- await asyncio.sleep(15) # فاصل حماية بعد رفع الألبوم
184
  continue
185
 
186
- # معالجة الرسائل المنفردة
187
  print(f"⬆️ جاري رفع ملف منفرد (ID: {msg_id})...")
188
- if m_type == "photo":
189
- await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
190
- elif m_type == "video":
191
- await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
192
- elif m_type == "doc":
193
- await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
194
- elif m_type == "audio":
195
- await app.send_audio(TARGET_CHAT, audio=file_path, caption=caption)
196
 
197
  cursor.execute("UPDATE queue SET status='UPLOADED' WHERE id=?", (q_id,))
198
  conn.commit()
199
 
200
  if os.path.exists(file_path): os.remove(file_path)
201
- print(f"✅ تم رفع الملف بنجاح (ID: {msg_id})!")
202
- await asyncio.sleep(12)
203
 
204
  except FloodWait as e:
205
- print(f"🛑 [FloodWait] طلب تيليجرام التوقف لـ {e.value} ثانية. سيتم الانتظار دون فقدان البيانات.")
206
  await asyncio.sleep(e.value + 5)
207
  except Exception as e:
208
  print(f"❌ خطأ أثناء الرفع: {e}")
209
- await asyncio.sleep(10)
210
 
211
  # --- 8. نقطة الانطلاق ---
212
  async def main():
213
  await app.start()
214
- print("🚀 تم تشغيل نظام الأرشيف المدرع (سحب فوري + رفع ألبومات)...")
215
 
216
  asyncio.create_task(upload_worker())
217
  asyncio.create_task(scan_history_worker())
 
1
  import os
2
  import asyncio
3
  import sqlite3
4
+ import time
5
  from threading import Thread
6
  from http.server import BaseHTTPRequestHandler, HTTPServer
7
  from pyrogram import Client, filters, idle
 
9
  from pyrogram.enums import ChatType
10
  from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
11
 
12
+ # --- 1. إعداد مساحات التخزين والتنظيف الأولية ---
13
  DATA_DIR = "./data"
14
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
15
  DB_PATH = os.path.join(DATA_DIR, 'bot_archiver.db')
16
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
17
 
18
+ # تنظيف الملفات المؤقتة والعالقة من التشغيل السابق
19
+ for f in os.listdir(DOWNLOAD_DIR):
20
+ try: os.remove(os.path.join(DOWNLOAD_DIR, f))
21
+ except: pass
22
+
23
  conn = sqlite3.connect(DB_PATH, check_same_thread=False)
24
  cursor = conn.cursor()
25
 
26
+ # إنشاء الجداول بحقول المحاذاة الزمنية
27
  cursor.execute('''
28
  CREATE TABLE IF NOT EXISTS queue (
29
  id INTEGER PRIMARY KEY AUTOINCREMENT,
 
34
  caption TEXT,
35
  file_path TEXT,
36
  status TEXT DEFAULT 'DOWNLOADED',
37
+ timestamp REAL,
38
  UNIQUE(chat_id, msg_id)
39
  )
40
  ''')
41
+ cursor.execute('''CREATE TABLE IF NOT EXISTS scan_progress (chat_id INTEGER PRIMARY KEY, last_msg_id INTEGER)''')
42
  conn.commit()
43
 
44
+ # --- 2. سيرفر الويب الوهمي ---
45
  class RequestHandler(BaseHTTPRequestHandler):
46
  def do_GET(self):
47
  self.send_response(200)
48
  self.end_headers()
49
+ self.wfile.write(b"Super-Engine Archiver Active!")
50
  def log_message(self, format, *args): pass
51
 
52
  Thread(target=lambda: HTTPServer(('0.0.0.0', 7860), RequestHandler).serve_forever(), daemon=True).start()
 
63
  api_hash=API_HASH,
64
  session_string=SESSION_STRING,
65
  in_memory=True,
66
+ max_concurrent_transmissions=2
67
  )
68
 
69
+ # --- 4. دالة التنزيل الآمن مع كسر الـ 0 بايت وحفظ التوقيت ---
70
  async def download_media_safe(message):
71
  cursor.execute("SELECT status FROM queue WHERE chat_id=? AND msg_id=?", (message.chat.id, message.id))
72
  if cursor.fetchone():
73
+ return None
74
 
75
  unique_name = f"{DOWNLOAD_DIR}/{message.chat.id}_{message.id}"
76
 
77
+ for attempt in range(3):
78
  try:
79
  file_path = await message.download(file_name=unique_name)
80
  if file_path and os.path.exists(file_path) and os.path.getsize(file_path) > 0:
 
81
  m_type = "doc"
82
  if message.photo: m_type = "photo"
83
  elif message.video: m_type = "video"
 
87
  caption = message.caption or ""
88
 
89
  cursor.execute(
90
+ "INSERT OR IGNORE INTO queue (chat_id, msg_id, media_group_id, media_type, caption, file_path, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)",
91
+ (message.chat.id, message.id, group_id, m_type, caption, file_path, time.time())
92
  )
93
  conn.commit()
94
+ print(f"⚡ [صائد لحظي] تم تنزيل الملف بنجاح: ID {message.id}")
95
  return file_path
96
  else:
97
+ if file_path and os.path.exists(file_path): os.remove(file_path)
 
98
  except Exception as e:
 
99
  await asyncio.sleep(2)
100
 
101
  return None
102
 
103
+ # --- 5. صائد الرسائل اللحظي ---
104
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
105
  async def catch_incoming(client, message):
106
  if message.chat.id != TARGET_CHAT:
107
  await download_media_safe(message)
108
 
109
+ # --- 6. حاصد الأرشيف الذكي (يستكمل من حيث توقف) ---
110
  async def scan_history_worker():
111
+ print("🔎 بدء مسح الأرشيف القديم...")
112
  async for dialog in app.get_dialogs():
113
  if dialog.chat.type in [ChatType.CHANNEL, ChatType.SUPERGROUP, ChatType.GROUP] and dialog.chat.id != TARGET_CHAT:
114
  try:
115
+ cursor.execute("SELECT last_msg_id FROM scan_progress WHERE chat_id=?", (dialog.chat.id,))
116
+ res = cursor.fetchone()
117
+ last_id = res[0] if res else 0
118
+
119
  async for message in app.get_chat_history(dialog.chat.id):
120
+ if message.id <= last_id:
121
+ break # الوصول إلى ما تم فاعلياً سابقاً
122
  if message.media:
123
  await download_media_safe(message)
124
+
125
+ cursor.execute("INSERT OR REPLACE INTO scan_progress (chat_id, last_msg_id) VALUES (?, ?)", (dialog.chat.id, message.id))
126
+ conn.commit()
127
+
128
  except Exception as e:
129
+ print(f"تجاوز {dialog.chat.title}: {e}")
130
+ await asyncio.sleep(4)
131
+ print("✅ تم استكمال مسح جميع الأرشيفات.")
132
 
133
+ # --- 7. محرك الرفع الذكي (مع مؤقت تجميع الألبومات) ---
134
  async def upload_worker():
135
  while True:
136
  try:
137
+ 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")
 
138
  row = cursor.fetchone()
139
 
140
  if not row:
141
  await asyncio.sleep(5)
142
  continue
143
 
144
+ q_id, chat_id, msg_id, group_id, m_type, caption, file_path, ts = row
145
 
 
146
  if not os.path.exists(file_path):
147
  cursor.execute("UPDATE queue SET status='FAILED' WHERE id=?", (q_id,))
148
  conn.commit()
149
  continue
150
 
151
+ # معالجة الألبومات الذكية بمهلة انتظار (15 ثانية للتأكد من وصول كافة أجزاء الألبوم)
152
  if group_id:
153
+ time_passed = time.time() - ts
154
+ if time_passed < 15:
155
+ await asyncio.sleep(15 - time_passed)
156
+
157
  cursor.execute(
158
  "SELECT id, media_type, caption, file_path FROM queue WHERE chat_id=? AND media_group_id=? AND status='DOWNLOADED' ORDER BY msg_id ASC",
159
  (chat_id, group_id)
 
165
  ids_to_update = []
166
  files_to_delete = []
167
 
168
+ for idx, g_item in enumerate(group_rows[:10]):
169
  g_id, g_type, g_cap, g_path = g_item
 
170
  item_caption = g_cap if idx == 0 else ""
171
 
172
+ if g_type == "photo": media_list.append(InputMediaPhoto(media=g_path, caption=item_caption))
173
+ elif g_type == "video": media_list.append(InputMediaVideo(media=g_path, caption=item_caption, supports_streaming=True))
174
+ elif g_type == "doc": media_list.append(InputMediaDocument(media=g_path, caption=item_caption))
175
+ elif g_type == "audio": media_list.append(InputMediaAudio(media=g_path, caption=item_caption))
 
 
 
 
176
 
177
  ids_to_update.append(g_id)
178
  files_to_delete.append(g_path)
179
 
180
  if media_list:
181
+ print(f"📦 جاري رفع ألبوم كاشمل لـ {len(media_list)} عناصر...")
182
  await app.send_media_group(TARGET_CHAT, media=media_list)
183
 
 
184
  for item_id in ids_to_update:
185
  cursor.execute("UPDATE queue SET status='UPLOADED' WHERE id=?", (item_id,))
186
  conn.commit()
 
188
  for f_path in files_to_delete:
189
  if os.path.exists(f_path): os.remove(f_path)
190
 
191
+ print("✅ تم رفع الألبوم ككتلة واحدة بنجاح!")
192
+ await asyncio.sleep(12)
193
  continue
194
 
195
+ # رفع الملفات الفردية
196
  print(f"⬆️ جاري رفع ملف منفرد (ID: {msg_id})...")
197
+ if m_type == "photo": await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
198
+ elif m_type == "video": await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
199
+ elif m_type == "doc": await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
200
+ elif m_type == "audio": await app.send_audio(TARGET_CHAT, audio=file_path, caption=caption)
 
 
 
 
201
 
202
  cursor.execute("UPDATE queue SET status='UPLOADED' WHERE id=?", (q_id,))
203
  conn.commit()
204
 
205
  if os.path.exists(file_path): os.remove(file_path)
206
+ print(f"✅ تم الرفع بنجاح (ID: {msg_id})!")
207
+ await asyncio.sleep(10)
208
 
209
  except FloodWait as e:
210
+ print(f"🛑 [FloodWait] انتظار إجباري لـ {e.value} ثانية...")
211
  await asyncio.sleep(e.value + 5)
212
  except Exception as e:
213
  print(f"❌ خطأ أثناء الرفع: {e}")
214
+ await asyncio.sleep(8)
215
 
216
  # --- 8. نقطة الانطلاق ---
217
  async def main():
218
  await app.start()
219
+ print("🚀 تشغيل النسخة الفائقة والمعدلة كلياً...")
220
 
221
  asyncio.create_task(upload_worker())
222
  asyncio.create_task(scan_history_worker())