Reooiq commited on
Commit
f0ca916
·
verified ·
1 Parent(s): ece3133

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +81 -232
bot.py CHANGED
@@ -1,23 +1,19 @@
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
7
- from pyrogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument, InputMediaAudio
8
- from pyrogram.errors import FloodWait, RPCError
9
 
10
- # --- 1. إعداد مساحات التخزين الدائمة ---
11
  DATA_DIR = "/data"
12
- DB_PATH = os.path.join(DATA_DIR, 'bot_memory.db')
13
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
 
14
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
15
 
16
- # --- 2. إعداد قاعدة البيانات ---
17
  conn = sqlite3.connect(DB_PATH, check_same_thread=False)
18
  cursor = conn.cursor()
19
  cursor.execute('''CREATE TABLE IF NOT EXISTS processed (chat_id INTEGER, msg_id INTEGER, UNIQUE(chat_id, msg_id))''')
20
- cursor.execute('''CREATE TABLE IF NOT EXISTS processed_albums (album_id TEXT UNIQUE)''')
21
  conn.commit()
22
 
23
  def is_processed(chat_id, msg_id):
@@ -28,265 +24,118 @@ def mark_processed(chat_id, msg_id):
28
  cursor.execute("INSERT OR IGNORE INTO processed VALUES (?, ?)", (chat_id, msg_id))
29
  conn.commit()
30
 
31
- def is_album_processed(album_id):
32
- cursor.execute("SELECT 1 FROM processed_albums WHERE album_id=?", (album_id,))
33
- return cursor.fetchone() is not None
34
-
35
- def mark_album_processed(album_id):
36
- cursor.execute("INSERT OR IGNORE INTO processed_albums VALUES (?)", (album_id,))
37
- conn.commit()
38
-
39
- # --- 3. سيرفر الويب الوهمي للحفاظ على العمل 24/7 ---
40
- class RequestHandler(BaseHTTPRequestHandler):
41
- def do_GET(self):
42
- body = b"Ultimate Speed Archiver is Running 24/7!"
43
- self.send_response(200)
44
- self.send_header("Content-type", "text/html; charset=utf-8")
45
- self.send_header("Content-Length", str(len(body)))
46
- self.end_headers()
47
- self.wfile.write(body)
48
-
49
- def do_HEAD(self):
50
- body = b"Ultimate Speed Archiver is Running 24/7!"
51
- self.send_response(200)
52
- self.send_header("Content-type", "text/html; charset=utf-8")
53
- self.send_header("Content-Length", str(len(body)))
54
- self.end_headers()
55
-
56
- def log_message(self, format, *args): pass
57
-
58
- def start_web_server():
59
- try:
60
- HTTPServer(('0.0.0.0', 7860), RequestHandler).serve_forever()
61
- except Exception as e:
62
- print(f"⚠️ تجاوز خطأ السيرفر: {e}")
63
-
64
- Thread(target=start_web_server, daemon=True).start()
65
-
66
- # --- 4. إعدادات المتغيرات وتجهيز العميل ---
67
  API_ID = int(os.environ.get("API_ID", 0))
68
  API_HASH = os.environ.get("API_HASH", "")
69
  SESSION_STRING = os.environ.get("SESSION_STRING", "")
 
70
 
71
- target_env = os.environ.get("TARGET_CHAT", "")
72
- TARGET_CHAT = int(target_env) if target_env.lstrip('-').isdigit() else target_env
73
-
74
- source_env = os.environ.get("SOURCE_CHAT", "")
75
- SOURCE_CHAT = int(source_env) if source_env.lstrip('-').isdigit() else source_env
76
-
77
  app = Client(
78
- "my_userbot",
79
- api_id=API_ID,
80
- api_hash=API_HASH,
81
  session_string=SESSION_STRING,
82
- sleep_threshold=300,
83
- max_concurrent_transmissions=5,
84
- workers=10
85
  )
86
 
87
- download_queue = asyncio.Queue()
88
- upload_queue = asyncio.Queue()
89
 
90
- # --- 5. الرادار المباشر + تأخير الألبومات ---
91
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
92
  async def catch_new_messages(client, message):
93
- if message.media_group_id:
94
- if not is_album_processed(str(message.media_group_id)):
95
- mark_album_processed(str(message.media_group_id))
96
- asyncio.create_task(queue_album_after_delay(message))
97
- return
98
-
99
  if not is_processed(message.chat.id, message.id):
100
- await download_queue.put({'type': 'single', 'message': message})
101
-
102
- async def queue_album_after_delay(message):
103
- await asyncio.sleep(4) # مهلة لتجميع كافة أجزاء الألبوم من سيرفرات تيليجرام
104
- await download_queue.put({'type': 'album', 'message': message})
105
 
106
- # --- 6. حاصد الأرشيف المفقود (Backfill History Scanner) ---
107
  async def scan_old_history():
108
- if not SOURCE_CHAT:
109
- print("ℹ️ لم يتم تحديد SOURCE_CHAT في المتغيرات، سيتم الاعتماد على الرصد المباشر فقط.")
110
- return
111
-
112
- print(f"🔎 [جيمي] بدء مسح الأرشيف القديم للقناة المصدر: {SOURCE_CHAT}...")
113
- count = 0
114
  try:
115
- # جلب تاريخ القناة من الأقدم إلى الأحدث
116
- async for message in app.get_chat_history(SOURCE_CHAT):
117
- if message.media:
118
- if message.media_group_id:
119
- if not is_album_processed(str(message.media_group_id)):
120
- mark_album_processed(str(message.media_group_id))
121
- await download_queue.put({'type': 'album', 'message': message})
122
- count += 1
123
- else:
124
- if not is_processed(message.chat.id, message.id):
125
- await download_queue.put({'type': 'single', 'message': message})
126
- count += 1
127
- print(f"✅ اكتمل مسح الأرشيف! تم إدراج {count} عنصر قديم في طابور التحميل.")
128
  except Exception as e:
129
- print(f"❌ خطأ أثناء مسح الأرشيف: {e}")
130
 
131
- # --- 7. كتيبة التحميل إلى التخزين الدائم ---
132
- async def downloader_worker(worker_id):
133
  while True:
134
- task = await download_queue.get()
135
- task_type = task['type']
136
- message = task['message']
137
 
 
 
 
 
 
 
138
  try:
139
- if task_type == 'album':
140
- album_msgs = await app.get_media_group(message.chat.id, message.id)
141
- downloaded_media = []
142
-
143
- for msg in album_msgs:
144
- file_path = await msg.download(file_name=f"{DOWNLOAD_DIR}/")
145
- if file_path:
146
- downloaded_media.append({'path': file_path, 'msg': msg})
147
-
148
- if downloaded_media:
149
- await upload_queue.put({'type': 'album', 'items': downloaded_media})
150
-
151
- elif task_type == 'single':
152
- if is_processed(message.chat.id, message.id):
153
- download_queue.task_done()
154
- continue
155
-
156
- print(f"⚡ [محمل {worker_id}] جارٍ تحميل الملف (ID: {message.id})...")
157
- file_path = await message.download(file_name=f"{DOWNLOAD_DIR}/")
158
-
159
- if file_path:
160
- await upload_queue.put({'type': 'single', 'file_path': file_path, 'message': message})
161
-
162
- except Exception as e:
163
- print(f"❌ خطأ بالتحميل: {e}")
164
- finally:
165
- download_queue.task_done()
166
-
167
- # --- 8. عامل الرفع مع آلية التفكيك الاحتياطية عند الفشل ---
168
- async def send_single_item(file_path, message):
169
- caption = message.caption or ""
170
- entities = message.caption_entities
171
- if message.photo:
172
- await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption, caption_entities=entities)
173
- elif message.video:
174
- await app.send_video(TARGET_CHAT, video=file_path, caption=caption, caption_entities=entities, supports_streaming=True)
175
- elif message.animation:
176
- await app.send_animation(TARGET_CHAT, animation=file_path, caption=caption, caption_entities=entities)
177
- elif message.audio:
178
- await app.send_audio(TARGET_CHAT, audio=file_path, caption=caption, caption_entities=entities)
179
- elif message.voice:
180
- await app.send_voice(TARGET_CHAT, voice=file_path, caption=caption, caption_entities=entities)
181
- else:
182
- await app.send_document(TARGET_CHAT, document=file_path, caption=caption, caption_entities=entities)
183
 
184
- async def uploader_worker():
185
- while True:
186
- task = await upload_queue.get()
187
- task_type = task['type']
188
-
189
- try:
190
- if task_type == 'album':
191
- media_group = []
192
- files_to_remove = []
193
-
194
- for item in task['items']:
195
- file_path = item['path']
196
- msg = item['msg']
197
- files_to_remove.append(file_path)
198
-
199
- caption = msg.caption or ""
200
- entities = msg.caption_entities
201
-
202
- if msg.photo:
203
- media_group.append(InputMediaPhoto(media=file_path, caption=caption, caption_entities=entities))
204
- elif msg.video:
205
- media_group.append(InputMediaVideo(media=file_path, caption=caption, caption_entities=entities, supports_streaming=True))
206
- elif msg.audio:
207
- media_group.append(InputMediaAudio(media=file_path, caption=caption, caption_entities=entities))
208
- elif msg.document:
209
- media_group.append(InputMediaDocument(media=file_path, caption=caption, caption_entities=entities))
210
-
211
- if media_group:
212
- try:
213
- print("🚀 جارٍ رفع الألبوم كدفعة واحدة...")
214
- await app.send_media_group(TARGET_CHAT, media=media_group)
215
- print("✅ تم رفع الألبوم بنجاح!")
216
- except RPCError as e:
217
- print(f"⚠️ فشل رفع الألبوم كمجموعة واحدة ({e}). جارٍ التفكيك والرفع منفصلاً لمنع الفقدان...")
218
- for item in task['items']:
219
- await send_single_item(item['path'], item['msg'])
220
- await asyncio.sleep(2)
221
 
222
- for item in task['items']:
223
- mark_processed(item['msg'].chat.id, item['msg'].id)
224
- if os.path.exists(item['path']): os.remove(item['path'])
 
 
 
 
225
 
226
- elif task_type == 'single':
227
- file_path = task['file_path']
228
- message = task['message']
229
-
230
- print(f"🚀 رفع ملف منفرد (ID: {message.id})...")
231
- await send_single_item(file_path, message)
232
-
233
- mark_processed(message.chat.id, message.id)
234
- print(f"✅ تم الرفع بنجاح!")
235
- if os.path.exists(file_path): os.remove(file_path)
236
-
237
  except FloodWait as e:
238
- print(f"⏳ [حظر إرسال] انتظار {e.value} ثانية... الملفات محفوظة ولن تضيع.")
239
  await asyncio.sleep(e.value + 5)
240
- await upload_queue.put(task)
241
 
242
  except Exception as e:
243
- print(f"❌ خطأ غير متوقع أثناء الرفع: {e}")
244
 
245
  finally:
246
- upload_queue.task_done()
247
- await asyncio.sleep(2.5)
248
-
249
- # --- 9. استرجاع الملفات المعلقة عند إعادة التشغيل ---
250
- async def recover_orphaned_files():
251
- if not os.path.exists(DOWNLOAD_DIR): return
252
- files = [f for f in os.listdir(DOWNLOAD_DIR) if os.path.isfile(os.path.join(DOWNLOAD_DIR, f))]
253
- if files:
254
- print(f"🔍 [استرجاع] العثور على {len(files)} ملف معلق في القرص، جاري إنقاذها...")
255
- for filename in files:
256
- file_path = os.path.join(DOWNLOAD_DIR, filename)
257
- try:
258
- await app.send_document(TARGET_CHAT, document=file_path, caption="♻️ ملف مسترجع تلقائياً")
259
- os.remove(file_path)
260
- await asyncio.sleep(3)
261
- except FloodWait as e:
262
- await asyncio.sleep(e.value + 5)
263
- except Exception as e:
264
- print(f"❌ تعذر إنقاذ {filename}: {e}")
265
-
266
- # --- 10. التشغيل الرئيسي ---
267
  async def main():
268
  await app.start()
 
269
 
270
- print("🔄 جلب بيانات القنوات والاتصال...")
271
- try:
272
- async for dialog in app.get_dialogs():
273
- if dialog.chat.id == TARGET_CHAT:
274
- print(f"✅ القناة الهدف جاهزة: {dialog.chat.title}")
275
- break
276
- except Exception:
277
- pass
278
-
279
- await recover_orphaned_files()
280
 
281
- # تشغيل العمال
282
- for i in range(1, 4):
283
- asyncio.create_task(downloader_worker(i))
284
- asyncio.create_task(uploader_worker())
285
-
286
- # تشغيل مسح الأرشيف القديم لضمان جلب الفيديوهات الـ 116 السابقة
287
  asyncio.create_task(scan_old_history())
288
 
289
- print("🤖 [جيمي] البوت بآلية الفحص الشاملة يعمل الآن بكفاءة!")
290
  await idle()
291
  await app.stop()
292
 
 
1
  import os
2
  import asyncio
3
  import sqlite3
 
 
4
  from pyrogram import Client, filters, idle
5
+ from pyrogram.errors import FloodWait
6
+ from pyrogram.enums import ChatType
7
 
8
+ # --- 1. إعداد مساحات التخزين وقاعدة البيانات ---
9
  DATA_DIR = "/data"
 
10
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
11
+ DB_PATH = os.path.join(DATA_DIR, 'bot_memory.db')
12
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
13
 
 
14
  conn = sqlite3.connect(DB_PATH, check_same_thread=False)
15
  cursor = conn.cursor()
16
  cursor.execute('''CREATE TABLE IF NOT EXISTS processed (chat_id INTEGER, msg_id INTEGER, UNIQUE(chat_id, msg_id))''')
 
17
  conn.commit()
18
 
19
  def is_processed(chat_id, msg_id):
 
24
  cursor.execute("INSERT OR IGNORE INTO processed VALUES (?, ?)", (chat_id, msg_id))
25
  conn.commit()
26
 
27
+ # --- 2. إعدادات الحساب ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  API_ID = int(os.environ.get("API_ID", 0))
29
  API_HASH = os.environ.get("API_HASH", "")
30
  SESSION_STRING = os.environ.get("SESSION_STRING", "")
31
+ TARGET_CHAT = int(os.environ.get("TARGET_CHAT", 0))
32
 
33
+ # تقليل العمال لتجنب استفزاز رادار تيليجرام
 
 
 
 
 
34
  app = Client(
35
+ "restricted_bypass_bot",
36
+ api_id=API_ID,
37
+ api_hash=API_HASH,
38
  session_string=SESSION_STRING,
39
+ max_concurrent_transmissions=2
 
 
40
  )
41
 
42
+ process_queue = asyncio.Queue()
 
43
 
44
+ # --- 3. صائد الرسائل الجديدة ---
45
  @app.on_message(filters.incoming & ~filters.me & (filters.channel | filters.group) & filters.media)
46
  async def catch_new_messages(client, message):
 
 
 
 
 
 
47
  if not is_processed(message.chat.id, message.id):
48
+ await process_queue.put(message)
 
 
 
 
49
 
50
+ # --- 4. حاصد الأرشيف القديم (لكل القنوات المشترك بها) ---
51
  async def scan_old_history():
52
+ print("🔎 [جيمي] بدء مسح أرشيف القنوات والمجموعات...")
 
 
 
 
 
53
  try:
54
+ async for dialog in app.get_dialogs():
55
+ if dialog.chat.type in [ChatType.CHANNEL, ChatType.SUPERGROUP, ChatType.GROUP] and dialog.chat.id != TARGET_CHAT:
56
+ print(f"📂 فحص: {dialog.chat.title}...")
57
+ try:
58
+ async for message in app.get_chat_history(dialog.chat.id):
59
+ if message.media and not is_processed(message.chat.id, message.id):
60
+ await process_queue.put(message)
61
+ except Exception as e:
62
+ print(f"⚠️ تجاوز {dialog.chat.title} بسبب خطأ: {e}")
63
+
64
+ await asyncio.sleep(3) # فاصل بين فحص كل قناة وأخرى
65
+ print("✅ اكتمل سحب كافة الرسائل المفقودة إلى الطابور!")
 
66
  except Exception as e:
67
+ print(f"❌ خطأ عام بالمسح: {e}")
68
 
69
+ # --- 5. محرك الكسر والرفع (العملية المتسلسلة) ---
70
+ async def restricted_bypass_worker():
71
  while True:
72
+ message = await process_queue.get()
 
 
73
 
74
+ # تجنب معالجة ما تم إنجازه
75
+ if is_processed(message.chat.id, message.id):
76
+ process_queue.task_done()
77
+ continue
78
+
79
+ file_path = None
80
  try:
81
+ print(f"⬇️ جاري سحب الملف (ID: {message.id}) من قن��ة مقفلة...")
82
+
83
+ # خطوة 1: التحميل الفعلي
84
+ file_path = await message.download(file_name=f"{DOWNLOAD_DIR}/")
85
+
86
+ if not file_path:
87
+ print("⚠️ فشل التحميل، سيتم التخطي.")
88
+ continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
+ print(f"⬆️ جاري الرفع إلى قناتك...")
91
+
92
+ # خطوة 2: الرفع الفعلي
93
+ caption = message.caption or ""
94
+ if message.photo:
95
+ await app.send_photo(TARGET_CHAT, photo=file_path, caption=caption)
96
+ elif message.video:
97
+ await app.send_video(TARGET_CHAT, video=file_path, caption=caption, supports_streaming=True)
98
+ elif message.document:
99
+ await app.send_document(TARGET_CHAT, document=file_path, caption=caption)
100
+ else:
101
+ await app.send_audio(TARGET_CHAT, audio=file_path, caption=caption) # للأنواع الأخرى
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
+ # خطوة 3: التوثيق في قاعدة البيانات
104
+ mark_processed(message.chat.id, message.id)
105
+ print(f"✅ تم النقل بنجاح!")
106
+
107
+ # خطوة 4: الفاصل الزمني الإجباري (لا تقم بتعديله، فهو درع الحماية من الحظر)
108
+ print("⏳ استراحة أمنية لمدة 12 ثانية...")
109
+ await asyncio.sleep(12)
110
 
 
 
 
 
 
 
 
 
 
 
 
111
  except FloodWait as e:
112
+ print(f"🛑 [تحذير الحظر] تيليجرام يطلب التوقف لمدة {e.value} ثانية! سنطيع الأمر.")
113
  await asyncio.sleep(e.value + 5)
114
+ await process_queue.put(message) # إعادة إدراج الرسالة كي لا تضيع
115
 
116
  except Exception as e:
117
+ print(f"❌ خطأ أثناء معالجة الملف: {e}")
118
 
119
  finally:
120
+ # خطوة 5: حذف الملف فوراً لتجنب امتلاء السيرفر
121
+ if file_path and os.path.exists(file_path):
122
+ try:
123
+ os.remove(file_path)
124
+ except:
125
+ pass
126
+ process_queue.task_done()
127
+
128
+ # --- 6. التشغيل ---
 
 
 
 
 
 
 
 
 
 
 
 
129
  async def main():
130
  await app.start()
131
+ print("🚀 محرك اختراق القنوات المقفلة يعمل الآن بثبات!")
132
 
133
+ # عامل رفع واحد فقط لضمان الترتيب وعدم الضغط على سيرفر تيليجرام
134
+ asyncio.create_task(restricted_bypass_worker())
 
 
 
 
 
 
 
 
135
 
136
+ # تشغيل ماسح الأرشيف لجلب الفيديوهات القديمة
 
 
 
 
 
137
  asyncio.create_task(scan_old_history())
138
 
 
139
  await idle()
140
  await app.stop()
141