pmrony commited on
Commit
48f1d9a
·
verified ·
1 Parent(s): 1606747

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -29
app.py CHANGED
@@ -53,6 +53,13 @@ temp_clients = {}
53
 
54
  upload_mode = "telegram"
55
  ffmpeg_available = True
 
 
 
 
 
 
 
56
  try:
57
  subprocess.run(["ffmpeg", "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
58
  except FileNotFoundError:
@@ -345,6 +352,130 @@ def api_verify_code():
345
  return jsonify(result)
346
  except Exception as e: return jsonify({"status": "error", "msg": str(e)})
347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  # ================= TELEGRAM BOT COMMANDS =================
349
  @bot.on_message(filters.command("start"))
350
  async def start(client, message):
@@ -396,15 +527,6 @@ async def start(client, message):
396
  await message.reply(welcome_text, parse_mode=enums.ParseMode.HTML, reply_markup=markup)
397
  except Exception as e: print(f"Start error: {e}")
398
 
399
- async def save_progress(source_id, dest_id, msg_id):
400
- try:
401
- res = await db_query(lambda: supabase.table('clone_progress').select('id').eq('source_id', source_id).eq('dest_id', dest_id).execute())
402
- if res.data:
403
- await db_query(lambda: supabase.table('clone_progress').update({'last_copied_id': msg_id}).eq('id', res.data[0]['id']).execute())
404
- else:
405
- await db_query(lambda: supabase.table('clone_progress').insert({'source_id': source_id, 'dest_id': dest_id, 'last_copied_id': msg_id}).execute())
406
- except Exception as e: print(f"Error saving progress: {e}")
407
-
408
  @bot.on_message(filters.new_chat_members)
409
  async def bot_added_to_group(client, message):
410
  me = client.me
@@ -821,7 +943,6 @@ async def handle_media_upload(client, message):
821
  await proc.communicate()
822
  if not os.path.exists(thumb_path): thumb_path = None
823
 
824
- # Auto-retry logic for sending final result to admin
825
  try:
826
  if media_type == "photo":
827
  sent_to_admin = await client.send_photo(message.chat.id, telegram_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
@@ -842,7 +963,6 @@ async def handle_media_upload(client, message):
842
  thumb=thumb_path
843
  )
844
 
845
- # সেভ করে রাখা হচ্ছে যাতে নতুন গ্রুপে এড হলে এই ভিডিওটা দিতে পারে
846
  await save_progress(message.chat.id, 0, sent_to_admin.id)
847
 
848
  except Exception as e:
@@ -856,7 +976,6 @@ async def handle_media_upload(client, message):
856
  try: await status_msg.delete()
857
  except: pass
858
 
859
- # Load groups safely with auto-retry
860
  try:
861
  groups_res = await db_query(lambda: supabase.table('groups').select('group_id').execute())
862
  except Exception as db_err:
@@ -866,7 +985,6 @@ async def handle_media_upload(client, message):
866
  group_ids = [g['group_id'] for g in groups_res.data]
867
  success_count, fail_count = 0, 0
868
 
869
- # Safe Broadcast Phase
870
  for gid in set(group_ids):
871
  retries = 3
872
  while retries > 0:
@@ -888,7 +1006,6 @@ async def handle_media_upload(client, message):
888
  break
889
  await asyncio.sleep(1.5)
890
 
891
- # Success notification safely
892
  retries = 3
893
  while retries > 0:
894
  try:
@@ -1057,7 +1174,7 @@ async def auto_clean_channel_loop():
1057
  print(f"Auto clean error: {e}")
1058
  await asyncio.sleep(4 * 3600)
1059
 
1060
- @bot.on_message(filters.private & filters.user(ADMIN_IDS) & ~filters.command(["start", "stats", "users", "broadcast", "png", "addvideo", "blur", "clean", "sendto", "clone", "upload"]))
1061
  async def catch_admin_steps(client, message):
1062
  state = admin_states.get(message.chat.id, {})
1063
  if state.get("step") == 1:
@@ -1078,9 +1195,6 @@ async def catch_admin_steps(client, message):
1078
  # ==========================================
1079
  # REDIS QUEUE WATERMARK MULTIPROCESSING
1080
  # ==========================================
1081
- import json
1082
- import redis.asyncio as redis
1083
-
1084
  REDIS_URL = os.environ.get("REDIS_URL_1")
1085
 
1086
  processing_owners = set()
@@ -1094,13 +1208,10 @@ async def process_single_video(task, redis_client):
1094
  wm_text = task['watermark_text']
1095
  task_id = f"{owner_id}_{message_id}"
1096
 
1097
- # ==============================
1098
- # FIX: আগে ভেরিয়েবল ডিফাইন করা হলো যাতে finally ব্লকে এরর না আসে
1099
  raw_video_path = None
1100
  watermarked_path = None
1101
  thumb_path = f"thumb_{task_id}.jpg"
1102
  clone_client = None
1103
- # ==============================
1104
 
1105
  print(f"▶️ [WM] Task Started for User: {owner_id}, Msg: {message_id}")
1106
 
@@ -1122,7 +1233,6 @@ async def process_single_video(task, redis_client):
1122
 
1123
  watermarked_path = f"wm_{task_id}.mp4"
1124
 
1125
- # Hugging Face এ দ্রুত প্রসেস করার জন্য ultrafast, threads 4 এবং crf 26 ব্যবহার করা হলো
1126
  cmd = [
1127
  "ffmpeg", "-y", "-i", raw_video_path,
1128
  "-vf", f"drawtext=text='{wm_text}':x=W-tw-20:y=H-th-20:fontsize=22:fontcolor=white@0.7:shadowcolor=black@0.8:shadowx=2:shadowy=2:enable='gte(t,5)'",
@@ -1146,14 +1256,12 @@ async def process_single_video(task, redis_client):
1146
 
1147
  await clone_client.edit_message_text(owner_id, status_msg.id, "⏳ <b>ফাইনাল ভিডিও স্টোরেজে আপলোড হচ্ছে...</b>", parse_mode=enums.ParseMode.HTML)
1148
 
1149
- # Background এ অরিজিনাল ভিডিও স্টোরেজে পাঠানো হচ্ছে, যাতে ইউজারকে ওয়েট করতে না হয়
1150
  async def backup_raw_video():
1151
  try:
1152
  await bot.send_video(chat_id=STORAGE_CHANNEL_ID, video=raw_video_path, caption=f"Original Backup for Clone Owner {owner_id}")
1153
  except Exception: pass
1154
  asyncio.create_task(backup_raw_video())
1155
 
1156
- # ওয়াটারমার্ক করা ভিডিওটি আপলোড হচ্ছে (সঠিক Stream Link বানানোর জন্য)
1157
  wm_sent = await bot.send_video(
1158
  chat_id=STORAGE_CHANNEL_ID,
1159
  video=watermarked_path,
@@ -1161,7 +1269,6 @@ async def process_single_video(task, redis_client):
1161
  thumb=thumb_path
1162
  )
1163
 
1164
- # FIX: এখন লিংকগুলো অরিজিনালের বদলে ওয়াটারমার্ক ভিডিও পয়েন্ট করবে
1165
  wm_storage_id = wm_sent.id
1166
  stream_link = f"{BACKEND_URL}/stream/{wm_storage_id}"
1167
  download_link = f"{BACKEND_URL}/download/{wm_storage_id}"
@@ -1191,7 +1298,6 @@ async def process_single_video(task, redis_client):
1191
  print(f"❌ [WM] Failed to send error msg to user: {ex}")
1192
 
1193
  finally:
1194
- # ফাইল এবং লক ক্লিনআপ
1195
  if raw_video_path and os.path.exists(raw_video_path): os.remove(raw_video_path)
1196
  if watermarked_path and os.path.exists(watermarked_path): os.remove(watermarked_path)
1197
  if thumb_path and os.path.exists(thumb_path): os.remove(thumb_path)
@@ -1218,7 +1324,6 @@ async def watermark_processor_loop():
1218
  print(f"❌ Redis Connection Failed in Hugging Face: {e}")
1219
  return
1220
 
1221
- # Clear stuck locks
1222
  try:
1223
  async for key in redis_client.scan_iter("wm_processing:*"):
1224
  await redis_client.delete(key)
@@ -1264,5 +1369,4 @@ async def main():
1264
 
1265
  if __name__ == "__main__":
1266
  threading.Thread(target=run_flask, daemon=True).start()
1267
- main_loop.run_until_complete(main())
1268
- #--- END OF FILE main.py
 
53
 
54
  upload_mode = "telegram"
55
  ffmpeg_available = True
56
+
57
+ # ================= AUTO SHARE VARIABLES =================
58
+ auto_share_running = False
59
+ auto_share_task = None
60
+ TARGET_SHARE_GROUP = -1004333630822
61
+ # =========================================================
62
+
63
  try:
64
  subprocess.run(["ffmpeg", "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
65
  except FileNotFoundError:
 
352
  return jsonify(result)
353
  except Exception as e: return jsonify({"status": "error", "msg": str(e)})
354
 
355
+
356
+ async def save_progress(source_id, dest_id, msg_id):
357
+ try:
358
+ res = await db_query(lambda: supabase.table('clone_progress').select('id').eq('source_id', source_id).eq('dest_id', dest_id).execute())
359
+ if res.data:
360
+ await db_query(lambda: supabase.table('clone_progress').update({'last_copied_id': msg_id}).eq('id', res.data[0]['id']).execute())
361
+ else:
362
+ await db_query(lambda: supabase.table('clone_progress').insert({'source_id': source_id, 'dest_id': dest_id, 'last_copied_id': msg_id}).execute())
363
+ except Exception as e: print(f"Error saving progress: {e}")
364
+
365
+
366
+ # ================= AUTO SHARE LOGIC (5 videos / 5 mins) =================
367
+ async def auto_share_loop(client, target_chat_id, delay=300):
368
+ global auto_share_running
369
+
370
+ while auto_share_running:
371
+ try:
372
+ # Check maximum message ID to avoid infinite blank search
373
+ latest_msg_id = 0
374
+ async for m in client.get_chat_history(STORAGE_CHANNEL_ID, limit=1):
375
+ latest_msg_id = m.id
376
+ break
377
+
378
+ progress_res = await db_query(lambda: supabase.table('clone_progress').select('last_copied_id').eq('source_id', STORAGE_CHANNEL_ID).eq('dest_id', target_chat_id).execute())
379
+ last_checked_id = 0
380
+ if progress_res.data:
381
+ last_checked_id = progress_res.data[0]['last_copied_id']
382
+
383
+ if latest_msg_id > 0 and last_checked_id >= latest_msg_id:
384
+ await asyncio.sleep(60)
385
+ continue
386
+
387
+ batch_to_send = []
388
+ while len(batch_to_send) < 5 and auto_share_running:
389
+ if latest_msg_id > 0 and last_checked_id >= latest_msg_id:
390
+ break
391
+
392
+ chunk_ids = list(range(last_checked_id + 1, min(last_checked_id + 51, latest_msg_id + 1)))
393
+ if not chunk_ids:
394
+ break
395
+
396
+ try:
397
+ msgs = await client.get_messages(STORAGE_CHANNEL_ID, chunk_ids)
398
+ for idx, msg in enumerate(msgs):
399
+ msg_expected_id = chunk_ids[idx]
400
+ if msg is None or getattr(msg, "empty", False):
401
+ last_checked_id = max(last_checked_id, msg_expected_id)
402
+ continue
403
+
404
+ if msg.video or (msg.document and msg.document.mime_type and "video" in msg.document.mime_type) or msg.photo:
405
+ batch_to_send.append(msg)
406
+ last_checked_id = max(last_checked_id, msg.id)
407
+ if len(batch_to_send) == 5:
408
+ break
409
+ else:
410
+ last_checked_id = max(last_checked_id, msg.id)
411
+ except FloodWait as e:
412
+ await asyncio.sleep(e.value + 1)
413
+ except Exception as e:
414
+ print(f"Fetch error in auto share: {e}")
415
+ await asyncio.sleep(5)
416
+
417
+ if not batch_to_send:
418
+ await save_progress(STORAGE_CHANNEL_ID, target_chat_id, last_checked_id)
419
+ await asyncio.sleep(10)
420
+ continue
421
+
422
+ sent_message_ids = []
423
+ for msg in batch_to_send:
424
+ if not auto_share_running: break
425
+ try:
426
+ sent = await msg.copy(target_chat_id)
427
+ sent_message_ids.append(sent.id)
428
+ await asyncio.sleep(1.5)
429
+ except FloodWait as e:
430
+ await asyncio.sleep(e.value + 1)
431
+ except Exception as e:
432
+ print(f"Error copying msg {msg.id}: {e}")
433
+
434
+ await save_progress(STORAGE_CHANNEL_ID, target_chat_id, last_checked_id)
435
+
436
+ for _ in range(delay):
437
+ if not auto_share_running: break
438
+ await asyncio.sleep(1)
439
+
440
+ if sent_message_ids and auto_share_running:
441
+ try:
442
+ await client.delete_messages(target_chat_id, sent_message_ids)
443
+ except FloodWait as e:
444
+ await asyncio.sleep(e.value + 1)
445
+ await client.delete_messages(target_chat_id, sent_message_ids)
446
+ except Exception as e:
447
+ print(f"Error deleting msgs: {e}")
448
+
449
+ except Exception as e:
450
+ print(f"Auto-share loop error: {e}")
451
+ await asyncio.sleep(5)
452
+
453
+ @bot.on_message(filters.command("startshare") & filters.private & filters.user(ADMIN_IDS))
454
+ async def start_sharing_cmd(client, message):
455
+ global auto_share_running, auto_share_task
456
+ args = message.command
457
+
458
+ if len(args) > 1 and args[1].lower() == "reset":
459
+ await save_progress(STORAGE_CHANNEL_ID, TARGET_SHARE_GROUP, 0)
460
+ await message.reply("🔄 <b>Progress reset!</b> The bot will now start sharing from the 1st video.")
461
+
462
+ if auto_share_running:
463
+ return await message.reply("⚠️ <b>Auto-share is already running!</b>\nUse `/stopshare` to stop it first.")
464
+
465
+ auto_share_running = True
466
+ auto_share_task = asyncio.create_task(auto_share_loop(client, TARGET_SHARE_GROUP, 300))
467
+ await message.reply(f"✅ <b>Auto-sharing started!</b>\n\n📌 <b>Target Group:</b> <code>{TARGET_SHARE_GROUP}</code>\n📦 <b>Batch Size:</b> 5 videos\n⏱ <b>Interval:</b> 5 minutes\n\n<i>Bot will send 5 videos, wait 5 minutes, delete them, and send the next 5!</i>", parse_mode=enums.ParseMode.HTML)
468
+
469
+ @bot.on_message(filters.command("stopshare") & filters.private & filters.user(ADMIN_IDS))
470
+ async def stop_sharing_cmd(client, message):
471
+ global auto_share_running
472
+ if not auto_share_running:
473
+ return await message.reply("⚠️ Auto-share is not currently running.")
474
+
475
+ auto_share_running = False
476
+ await message.reply("🛑 <b>Auto-sharing stopped successfully!</b>", parse_mode=enums.ParseMode.HTML)
477
+
478
+
479
  # ================= TELEGRAM BOT COMMANDS =================
480
  @bot.on_message(filters.command("start"))
481
  async def start(client, message):
 
527
  await message.reply(welcome_text, parse_mode=enums.ParseMode.HTML, reply_markup=markup)
528
  except Exception as e: print(f"Start error: {e}")
529
 
 
 
 
 
 
 
 
 
 
530
  @bot.on_message(filters.new_chat_members)
531
  async def bot_added_to_group(client, message):
532
  me = client.me
 
943
  await proc.communicate()
944
  if not os.path.exists(thumb_path): thumb_path = None
945
 
 
946
  try:
947
  if media_type == "photo":
948
  sent_to_admin = await client.send_photo(message.chat.id, telegram_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
 
963
  thumb=thumb_path
964
  )
965
 
 
966
  await save_progress(message.chat.id, 0, sent_to_admin.id)
967
 
968
  except Exception as e:
 
976
  try: await status_msg.delete()
977
  except: pass
978
 
 
979
  try:
980
  groups_res = await db_query(lambda: supabase.table('groups').select('group_id').execute())
981
  except Exception as db_err:
 
985
  group_ids = [g['group_id'] for g in groups_res.data]
986
  success_count, fail_count = 0, 0
987
 
 
988
  for gid in set(group_ids):
989
  retries = 3
990
  while retries > 0:
 
1006
  break
1007
  await asyncio.sleep(1.5)
1008
 
 
1009
  retries = 3
1010
  while retries > 0:
1011
  try:
 
1174
  print(f"Auto clean error: {e}")
1175
  await asyncio.sleep(4 * 3600)
1176
 
1177
+ @bot.on_message(filters.private & filters.user(ADMIN_IDS) & ~filters.command(["start", "stats", "users", "broadcast", "png", "addvideo", "blur", "clean", "sendto", "clone", "upload", "startshare", "stopshare"]))
1178
  async def catch_admin_steps(client, message):
1179
  state = admin_states.get(message.chat.id, {})
1180
  if state.get("step") == 1:
 
1195
  # ==========================================
1196
  # REDIS QUEUE WATERMARK MULTIPROCESSING
1197
  # ==========================================
 
 
 
1198
  REDIS_URL = os.environ.get("REDIS_URL_1")
1199
 
1200
  processing_owners = set()
 
1208
  wm_text = task['watermark_text']
1209
  task_id = f"{owner_id}_{message_id}"
1210
 
 
 
1211
  raw_video_path = None
1212
  watermarked_path = None
1213
  thumb_path = f"thumb_{task_id}.jpg"
1214
  clone_client = None
 
1215
 
1216
  print(f"▶️ [WM] Task Started for User: {owner_id}, Msg: {message_id}")
1217
 
 
1233
 
1234
  watermarked_path = f"wm_{task_id}.mp4"
1235
 
 
1236
  cmd = [
1237
  "ffmpeg", "-y", "-i", raw_video_path,
1238
  "-vf", f"drawtext=text='{wm_text}':x=W-tw-20:y=H-th-20:fontsize=22:fontcolor=white@0.7:shadowcolor=black@0.8:shadowx=2:shadowy=2:enable='gte(t,5)'",
 
1256
 
1257
  await clone_client.edit_message_text(owner_id, status_msg.id, "⏳ <b>ফাইনাল ভিডিও স্টোরেজে আপলোড হচ্ছে...</b>", parse_mode=enums.ParseMode.HTML)
1258
 
 
1259
  async def backup_raw_video():
1260
  try:
1261
  await bot.send_video(chat_id=STORAGE_CHANNEL_ID, video=raw_video_path, caption=f"Original Backup for Clone Owner {owner_id}")
1262
  except Exception: pass
1263
  asyncio.create_task(backup_raw_video())
1264
 
 
1265
  wm_sent = await bot.send_video(
1266
  chat_id=STORAGE_CHANNEL_ID,
1267
  video=watermarked_path,
 
1269
  thumb=thumb_path
1270
  )
1271
 
 
1272
  wm_storage_id = wm_sent.id
1273
  stream_link = f"{BACKEND_URL}/stream/{wm_storage_id}"
1274
  download_link = f"{BACKEND_URL}/download/{wm_storage_id}"
 
1298
  print(f"❌ [WM] Failed to send error msg to user: {ex}")
1299
 
1300
  finally:
 
1301
  if raw_video_path and os.path.exists(raw_video_path): os.remove(raw_video_path)
1302
  if watermarked_path and os.path.exists(watermarked_path): os.remove(watermarked_path)
1303
  if thumb_path and os.path.exists(thumb_path): os.remove(thumb_path)
 
1324
  print(f"❌ Redis Connection Failed in Hugging Face: {e}")
1325
  return
1326
 
 
1327
  try:
1328
  async for key in redis_client.scan_iter("wm_processing:*"):
1329
  await redis_client.delete(key)
 
1369
 
1370
  if __name__ == "__main__":
1371
  threading.Thread(target=run_flask, daemon=True).start()
1372
+ main_loop.run_until_complete(main())