Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -7,6 +7,7 @@ import asyncio
|
|
| 7 |
import re
|
| 8 |
import urllib3
|
| 9 |
import subprocess
|
|
|
|
| 10 |
from flask import Flask, jsonify, make_response, request, Response
|
| 11 |
from supabase import create_client
|
| 12 |
from pyrogram import Client, filters, enums, idle, utils
|
|
@@ -15,6 +16,10 @@ from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInf
|
|
| 15 |
|
| 16 |
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
# ==================== PYROGRAM NEW ID RANGE FIX (MONKEY PATCH) ====================
|
| 19 |
def get_peer_type_new(peer_id: int) -> str:
|
| 20 |
peer_id_str = str(peer_id)
|
|
@@ -100,9 +105,10 @@ def get_msg_file_id(msg):
|
|
| 100 |
if media: return media.file_id
|
| 101 |
return None
|
| 102 |
|
| 103 |
-
# ==================== CUSTOM VIDEO STREAMING ENGINE ====================
|
| 104 |
def get_file_stream(message_id):
|
| 105 |
q = queue.Queue(maxsize=10)
|
|
|
|
| 106 |
|
| 107 |
async def producer():
|
| 108 |
try:
|
|
@@ -110,14 +116,32 @@ def get_file_stream(message_id):
|
|
| 110 |
msg = await bot.get_messages(STORAGE_CHANNEL_ID, message_id)
|
| 111 |
media = get_media_obj(msg)
|
| 112 |
if not media:
|
| 113 |
-
await asyncio.to_thread(q.put, None)
|
|
|
|
| 114 |
return
|
|
|
|
| 115 |
async for chunk in bot.stream_media(msg):
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
except Exception as e:
|
| 118 |
print(f"Error in stream producer: {e}")
|
| 119 |
finally:
|
| 120 |
-
|
|
|
|
|
|
|
| 121 |
|
| 122 |
asyncio.run_coroutine_threadsafe(producer(), main_loop)
|
| 123 |
|
|
@@ -129,6 +153,12 @@ def get_file_stream(message_id):
|
|
| 129 |
if chunk is None: break
|
| 130 |
yield chunk
|
| 131 |
except GeneratorExit:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
while not q.empty():
|
| 133 |
try: q.get_nowait()
|
| 134 |
except: break
|
|
@@ -816,51 +846,77 @@ async def handle_media_upload(client, message):
|
|
| 816 |
await proc.communicate()
|
| 817 |
if not os.path.exists(thumb_path): thumb_path = None
|
| 818 |
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
| 836 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 837 |
|
| 838 |
tg_file_id = get_msg_file_id(sent_to_admin)
|
| 839 |
if not tg_file_id:
|
| 840 |
tg_file_id = get_msg_file_id(message)
|
| 841 |
|
| 842 |
-
await status_msg.delete()
|
|
|
|
| 843 |
|
|
|
|
| 844 |
groups_res = await db_query(lambda: supabase.table('groups').select('group_id').execute())
|
| 845 |
group_ids = [g['group_id'] for g in groups_res.data]
|
| 846 |
success_count, fail_count = 0, 0
|
| 847 |
|
| 848 |
for gid in set(group_ids):
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
else: await client.send_video(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
|
| 852 |
-
success_count += 1
|
| 853 |
-
await asyncio.sleep(1.5)
|
| 854 |
-
except FloodWait as e:
|
| 855 |
-
await asyncio.sleep(e.value + 1)
|
| 856 |
try:
|
| 857 |
if media_type == "photo": await client.send_photo(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
|
| 858 |
else: await client.send_video(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
|
| 859 |
success_count += 1
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 864 |
|
| 865 |
except Exception as e:
|
| 866 |
try: await message.reply(f"⚠️ Error occurred: {str(e)}")
|
|
|
|
| 7 |
import re
|
| 8 |
import urllib3
|
| 9 |
import subprocess
|
| 10 |
+
import logging
|
| 11 |
from flask import Flask, jsonify, make_response, request, Response
|
| 12 |
from supabase import create_client
|
| 13 |
from pyrogram import Client, filters, enums, idle, utils
|
|
|
|
| 16 |
|
| 17 |
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
| 18 |
|
| 19 |
+
# Flask এর অপ্রয়োজনীয় socket.send() এরর লগস বন্ধ করার জন্য
|
| 20 |
+
log = logging.getLogger('werkzeug')
|
| 21 |
+
log.setLevel(logging.ERROR)
|
| 22 |
+
|
| 23 |
# ==================== PYROGRAM NEW ID RANGE FIX (MONKEY PATCH) ====================
|
| 24 |
def get_peer_type_new(peer_id: int) -> str:
|
| 25 |
peer_id_str = str(peer_id)
|
|
|
|
| 105 |
if media: return media.file_id
|
| 106 |
return None
|
| 107 |
|
| 108 |
+
# ==================== CUSTOM VIDEO STREAMING ENGINE (MEMORY LEAK FIXED) ====================
|
| 109 |
def get_file_stream(message_id):
|
| 110 |
q = queue.Queue(maxsize=10)
|
| 111 |
+
stop_flag = [False]
|
| 112 |
|
| 113 |
async def producer():
|
| 114 |
try:
|
|
|
|
| 116 |
msg = await bot.get_messages(STORAGE_CHANNEL_ID, message_id)
|
| 117 |
media = get_media_obj(msg)
|
| 118 |
if not media:
|
| 119 |
+
try: await asyncio.to_thread(q.put, None, True, 1.0)
|
| 120 |
+
except queue.Full: pass
|
| 121 |
return
|
| 122 |
+
|
| 123 |
async for chunk in bot.stream_media(msg):
|
| 124 |
+
if stop_flag[0]: break
|
| 125 |
+
|
| 126 |
+
# Custom wait timeout to check stop_flag efficiently
|
| 127 |
+
put_success = False
|
| 128 |
+
while not stop_flag[0]:
|
| 129 |
+
try:
|
| 130 |
+
await asyncio.to_thread(q.put, chunk, True, 2.0)
|
| 131 |
+
put_success = True
|
| 132 |
+
break
|
| 133 |
+
except queue.Full:
|
| 134 |
+
continue
|
| 135 |
+
|
| 136 |
+
if not put_success:
|
| 137 |
+
break
|
| 138 |
+
|
| 139 |
except Exception as e:
|
| 140 |
print(f"Error in stream producer: {e}")
|
| 141 |
finally:
|
| 142 |
+
if not stop_flag[0]:
|
| 143 |
+
try: await asyncio.to_thread(q.put, None, True, 1.0)
|
| 144 |
+
except queue.Full: pass
|
| 145 |
|
| 146 |
asyncio.run_coroutine_threadsafe(producer(), main_loop)
|
| 147 |
|
|
|
|
| 153 |
if chunk is None: break
|
| 154 |
yield chunk
|
| 155 |
except GeneratorExit:
|
| 156 |
+
# Client closed video player or browser disconnected
|
| 157 |
+
pass
|
| 158 |
+
except Exception as e:
|
| 159 |
+
print(f"Consumer error: {e}")
|
| 160 |
+
finally:
|
| 161 |
+
stop_flag[0] = True
|
| 162 |
while not q.empty():
|
| 163 |
try: q.get_nowait()
|
| 164 |
except: break
|
|
|
|
| 846 |
await proc.communicate()
|
| 847 |
if not os.path.exists(thumb_path): thumb_path = None
|
| 848 |
|
| 849 |
+
# Auto-retry logic for sending final result to admin
|
| 850 |
+
try:
|
| 851 |
+
if media_type == "photo":
|
| 852 |
+
sent_to_admin = await client.send_photo(message.chat.id, telegram_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
|
| 853 |
+
else:
|
| 854 |
+
media = get_media_obj(message)
|
| 855 |
+
vid_duration = media.duration if media and hasattr(media, 'duration') and media.duration else 0
|
| 856 |
+
vid_width = media.width if media and hasattr(media, 'width') and media.width else 0
|
| 857 |
+
vid_height = media.height if media and hasattr(media, 'height') and media.height else 0
|
| 858 |
+
|
| 859 |
+
sent_to_admin = await client.send_video(
|
| 860 |
+
message.chat.id,
|
| 861 |
+
telegram_file,
|
| 862 |
+
caption=admin_cap,
|
| 863 |
+
parse_mode=enums.ParseMode.HTML,
|
| 864 |
+
duration=vid_duration,
|
| 865 |
+
width=vid_width,
|
| 866 |
+
height=vid_height,
|
| 867 |
+
thumb=thumb_path
|
| 868 |
+
)
|
| 869 |
+
except Exception as e:
|
| 870 |
+
await message.reply(f"❌ Failed to send final file to you: {e}")
|
| 871 |
+
return
|
| 872 |
|
| 873 |
tg_file_id = get_msg_file_id(sent_to_admin)
|
| 874 |
if not tg_file_id:
|
| 875 |
tg_file_id = get_msg_file_id(message)
|
| 876 |
|
| 877 |
+
try: await status_msg.delete()
|
| 878 |
+
except: pass
|
| 879 |
|
| 880 |
+
# Broadcast Phase with Retries
|
| 881 |
groups_res = await db_query(lambda: supabase.table('groups').select('group_id').execute())
|
| 882 |
group_ids = [g['group_id'] for g in groups_res.data]
|
| 883 |
success_count, fail_count = 0, 0
|
| 884 |
|
| 885 |
for gid in set(group_ids):
|
| 886 |
+
retries = 3
|
| 887 |
+
while retries > 0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 888 |
try:
|
| 889 |
if media_type == "photo": await client.send_photo(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
|
| 890 |
else: await client.send_video(gid, tg_file_id, caption=caption_text, parse_mode=enums.ParseMode.HTML, reply_markup=group_markup)
|
| 891 |
success_count += 1
|
| 892 |
+
break
|
| 893 |
+
except FloodWait as e:
|
| 894 |
+
await asyncio.sleep(e.value + 1)
|
| 895 |
+
except Exception as e:
|
| 896 |
+
err_msg = str(e).lower()
|
| 897 |
+
if "disconnect" in err_msg or "connection" in err_msg or "timeout" in err_msg:
|
| 898 |
+
retries -= 1
|
| 899 |
+
await asyncio.sleep(3)
|
| 900 |
+
else:
|
| 901 |
+
fail_count += 1
|
| 902 |
+
break
|
| 903 |
+
await asyncio.sleep(1.5)
|
| 904 |
+
|
| 905 |
+
# Success notification with Retries
|
| 906 |
+
retries = 3
|
| 907 |
+
while retries > 0:
|
| 908 |
+
try:
|
| 909 |
+
await message.reply(f"📢 <b>Broadcast Complete!</b>\n\n✅ Success: {success_count} groups\n❌ Failed: {fail_count} groups", parse_mode=enums.ParseMode.HTML)
|
| 910 |
+
break
|
| 911 |
+
except FloodWait as e:
|
| 912 |
+
await asyncio.sleep(e.value + 1)
|
| 913 |
+
except Exception as e:
|
| 914 |
+
err_msg = str(e).lower()
|
| 915 |
+
if "disconnect" in err_msg or "connection" in err_msg or "timeout" in err_msg:
|
| 916 |
+
retries -= 1
|
| 917 |
+
await asyncio.sleep(3)
|
| 918 |
+
else:
|
| 919 |
+
break
|
| 920 |
|
| 921 |
except Exception as e:
|
| 922 |
try: await message.reply(f"⚠️ Error occurred: {str(e)}")
|