Reooiq commited on
Commit
6bd7bde
·
verified ·
1 Parent(s): bd30725

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +62 -23
bot.py CHANGED
@@ -4,14 +4,14 @@ import logging
4
  import time
5
  import threading
6
  import shutil
7
- from typing import Optional, List, Dict, Any, Set
8
  import aiosqlite
9
  import gradio as gr
10
- from hydrogram import Client, filters
11
  from hydrogram.errors import FloodWait, RPCError
12
  from hydrogram.types import (
13
  InputMediaPhoto, InputMediaVideo, InputMediaDocument,
14
- InputMediaAudio, Message, Chat
15
  )
16
  from fastapi import FastAPI
17
  import uvicorn
@@ -44,7 +44,7 @@ logging.basicConfig(
44
  format='%(asctime)s | %(levelname)-7s | %(message)s',
45
  datefmt='%Y-%m-%d %H:%M:%S'
46
  )
47
- logger = logging.getLogger("AutoArchiverPro")
48
 
49
  # ============ الإعدادات والمتغيرات ============
50
  API_ID = int(os.environ.get("API_ID", 0))
@@ -55,12 +55,12 @@ AUTO_SCAN_ALL = os.environ.get("AUTO_SCAN_ALL", "1") == "1"
55
 
56
  DATA_DIR = "/data" if os.path.exists("/data") else "/tmp/data"
57
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
58
- DB_PATH = os.path.join(DATA_DIR, "auto_archiver_v4.db")
59
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
60
 
61
  # ============ إنشاء العميل ============
62
  app = Client(
63
- "auto_archiver",
64
  api_id=API_ID,
65
  api_hash=API_HASH,
66
  session_string=SESSION_STRING,
@@ -69,7 +69,7 @@ app = Client(
69
  max_concurrent_transmissions=4,
70
  device_model="Universal Archiver Server",
71
  system_version="Linux 64bit",
72
- app_version="4.0.0",
73
  lang_code="ar"
74
  )
75
 
@@ -88,9 +88,9 @@ stats = {
88
  "status": "Starting..."
89
  }
90
 
91
- # ============ إدارة التحكم بالسرعة وتفادي الحظر ============
92
  class SmartFloodManager:
93
- def __init__(self, normal_delay: float = 1.6):
94
  self.normal_delay = normal_delay
95
  self.last_call = 0.0
96
  self.lock = asyncio.Lock()
@@ -113,9 +113,9 @@ class SmartFloodManager:
113
  def handle_flood(self, seconds: int):
114
  wait_seconds = max(seconds, 5) + 2
115
  self.flood_until = time.time() + wait_seconds
116
- logger.warning(f"🚨 استلام FloodWait من تيليجرام: {seconds} ثانية. تهدئة حتى {wait_seconds} ثانية.")
117
 
118
- flood_manager = SmartFloodManager(normal_delay=1.8)
119
 
120
  # ============ قاعدة البيانات ذاتية الإصلاح والتحديث ============
121
  def cleanup_corrupted_files():
@@ -175,7 +175,7 @@ async def init_db():
175
  chat_type TEXT,
176
  last_scraped_id INTEGER DEFAULT 0,
177
  total_queued INTEGER DEFAULT 0,
178
- status TEXT DEFAULT 'idle', -- idle, in_progress, completed
179
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
180
  )
181
  """)
@@ -381,27 +381,38 @@ async def queue_worker_loop():
381
  logger.error(f"خطأ في محرك الإرسال: {e}")
382
  await asyncio.sleep(4)
383
 
384
- # ============ تسخين ذاكرة المحادثات وحل خطأ PEER_ID_INVALID نهائياً ============
385
  async def warm_up_dialogs_cache() -> List[Dict[str, Any]]:
386
  logger.info("🔄 جاري فحص وتسخين ذاكرة القنوات والمجموعات المنضم إليها الحساب...")
387
  discovered = []
388
  try:
389
  async for dialog in app.get_dialogs():
390
  chat = dialog.chat
 
 
 
391
  if TARGET_CHAT_ID and chat.id == TARGET_CHAT_ID:
392
  continue
393
- if chat.type in ["channel", "supergroup", "group"]:
 
 
 
 
 
 
 
394
  chat_info = {
395
  "id": chat.id,
396
- "title": chat.title or f"Chat_{chat.id}",
397
  "username": chat.username or "",
398
- "type": chat.type
399
  }
400
  KNOWN_CHATS[chat.id] = chat_info
401
  discovered.append(chat_info)
 
402
 
403
  stats["discovered_chats"] = len(discovered)
404
- logger.info(f"✅ تم اكتشاف وتأمين {len(discovered)} قناة ومجموعة بنجاح!")
405
  return discovered
406
  except Exception as e:
407
  logger.error(f"خطأ أثناء جلب المحادثات: {e}")
@@ -483,7 +494,7 @@ async def scrape_all_joined_chats(limit_per_chat: int = 0) -> str:
483
  try:
484
  chats = await warm_up_dialogs_cache()
485
  if not chats:
486
- return "لم يتم العثور على قنوات أو مجموعات في الحساب."
487
 
488
  logger.info(f"🚀 بدء عملية الفحص الشامل لـ {len(chats)} قناة ومجموعة...")
489
  total_all = 0
@@ -514,12 +525,13 @@ async def realtime_all_chats_handler(client, message: Message):
514
  if str(message.chat.id) == str(TARGET_CHAT):
515
  return
516
 
517
- if message.chat.id not in KNOWN_CHATS and message.chat.type in ["channel", "supergroup", "group"]:
 
518
  KNOWN_CHATS[message.chat.id] = {
519
  "id": message.chat.id,
520
  "title": message.chat.title or f"Chat_{message.chat.id}",
521
  "username": message.chat.username or "",
522
- "type": message.chat.type
523
  }
524
 
525
  if message.media_group_id:
@@ -570,7 +582,7 @@ def create_dashboard():
570
  gr.Markdown("""
571
  # 🌐 Universal Telegram Archiver Pro (النسخة الشاملة التلقائية)
572
  **يسحب من جميع القنوات والكروبات المنضم إليها تلقائياً بدون استثناء وبدون ضياع ملف واحد:**
573
- * ✅ حل مشكلة `PEER_ID_INVALID` بشكل جذري بتسخين الذاكرة التلقائي.
574
  * ✅ فحص أرشيف كل القنوات والمجموعات المنضم إليها دفعة واحدة تلقائياً.
575
  * ✅ رصد فوري لحظي لأي ملف أو ألبوم ينزل في أي قناة أو كروب.
576
  * ✅ طابور ذكي دائم مع كتابة المصدر ورقم المقطع ونظام ضد الحظر.
@@ -591,6 +603,13 @@ def create_dashboard():
591
 
592
  scrape_status = gr.Textbox(label="حالة الفحص والعمليات", interactive=False)
593
 
 
 
 
 
 
 
 
594
  def trigger_scan_all(lim):
595
  if MAIN_LOOP and MAIN_LOOP.is_running():
596
  asyncio.run_coroutine_threadsafe(
@@ -600,20 +619,40 @@ def create_dashboard():
600
  return "🚀 تم بدء عملية الفحص الشامل لجميع القنوات والكروبات في الخلفية بنجاح! راقب السجلات والطابور."
601
  return "❌ تعذر إطلاق المهمة، تأكد من اتصال البوت."
602
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  scan_all_btn.click(fn=trigger_scan_all, inputs=[limit_input], outputs=[scrape_status])
 
604
 
605
  return demo
606
 
607
  # ============ تشغيل الويب ============
608
  def run_web_server():
609
  fastapi_app = FastAPI()
610
- demo = create_dashboard()
611
- gr.mount_gradio_app(fastapi_app, demo, path="/")
612
 
613
  @fastapi_app.get("/health")
614
  async def health():
615
  return {"status": "ok", "stats": stats}
616
 
 
 
 
 
 
 
 
617
  uvicorn.run(fastapi_app, host="0.0.0.0", port=7860)
618
 
619
  # ============ نقطة الدخول ============
 
4
  import time
5
  import threading
6
  import shutil
7
+ from typing import Optional, List, Dict, Any
8
  import aiosqlite
9
  import gradio as gr
10
+ from hydrogram import Client, filters, enums
11
  from hydrogram.errors import FloodWait, RPCError
12
  from hydrogram.types import (
13
  InputMediaPhoto, InputMediaVideo, InputMediaDocument,
14
+ InputMediaAudio, Message
15
  )
16
  from fastapi import FastAPI
17
  import uvicorn
 
44
  format='%(asctime)s | %(levelname)-7s | %(message)s',
45
  datefmt='%Y-%m-%d %H:%M:%S'
46
  )
47
+ logger = logging.getLogger("UniversalArchiver")
48
 
49
  # ============ الإعدادات والمتغيرات ============
50
  API_ID = int(os.environ.get("API_ID", 0))
 
55
 
56
  DATA_DIR = "/data" if os.path.exists("/data") else "/tmp/data"
57
  DOWNLOAD_DIR = os.path.join(DATA_DIR, "downloads")
58
+ DB_PATH = os.path.join(DATA_DIR, "ultra_archiver_v5.db")
59
  os.makedirs(DOWNLOAD_DIR, exist_ok=True)
60
 
61
  # ============ إنشاء العميل ============
62
  app = Client(
63
+ "universal_archiver",
64
  api_id=API_ID,
65
  api_hash=API_HASH,
66
  session_string=SESSION_STRING,
 
69
  max_concurrent_transmissions=4,
70
  device_model="Universal Archiver Server",
71
  system_version="Linux 64bit",
72
+ app_version="5.0.0",
73
  lang_code="ar"
74
  )
75
 
 
88
  "status": "Starting..."
89
  }
90
 
91
+ # ============ إدارة التحكم بالسرعة ومكافحة الحظر ============
92
  class SmartFloodManager:
93
+ def __init__(self, normal_delay: float = 1.5):
94
  self.normal_delay = normal_delay
95
  self.last_call = 0.0
96
  self.lock = asyncio.Lock()
 
113
  def handle_flood(self, seconds: int):
114
  wait_seconds = max(seconds, 5) + 2
115
  self.flood_until = time.time() + wait_seconds
116
+ logger.warning(f"🚨 استلام FloodWait: {seconds} ثانية. تهدئة العمليات حتى {wait_seconds} ثانية.")
117
 
118
+ flood_manager = SmartFloodManager(normal_delay=1.6)
119
 
120
  # ============ قاعدة البيانات ذاتية الإصلاح والتحديث ============
121
  def cleanup_corrupted_files():
 
175
  chat_type TEXT,
176
  last_scraped_id INTEGER DEFAULT 0,
177
  total_queued INTEGER DEFAULT 0,
178
+ status TEXT DEFAULT 'idle',
179
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
180
  )
181
  """)
 
381
  logger.error(f"خطأ في محرك الإرسال: {e}")
382
  await asyncio.sleep(4)
383
 
384
+ # ============ فحص وتسخين الذاكرة لجميع المحادثات ============
385
  async def warm_up_dialogs_cache() -> List[Dict[str, Any]]:
386
  logger.info("🔄 جاري فحص وتسخين ذاكرة القنوات والمجموعات المنضم إليها الحساب...")
387
  discovered = []
388
  try:
389
  async for dialog in app.get_dialogs():
390
  chat = dialog.chat
391
+ if not chat:
392
+ continue
393
+
394
  if TARGET_CHAT_ID and chat.id == TARGET_CHAT_ID:
395
  continue
396
+ if str(chat.id) == str(TARGET_CHAT):
397
+ continue
398
+
399
+ type_str = str(chat.type).lower()
400
+ is_group_or_channel = any(k in type_str for k in ["channel", "supergroup", "group"])
401
+
402
+ if is_group_or_channel:
403
+ title = chat.title or chat.first_name or f"Chat_{chat.id}"
404
  chat_info = {
405
  "id": chat.id,
406
+ "title": title,
407
  "username": chat.username or "",
408
+ "type": type_str
409
  }
410
  KNOWN_CHATS[chat.id] = chat_info
411
  discovered.append(chat_info)
412
+ logger.info(f"📌 تم اكتشاف: [{title}] | الآيدي: ({chat.id}) | النوع: ({type_str})")
413
 
414
  stats["discovered_chats"] = len(discovered)
415
+ logger.info(f"✅ اكتمل الفحص: تم تأمين وتسجيل {len(discovered)} قناة ومجموعة بنجاح!")
416
  return discovered
417
  except Exception as e:
418
  logger.error(f"خطأ أثناء جلب المحادثات: {e}")
 
494
  try:
495
  chats = await warm_up_dialogs_cache()
496
  if not chats:
497
+ return "لم يتم العثور على قنوات أو مجموعات في الحساب. تأكد من أن الحساب منضم إلى قنوات."
498
 
499
  logger.info(f"🚀 بدء عملية الفحص الشامل لـ {len(chats)} قناة ومجموعة...")
500
  total_all = 0
 
525
  if str(message.chat.id) == str(TARGET_CHAT):
526
  return
527
 
528
+ type_str = str(message.chat.type).lower()
529
+ if message.chat.id not in KNOWN_CHATS and any(k in type_str for k in ["channel", "supergroup", "group"]):
530
  KNOWN_CHATS[message.chat.id] = {
531
  "id": message.chat.id,
532
  "title": message.chat.title or f"Chat_{message.chat.id}",
533
  "username": message.chat.username or "",
534
+ "type": type_str
535
  }
536
 
537
  if message.media_group_id:
 
582
  gr.Markdown("""
583
  # 🌐 Universal Telegram Archiver Pro (النسخة الشاملة التلقائية)
584
  **يسحب من جميع القنوات والكروبات المنضم إليها تلقائياً بدون استثناء وبدون ضياع ملف واحد:**
585
+ * ✅ حل مشكلة `PEER_ID_INVALID` بشكل جذري.
586
  * ✅ فحص أرشيف كل القنوات والمجموعات المنضم إليها دفعة واحدة تلقائياً.
587
  * ✅ رصد فوري لحظي لأي ملف أو ألبوم ينزل في أي قناة أو كروب.
588
  * ✅ طابور ذكي دائم مع كتابة المصدر ورقم المقطع ونظام ضد الحظر.
 
603
 
604
  scrape_status = gr.Textbox(label="حالة الفحص والعمليات", interactive=False)
605
 
606
+ gr.Markdown("---")
607
+ gr.Markdown("### 🎯 فحص قناة أو كروب محدد (اختياري):")
608
+ with gr.Row():
609
+ single_ch_input = gr.Textbox(label="معرف أو رابط القناة", placeholder="@my_channel أو https://t.me/...")
610
+ single_lim_input = gr.Number(label="الحد الأقصى (0 = الكل)", value=0)
611
+ single_scan_btn = gr.Button("فحص هذه القناة فقط 📥")
612
+
613
  def trigger_scan_all(lim):
614
  if MAIN_LOOP and MAIN_LOOP.is_running():
615
  asyncio.run_coroutine_threadsafe(
 
619
  return "🚀 تم بدء عملية الفحص الشامل لجميع القنوات والكروبات في الخلفية بنجاح! راقب السجلات والطابور."
620
  return "❌ تعذر إطلاق المهمة، تأكد من اتصال البوت."
621
 
622
+ def trigger_single_scan(ch, lim):
623
+ if not ch or not ch.strip():
624
+ return "⚠️ يرجى إدخال معرف القناة أولاً."
625
+ if MAIN_LOOP and MAIN_LOOP.is_running():
626
+ async def do_single():
627
+ try:
628
+ c = await app.get_chat(ch.strip())
629
+ await scrape_single_chat(c.id, c.title or ch, int(lim))
630
+ except Exception as e:
631
+ logger.error(f"Single scan error: {e}")
632
+ asyncio.run_coroutine_threadsafe(do_single(), MAIN_LOOP)
633
+ return f"🚀 تم بدء فحص القناة ({ch}) بنجاح!"
634
+ return "❌ تعذر إطلاق المهمة."
635
+
636
  scan_all_btn.click(fn=trigger_scan_all, inputs=[limit_input], outputs=[scrape_status])
637
+ single_scan_btn.click(fn=trigger_single_scan, inputs=[single_ch_input, single_lim_input], outputs=[scrape_status])
638
 
639
  return demo
640
 
641
  # ============ تشغيل الويب ============
642
  def run_web_server():
643
  fastapi_app = FastAPI()
 
 
644
 
645
  @fastapi_app.get("/health")
646
  async def health():
647
  return {"status": "ok", "stats": stats}
648
 
649
+ @fastapi_app.get("/ping")
650
+ async def ping():
651
+ return {"status": "alive", "stats": stats}
652
+
653
+ demo = create_dashboard()
654
+ gr.mount_gradio_app(fastapi_app, demo, path="/")
655
+
656
  uvicorn.run(fastapi_app, host="0.0.0.0", port=7860)
657
 
658
  # ============ نقطة الدخول ============