Reooiq commited on
Commit
c1d92bb
·
verified ·
1 Parent(s): 0f6824d

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +5 -17
bot.py CHANGED
@@ -14,8 +14,9 @@ from hydrogram.types import (
14
  from fastapi import FastAPI
15
 
16
  # ============ CRITICAL FIX: Monkey-patch FloodPremiumWait ============
17
- # Older Hydrogram versions don't have FloodPremiumWait. Telegram sends it → AttributeError → infinite crash loop.
18
  import hydrogram.errors.rpc_error as _rpc_error
 
19
  if "FLOOD_PREMIUM_WAIT" not in [k for d in _rpc_error.exceptions.values() for k in d.keys()]:
20
  class FloodPremiumWait(FloodWait):
21
  CODE = 420
@@ -61,7 +62,6 @@ TARGET_CHAT = None
61
 
62
  # ============ Global Flood Control ============
63
  class GlobalFloodControl:
64
- """Pause ALL workers when ANY worker hits a FloodWait."""
65
  def __init__(self):
66
  self.until = 0
67
  self._lock = asyncio.Lock()
@@ -84,7 +84,7 @@ flood_control = GlobalFloodControl()
84
 
85
  # ============ Throttle Controller ============
86
  class ThrottleController:
87
- def __init__(self, rate=3.0): # slightly slower to avoid bans
88
  self.rate = rate
89
  self.last_send = {}
90
  self.lock = asyncio.Lock()
@@ -102,7 +102,7 @@ throttle = ThrottleController(rate=3.0)
102
 
103
  # ============ Locks ============
104
  download_lock = asyncio.Lock()
105
- send_sem = asyncio.Semaphore(1) # reduce to 1 to be gentler on API
106
 
107
  # ============ قاعدة البيانات ============
108
  async def init_db():
@@ -167,7 +167,6 @@ async def add_job(message):
167
  file_id = message.animation.file_id
168
  file_size = message.animation.file_size or 0
169
 
170
- # CRITICAL FIX: Explicit typing to prevent "unsupported type" SQLite errors
171
  chat_id = int(message.chat.id)
172
  message_id = int(message.id)
173
  file_size = int(file_size) if file_size else 0
@@ -194,7 +193,6 @@ async def add_job(message):
194
  logger.error(f"Add job error: {e}")
195
 
196
  async def update_job_status(chat_id, message_id, status, file_path=None, error=None):
197
- # CRITICAL FIX: Explicit int typing
198
  chat_id = int(chat_id)
199
  message_id = int(message_id)
200
 
@@ -208,7 +206,7 @@ async def update_job_status(chat_id, message_id, status, file_path=None, error=N
208
  await db.execute("""
209
  UPDATE jobs SET status=?, error=?, attempts=attempts+1, updated_at=CURRENT_TIMESTAMP
210
  WHERE chat_id=? AND message_id=?
211
- """, (status, str(error)[:500], chat_id, message_id)) # cap error length
212
  else:
213
  await db.execute("""
214
  UPDATE jobs SET status=?, updated_at=CURRENT_TIMESTAMP
@@ -306,7 +304,6 @@ async def verify_download(file_path, expected_size):
306
  return True
307
 
308
  async def download_with_message_object(chat_id, message_id, file_path):
309
- """إعادة جلب الرسالة وتحميلها (الأكثر موثوقية)"""
310
  try:
311
  logger.info(f"Re-fetching message {chat_id}/{message_id}")
312
  message = await app.get_messages(int(chat_id), int(message_id))
@@ -323,8 +320,6 @@ async def download_with_message_object(chat_id, message_id, file_path):
323
  return None
324
 
325
  async def download_job(job):
326
- """3 محاولات: file_id → message object → final retry"""
327
- # CRITICAL FIX: Explicit int typing to prevent SQLite binding errors
328
  chat_id = int(job['chat_id'])
329
  message_id = int(job['message_id'])
330
  expected_size = int(job['file_size'] or 0)
@@ -344,14 +339,12 @@ async def download_job(job):
344
  except:
345
  pass
346
 
347
- # Respect global flood waits before starting
348
  await flood_control.wait()
349
 
350
  try:
351
  await update_job_status(chat_id, message_id, 'downloading')
352
  downloaded = None
353
 
354
- # المحاولة 1: file_id
355
  if file_id:
356
  logger.info(f"Attempt 1 (file_id): {message_id}")
357
  try:
@@ -362,12 +355,10 @@ async def download_job(job):
362
  except Exception as e:
363
  logger.warning(f"file_id failed: {e}")
364
 
365
- # المحاولة 2: message object
366
  if not await verify_download(downloaded, expected_size):
367
  logger.info(f"Attempt 2 (message): {message_id}")
368
  downloaded = await download_with_message_object(chat_id, message_id, file_path)
369
 
370
- # المحاولة 3: إعادة أخيرة
371
  if not await verify_download(downloaded, expected_size):
372
  logger.info(f"Attempt 3 (retry): {message_id}")
373
  await asyncio.sleep(5)
@@ -402,7 +393,6 @@ async def download_job(job):
402
 
403
  # ============ الإرسال ============
404
  async def safe_send(send_func):
405
- """Manual retry that RESPECTS FloodWait from Telegram."""
406
  for attempt in range(5):
407
  try:
408
  return await send_func()
@@ -432,7 +422,6 @@ async def send_job(job):
432
  await update_job_status(chat_id, message_id, 'pending', error="File not found")
433
  return False
434
 
435
- # Respect global flood waits
436
  await flood_control.wait()
437
 
438
  try:
@@ -685,7 +674,6 @@ def run_gradio():
685
 
686
  # ============ Main ============
687
  async def main():
688
- # 🔑 تأكد من عدم وجود اتصال سابق
689
  try:
690
  if app.is_connected:
691
  await app.stop()
 
14
  from fastapi import FastAPI
15
 
16
  # ============ CRITICAL FIX: Monkey-patch FloodPremiumWait ============
17
+ import hydrogram
18
  import hydrogram.errors.rpc_error as _rpc_error
19
+
20
  if "FLOOD_PREMIUM_WAIT" not in [k for d in _rpc_error.exceptions.values() for k in d.keys()]:
21
  class FloodPremiumWait(FloodWait):
22
  CODE = 420
 
62
 
63
  # ============ Global Flood Control ============
64
  class GlobalFloodControl:
 
65
  def __init__(self):
66
  self.until = 0
67
  self._lock = asyncio.Lock()
 
84
 
85
  # ============ Throttle Controller ============
86
  class ThrottleController:
87
+ def __init__(self, rate=3.0):
88
  self.rate = rate
89
  self.last_send = {}
90
  self.lock = asyncio.Lock()
 
102
 
103
  # ============ Locks ============
104
  download_lock = asyncio.Lock()
105
+ send_sem = asyncio.Semaphore(1)
106
 
107
  # ============ قاعدة البيانات ============
108
  async def init_db():
 
167
  file_id = message.animation.file_id
168
  file_size = message.animation.file_size or 0
169
 
 
170
  chat_id = int(message.chat.id)
171
  message_id = int(message.id)
172
  file_size = int(file_size) if file_size else 0
 
193
  logger.error(f"Add job error: {e}")
194
 
195
  async def update_job_status(chat_id, message_id, status, file_path=None, error=None):
 
196
  chat_id = int(chat_id)
197
  message_id = int(message_id)
198
 
 
206
  await db.execute("""
207
  UPDATE jobs SET status=?, error=?, attempts=attempts+1, updated_at=CURRENT_TIMESTAMP
208
  WHERE chat_id=? AND message_id=?
209
+ """, (status, str(error)[:500], chat_id, message_id))
210
  else:
211
  await db.execute("""
212
  UPDATE jobs SET status=?, updated_at=CURRENT_TIMESTAMP
 
304
  return True
305
 
306
  async def download_with_message_object(chat_id, message_id, file_path):
 
307
  try:
308
  logger.info(f"Re-fetching message {chat_id}/{message_id}")
309
  message = await app.get_messages(int(chat_id), int(message_id))
 
320
  return None
321
 
322
  async def download_job(job):
 
 
323
  chat_id = int(job['chat_id'])
324
  message_id = int(job['message_id'])
325
  expected_size = int(job['file_size'] or 0)
 
339
  except:
340
  pass
341
 
 
342
  await flood_control.wait()
343
 
344
  try:
345
  await update_job_status(chat_id, message_id, 'downloading')
346
  downloaded = None
347
 
 
348
  if file_id:
349
  logger.info(f"Attempt 1 (file_id): {message_id}")
350
  try:
 
355
  except Exception as e:
356
  logger.warning(f"file_id failed: {e}")
357
 
 
358
  if not await verify_download(downloaded, expected_size):
359
  logger.info(f"Attempt 2 (message): {message_id}")
360
  downloaded = await download_with_message_object(chat_id, message_id, file_path)
361
 
 
362
  if not await verify_download(downloaded, expected_size):
363
  logger.info(f"Attempt 3 (retry): {message_id}")
364
  await asyncio.sleep(5)
 
393
 
394
  # ============ الإرسال ============
395
  async def safe_send(send_func):
 
396
  for attempt in range(5):
397
  try:
398
  return await send_func()
 
422
  await update_job_status(chat_id, message_id, 'pending', error="File not found")
423
  return False
424
 
 
425
  await flood_control.wait()
426
 
427
  try:
 
674
 
675
  # ============ Main ============
676
  async def main():
 
677
  try:
678
  if app.is_connected:
679
  await app.stop()