pmrony commited on
Commit
9f19490
·
verified ·
1 Parent(s): 098933b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -11
app.py CHANGED
@@ -8,7 +8,7 @@ import urllib3
8
  from flask import Flask, jsonify, make_response, request
9
  from supabase import create_client
10
  from pyrogram import Client, filters, enums, idle
11
- from pyrogram.errors import SessionPasswordNeeded, PhoneCodeInvalid, PhoneCodeExpired, UserDeactivated, SessionRevoked, AuthKeyUnregistered
12
  from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
13
 
14
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@@ -259,7 +259,12 @@ async def bot_added_to_group(client, message):
259
  for member in message.new_chat_members:
260
  if member.id == me.id:
261
  try:
262
- await db_query(lambda: supabase.table('groups').upsert({'group_id': message.chat.id}).execute())
 
 
 
 
 
263
  group_name = message.chat.title
264
  admin_msg = f"✅ <b>Bot added to a new group!</b>\n\n📌 <b>Group Name:</b> {group_name}\n🆔 <b>ID:</b> <code>{message.chat.id}</code>"
265
  for admin_id in ADMIN_IDS:
@@ -267,6 +272,127 @@ async def bot_added_to_group(client, message):
267
  except: pass
268
  except: pass
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  @bot.on_message(filters.command("blur") & filters.private & filters.user(ADMIN_IDS))
271
  async def set_blur_state(client, message):
272
  try:
@@ -358,8 +484,8 @@ async def handle_media_upload(client, message):
358
  if media_type == "video":
359
  duration = message.video.duration if message.video and message.video.duration else 0
360
  file_size = message.video.file_size if message.video and message.video.file_size else 0
361
- MAX_DURATION = 7200 # 2 Hours
362
- MAX_SIZE = 1900 * 1024 * 1024 # 1.9 GB
363
 
364
  if duration > MAX_DURATION or file_size > MAX_SIZE:
365
  is_large_video = True
@@ -372,7 +498,6 @@ async def handle_media_upload(client, message):
372
  original_file, watermarked_file, blurred_file = None, None, None
373
  clean_upload_file, telegram_file, embed_link = None, None, None
374
 
375
- # === Progress Bar Function ===
376
  last_update_time = time.time()
377
  async def download_progress(current, total):
378
  nonlocal last_update_time
@@ -384,13 +509,11 @@ async def handle_media_upload(client, message):
384
  last_update_time = now
385
  except Exception:
386
  pass
387
- # =============================
388
 
389
  try:
390
  original_file = await message.download(progress=download_progress)
391
  clean_upload_file = original_file
392
 
393
- # ১. ওয়াটারমার্ক (Watermark) করা - Balanced (Superfast + CRF 23)
394
  if media_type == "video" and not is_large_video:
395
  await status_msg.edit_text("⏳ Watermarking video... (HD + Superfast Processing)")
396
  watermarked_file = f"{original_file}_wm.mp4"
@@ -405,7 +528,6 @@ async def handle_media_upload(client, message):
405
  if process.returncode == 0 and os.path.exists(watermarked_file):
406
  clean_upload_file = watermarked_file
407
 
408
- # ২. byse.sx সার্ভারে HD / Clean ভিডিও আপলোড করা
409
  if media_type == "video":
410
  await status_msg.edit_text("⏳ Uploading Clean HD video to byse.sx server...")
411
  api_endpoint = "https://api.byse.sx/upload/server"
@@ -433,7 +555,6 @@ async def handle_media_upload(client, message):
433
  await status_msg.delete()
434
  return
435
 
436
- # ৩. টেলিগ্রামে পাঠানোর জন্য ভিডিও ব্লার করা
437
  telegram_file = clean_upload_file
438
  if is_blur and not is_large_video:
439
  await status_msg.edit_text(f"⏳ Applying {blur_percent}% blur for Telegram broadcast...")
@@ -501,6 +622,7 @@ async def handle_media_upload(client, message):
501
  tg_file_id = sent_to_admin.video.file_id
502
 
503
  await status_msg.delete()
 
504
  groups_res = await db_query(lambda: supabase.table('groups').select('group_id').execute())
505
  group_ids = [g['group_id'] for g in groups_res.data]
506
  success_count, fail_count = 0, 0
@@ -512,7 +634,17 @@ async def handle_media_upload(client, message):
512
  else: await client.send_video(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
513
  success_count += 1
514
  await asyncio.sleep(1.5)
515
- except Exception: fail_count += 1
 
 
 
 
 
 
 
 
 
 
516
 
517
  await message.reply(f"📢 <b>Broadcast Complete!</b>\n\n✅ Success: {success_count} groups\n❌ Failed: {fail_count} groups", parse_mode=enums.ParseMode.HTML)
518
 
@@ -561,6 +693,12 @@ async def process_broadcast(client, message):
561
  await message.copy(chat_id=u['user_id'])
562
  success += 1
563
  await asyncio.sleep(0.15)
 
 
 
 
 
 
564
  except Exception: failed += 1
565
 
566
  await message.reply(f"✅ Broadcast Complete!\nSuccess: {success}\nFailed: {failed}")
@@ -624,6 +762,8 @@ async def manual_clean_channel(client, message):
624
  except Exception: pass
625
 
626
  await asyncio.sleep(1.5)
 
 
627
  except Exception:
628
  pass
629
 
@@ -668,6 +808,8 @@ async def auto_clean_channel_loop():
668
  await bot.unban_chat_member(PREMIUM_CHANNEL_ID, user_id)
669
  except Exception: pass
670
  await asyncio.sleep(2)
 
 
671
  except Exception:
672
  pass
673
  except Exception as e:
@@ -675,7 +817,7 @@ async def auto_clean_channel_loop():
675
 
676
  await asyncio.sleep(4 * 3600)
677
 
678
- @bot.on_message(filters.private & filters.user(ADMIN_IDS) & ~filters.command(["start", "stats", "users", "broadcast", "png", "addvideo", "blur", "clean"]))
679
  async def catch_admin_steps(client, message):
680
  state = admin_states.get(message.chat.id, {})
681
  if state.get("step") == 1:
 
8
  from flask import Flask, jsonify, make_response, request
9
  from supabase import create_client
10
  from pyrogram import Client, filters, enums, idle
11
+ from pyrogram.errors import SessionPasswordNeeded, PhoneCodeInvalid, PhoneCodeExpired, UserDeactivated, SessionRevoked, AuthKeyUnregistered, FloodWait
12
  from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
13
 
14
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
 
259
  for member in message.new_chat_members:
260
  if member.id == me.id:
261
  try:
262
+ await db_query(lambda: supabase.table('groups').upsert({
263
+ 'group_id': message.chat.id,
264
+ 'group_name': message.chat.title,
265
+ 'added_by': message.from_user.id if message.from_user else None
266
+ }).execute())
267
+
268
  group_name = message.chat.title
269
  admin_msg = f"✅ <b>Bot added to a new group!</b>\n\n📌 <b>Group Name:</b> {group_name}\n🆔 <b>ID:</b> <code>{message.chat.id}</code>"
270
  for admin_id in ADMIN_IDS:
 
272
  except: pass
273
  except: pass
274
 
275
+ @bot.on_message(filters.command("sendto") & filters.private & filters.user(ADMIN_IDS))
276
+ async def send_to_specific_group(client, message):
277
+ if not message.reply_to_message:
278
+ return await message.reply("❌ <b>Please reply to a message, photo, or video that you want to send.</b>\n\nExample: `/sendto -1001234567890`")
279
+
280
+ args = message.command
281
+ if len(args) < 2:
282
+ return await message.reply("❌ <b>Group ID missing!</b>\n\nCorrect format:\n`/sendto -1003973566529`")
283
+
284
+ try:
285
+ group_id = int(args[1])
286
+ status = await message.reply("⏳ Sending message to group...")
287
+
288
+ await message.reply_to_message.copy(chat_id=group_id)
289
+ await status.edit_text(f"✅ <b>Successfully sent to Group ID:</b> <code>{group_id}</code>", parse_mode=enums.ParseMode.HTML)
290
+ except Exception as e:
291
+ await status.edit_text(f"❌ <b>Failed to send!</b>\nError: {e}", parse_mode=enums.ParseMode.HTML)
292
+
293
+ # ================= DATABASE PROGRESS-BASED CLONING =================
294
+ async def save_progress(source_id, dest_id, msg_id):
295
+ try:
296
+ # ডাটাবেজে আগে থেকে প্রোগ্রেস আছে কিনা চেক করা হচ্ছে
297
+ res = await db_query(lambda: supabase.table('clone_progress').select('id').eq('source_id', source_id).eq('dest_id', dest_id).execute())
298
+ if res.data:
299
+ # থাকলে সেটা আপডেট হবে
300
+ await db_query(lambda: supabase.table('clone_progress').update({'last_copied_id': msg_id}).eq('id', res.data[0]['id']).execute())
301
+ else:
302
+ # না থাকলে নতুন রো ইনসার্ট হবে
303
+ await db_query(lambda: supabase.table('clone_progress').insert({'source_id': source_id, 'dest_id': dest_id, 'last_copied_id': msg_id}).execute())
304
+ except Exception as e:
305
+ print(f"Error saving progress: {e}")
306
+
307
+ async def clone_videos_background(client, source_id, dest_id, status_msg):
308
+ try:
309
+ # ডাটাবেজে আগের কোনো সেভড প্রোগ্রেস আছে কিনা দেখা হচ্ছে
310
+ progress_res = await db_query(lambda: supabase.table('clone_progress').select('last_copied_id').eq('source_id', source_id).eq('dest_id', dest_id).execute())
311
+
312
+ last_copied_id = None
313
+ if progress_res.data:
314
+ last_copied_id = progress_res.data[0]['last_copied_id']
315
+ await status_msg.edit_text(f"⏳ <b>Resuming clone task...</b>\nFound previous progress. Resuming after video ID <code>{last_copied_id}</code>...\nFetching video list from <code>{source_id}</code>...", parse_mode=enums.ParseMode.HTML)
316
+ else:
317
+ await status_msg.edit_text(f"⏳ <b>Cloning started!</b>\nFetching video list from <code>{source_id}</code>...\n<i>This might take a few minutes if the group has many videos.</i>", parse_mode=enums.ParseMode.HTML)
318
+
319
+ video_ids = []
320
+ async for msg in client.search_messages(source_id, filter=enums.MessagesFilter.VIDEO):
321
+ # যদি আগের প্রোগ্রেস থাকে, তবে আগের কপি করা ভিডিওর আইডি থেকে ছোট সব ভিডিও স্কিপ করা হবে
322
+ if last_copied_id and msg.id <= last_copied_id:
323
+ continue
324
+ video_ids.append(msg.id)
325
+ if len(video_ids) % 200 == 0:
326
+ await asyncio.sleep(0.1)
327
+
328
+ if not video_ids:
329
+ if last_copied_id:
330
+ return await status_msg.edit_text("🎉 <b>All videos are already cloned!</b>\nNo new videos found in the source group.", parse_mode=enums.ParseMode.HTML)
331
+ else:
332
+ return await status_msg.edit_text("❌ <b>No videos found in the source group!</b>\n(Make sure the bot is an admin with read history permission in that group).", parse_mode=enums.ParseMode.HTML)
333
+
334
+ video_ids.reverse() # Oldest to newest
335
+ total = len(video_ids)
336
+
337
+ if last_copied_id:
338
+ await status_msg.edit_text(f"✅ Found <b>{total}</b> new videos to clone.\n🚀 Resuming background cloning from oldest to newest...", parse_mode=enums.ParseMode.HTML)
339
+ else:
340
+ await status_msg.edit_text(f"✅ Found <b>{total}</b> videos.\n🚀 Background cloning started from oldest to newest...", parse_mode=enums.ParseMode.HTML)
341
+
342
+ success = 0
343
+ failed = 0
344
+
345
+ for index, msg_id in enumerate(video_ids, 1):
346
+ try:
347
+ await client.copy_message(chat_id=dest_id, from_chat_id=source_id, message_id=msg_id)
348
+ success += 1
349
+ # সফলভাবে কপি হওয়ার সাথে সাথেই ডাটাবেজে প্রোগ্রেস সেভ
350
+ await save_progress(source_id, dest_id, msg_id)
351
+ except FloodWait as e:
352
+ await asyncio.sleep(e.value + 2)
353
+ try:
354
+ await client.copy_message(chat_id=dest_id, from_chat_id=source_id, message_id=msg_id)
355
+ success += 1
356
+ await save_progress(source_id, dest_id, msg_id)
357
+ except Exception:
358
+ failed += 1
359
+ except Exception:
360
+ failed += 1
361
+
362
+ if index % 20 == 0 or index == total:
363
+ try:
364
+ await status_msg.edit_text(f"⏳ <b>Cloning in progress... (Background)</b>\n\nTotal Videos to Copy: <b>{total}</b>\n✅ Copied: <b>{success}</b>\n❌ Failed: <b>{failed}</b>\nLast Video ID: <code>{msg_id}</code>", parse_mode=enums.ParseMode.HTML)
365
+ except FloodWait:
366
+ pass
367
+ except Exception:
368
+ pass
369
+
370
+ await asyncio.sleep(2.5)
371
+
372
+ await status_msg.edit_text(f"🎉 <b>Cloning Completely Finished!</b>\n\nSource: <code>{source_id}</code>\nTotal Copied: <b>{total}</b>\n✅ Successfully Copied: <b>{success}</b>\n❌ Failed: <b>{failed}</b>", parse_mode=enums.ParseMode.HTML)
373
+
374
+ except Exception as e:
375
+ try:
376
+ await status_msg.edit_text(f"❌ <b>Cloning Error:</b> {e}", parse_mode=enums.ParseMode.HTML)
377
+ except: pass
378
+
379
+ @bot.on_message(filters.command("clone") & filters.private & filters.user(ADMIN_IDS))
380
+ async def start_cloning(client, message):
381
+ args = message.command
382
+ if len(args) != 3:
383
+ return await message.reply("❌ <b>Invalid format!</b>\n\nUse: `/clone <Source_Group_ID> <Destination_Group_ID>`\nExample: `/clone -100123456789 -100987654321`", parse_mode=enums.ParseMode.HTML)
384
+
385
+ try:
386
+ source_id = int(args[1])
387
+ dest_id = int(args[2])
388
+ except ValueError:
389
+ return await message.reply("❌ Chat IDs must be numbers.")
390
+
391
+ status_msg = await message.reply("⏳ Initializing cloning task...", parse_mode=enums.ParseMode.HTML)
392
+ asyncio.create_task(clone_videos_background(client, source_id, dest_id, status_msg))
393
+
394
+ # =================================================================
395
+
396
  @bot.on_message(filters.command("blur") & filters.private & filters.user(ADMIN_IDS))
397
  async def set_blur_state(client, message):
398
  try:
 
484
  if media_type == "video":
485
  duration = message.video.duration if message.video and message.video.duration else 0
486
  file_size = message.video.file_size if message.video and message.video.file_size else 0
487
+ MAX_DURATION = 7200
488
+ MAX_SIZE = 1900 * 1024 * 1024
489
 
490
  if duration > MAX_DURATION or file_size > MAX_SIZE:
491
  is_large_video = True
 
498
  original_file, watermarked_file, blurred_file = None, None, None
499
  clean_upload_file, telegram_file, embed_link = None, None, None
500
 
 
501
  last_update_time = time.time()
502
  async def download_progress(current, total):
503
  nonlocal last_update_time
 
509
  last_update_time = now
510
  except Exception:
511
  pass
 
512
 
513
  try:
514
  original_file = await message.download(progress=download_progress)
515
  clean_upload_file = original_file
516
 
 
517
  if media_type == "video" and not is_large_video:
518
  await status_msg.edit_text("⏳ Watermarking video... (HD + Superfast Processing)")
519
  watermarked_file = f"{original_file}_wm.mp4"
 
528
  if process.returncode == 0 and os.path.exists(watermarked_file):
529
  clean_upload_file = watermarked_file
530
 
 
531
  if media_type == "video":
532
  await status_msg.edit_text("⏳ Uploading Clean HD video to byse.sx server...")
533
  api_endpoint = "https://api.byse.sx/upload/server"
 
555
  await status_msg.delete()
556
  return
557
 
 
558
  telegram_file = clean_upload_file
559
  if is_blur and not is_large_video:
560
  await status_msg.edit_text(f"⏳ Applying {blur_percent}% blur for Telegram broadcast...")
 
622
  tg_file_id = sent_to_admin.video.file_id
623
 
624
  await status_msg.delete()
625
+
626
  groups_res = await db_query(lambda: supabase.table('groups').select('group_id').execute())
627
  group_ids = [g['group_id'] for g in groups_res.data]
628
  success_count, fail_count = 0, 0
 
634
  else: await client.send_video(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
635
  success_count += 1
636
  await asyncio.sleep(1.5)
637
+ except FloodWait as e:
638
+ await asyncio.sleep(e.value + 1)
639
+ try:
640
+ if media_type == "photo": await client.send_photo(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
641
+ elif media_type == "animation": await client.send_animation(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
642
+ else: await client.send_video(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
643
+ success_count += 1
644
+ except Exception:
645
+ fail_count += 1
646
+ except Exception:
647
+ fail_count += 1
648
 
649
  await message.reply(f"📢 <b>Broadcast Complete!</b>\n\n✅ Success: {success_count} groups\n❌ Failed: {fail_count} groups", parse_mode=enums.ParseMode.HTML)
650
 
 
693
  await message.copy(chat_id=u['user_id'])
694
  success += 1
695
  await asyncio.sleep(0.15)
696
+ except FloodWait as e:
697
+ await asyncio.sleep(e.value + 1)
698
+ try:
699
+ await message.copy(chat_id=u['user_id'])
700
+ success += 1
701
+ except Exception: failed += 1
702
  except Exception: failed += 1
703
 
704
  await message.reply(f"✅ Broadcast Complete!\nSuccess: {success}\nFailed: {failed}")
 
762
  except Exception: pass
763
 
764
  await asyncio.sleep(1.5)
765
+ except FloodWait as e:
766
+ await asyncio.sleep(e.value + 1)
767
  except Exception:
768
  pass
769
 
 
808
  await bot.unban_chat_member(PREMIUM_CHANNEL_ID, user_id)
809
  except Exception: pass
810
  await asyncio.sleep(2)
811
+ except FloodWait as e:
812
+ await asyncio.sleep(e.value + 1)
813
  except Exception:
814
  pass
815
  except Exception as e:
 
817
 
818
  await asyncio.sleep(4 * 3600)
819
 
820
+ @bot.on_message(filters.private & filters.user(ADMIN_IDS) & ~filters.command(["start", "stats", "users", "broadcast", "png", "addvideo", "blur", "clean", "sendto", "clone"]))
821
  async def catch_admin_steps(client, message):
822
  state = admin_states.get(message.chat.id, {})
823
  if state.get("step") == 1: