Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -108,7 +108,7 @@ def get_file_stream(message_id):
|
|
| 108 |
await asyncio.to_thread(q.put, None)
|
| 109 |
return
|
| 110 |
|
| 111 |
-
# ডাটা রিড করে থ্রেড-সেফ কিউ-তে রাখা হচ্ছে
|
| 112 |
async for chunk in bot.stream_media(media):
|
| 113 |
await asyncio.to_thread(q.put, chunk)
|
| 114 |
except Exception as e:
|
|
@@ -124,7 +124,7 @@ def get_file_stream(message_id):
|
|
| 124 |
try:
|
| 125 |
while True:
|
| 126 |
try:
|
| 127 |
-
# সর্বোচ্চ ১৫ সেকেন্ড অপেক্ষা করবে
|
| 128 |
chunk = q.get(timeout=15)
|
| 129 |
except queue.Empty:
|
| 130 |
break
|
|
@@ -132,7 +132,7 @@ def get_file_stream(message_id):
|
|
| 132 |
break
|
| 133 |
yield chunk
|
| 134 |
except GeneratorExit:
|
| 135 |
-
# ইউজার যদি মাঝপথে ব্রাউজার ট্যাব কেটে দেয়
|
| 136 |
while not q.empty():
|
| 137 |
try: q.get_nowait()
|
| 138 |
except: break
|
|
@@ -420,7 +420,7 @@ async def send_to_specific_group(client, message):
|
|
| 420 |
|
| 421 |
args = message.command
|
| 422 |
if len(args) < 2:
|
| 423 |
-
return await message.reply("❌ <b>Group ID missing!</b>\n\nCorrect format:\n`/sendto -
|
| 424 |
|
| 425 |
try:
|
| 426 |
group_id = int(args[1])
|
|
@@ -616,7 +616,6 @@ def upload_file_sync(upload_url, file_path, api_key):
|
|
| 616 |
except Exception as e:
|
| 617 |
return {}
|
| 618 |
|
| 619 |
-
# filters.document যুক্ত করা হলো যাতে ফাইল/ডকুমেন্ট হিসেবে ভিডিও পাঠালেও বট প্রসেস করতে পারে
|
| 620 |
@bot.on_message((filters.video | filters.animation | filters.photo | filters.document) & filters.private & filters.user(ADMIN_IDS))
|
| 621 |
async def handle_media_upload(client, message):
|
| 622 |
global upload_mode
|
|
@@ -625,16 +624,13 @@ async def handle_media_upload(client, message):
|
|
| 625 |
await process_broadcast(client, message)
|
| 626 |
return
|
| 627 |
|
| 628 |
-
# ফাইলটি ভিডিও, জিআইএফ নাকি ফটো তা নিখুঁতভাবে চেক করা হচ্ছে
|
| 629 |
is_video = message.video or (message.document and message.document.mime_type and "video" in message.document.mime_type)
|
| 630 |
is_animation = message.animation or (message.document and message.document.mime_type and "gif" in message.document.mime_type)
|
| 631 |
is_photo = message.photo or (message.document and message.document.mime_type and "image" in message.document.mime_type)
|
| 632 |
|
| 633 |
-
# যদি ভিডিও, ফটো বা অ্যানিমেশন না হয় তবে কাস্টম ফাইল স্কিপ করবে
|
| 634 |
if not (is_video or is_animation or is_photo):
|
| 635 |
return
|
| 636 |
|
| 637 |
-
# FORCE ANIMATIONS (GIFS) TO BE TREATED AS VIDEOS FOR BROADCAST STABILITY
|
| 638 |
media_type = "video" if (is_video or is_animation) else "photo"
|
| 639 |
has_blur_caption = message.caption and "/blur" in message.caption.lower()
|
| 640 |
is_persistent_blur = bool(state.get("blur_percent"))
|
|
@@ -675,7 +671,6 @@ async def handle_media_upload(client, message):
|
|
| 675 |
|
| 676 |
is_large_video = False
|
| 677 |
if media_type == "video":
|
| 678 |
-
# Safe size checks for both Videos and Animations (GIFs/Documents)
|
| 679 |
media = get_media_obj(message)
|
| 680 |
duration = media.duration if media and hasattr(media, 'duration') and media.duration else 0
|
| 681 |
file_size = media.file_size if media and hasattr(media, 'file_size') and media.file_size else 0
|
|
@@ -693,7 +688,6 @@ async def handle_media_upload(client, message):
|
|
| 693 |
original_file, watermarked_file, blurred_file = None, None, None
|
| 694 |
clean_upload_file, telegram_file, embed_link = None, None, None
|
| 695 |
|
| 696 |
-
# === Progress Bar Function ===
|
| 697 |
last_update_time = time.time()
|
| 698 |
async def download_progress(current, total):
|
| 699 |
nonlocal last_update_time
|
|
@@ -705,18 +699,15 @@ async def handle_media_upload(client, message):
|
|
| 705 |
last_update_time = now
|
| 706 |
except Exception:
|
| 707 |
pass
|
| 708 |
-
# =============================
|
| 709 |
|
| 710 |
try:
|
| 711 |
original_file = await message.download(progress=download_progress)
|
| 712 |
clean_upload_file = original_file
|
| 713 |
|
| 714 |
-
# ১. ওয়াটারমার্ক (Watermark) করা - Balanced (Superfast + CRF 23)
|
| 715 |
if media_type == "video" and not is_large_video:
|
| 716 |
await status_msg.edit_text("⏳ Watermarking video... (HD + Superfast Processing)")
|
| 717 |
watermarked_file = f"{original_file}_wm.mp4"
|
| 718 |
|
| 719 |
-
# জাইএফ ফাইলের ক্ষেত্রে অডিও ট্র্যাক বাদ দেওয়া হবে (-an) অন্যথায় কপি করা হবে
|
| 720 |
has_audio = not (message.animation or (message.document and message.document.mime_type and "gif" in message.document.mime_type))
|
| 721 |
audio_opts = ["-an"] if not has_audio else ["-c:a", "copy"]
|
| 722 |
|
|
@@ -730,18 +721,14 @@ async def handle_media_upload(client, message):
|
|
| 730 |
process = await asyncio.create_subprocess_exec(*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
| 731 |
await process.communicate()
|
| 732 |
|
| 733 |
-
# বাগ সংশোধন: ফাইলের সাইজ ০-এর চেয়ে বেশি হলে তবেই আউটপুট ব্যবহার করা হবে, অন্যথায় অরিじんাল ফাইল ব্যবহৃত হবে
|
| 734 |
if process.returncode == 0 and os.path.exists(watermarked_file) and os.path.getsize(watermarked_file) > 0:
|
| 735 |
clean_upload_file = watermarked_file
|
| 736 |
|
| 737 |
-
# ২. আপনার নিজের টেলিগ্রাম স্টোরেজ চ্যানেলে ফাইল আপলোড (ভিডিও বা ফটো)
|
| 738 |
-
# এখানে থাম্বনেইল, সঠিক ডিউরেশন এবং সাইজ জেনারেট করে পোস্ট করা হবে যাতে সাদা ০:০০ শো না করে
|
| 739 |
storage_msg_id = None
|
| 740 |
if media_type in ["video", "photo"]:
|
| 741 |
if upload_mode == "telegram":
|
| 742 |
await status_msg.edit_text("⏳ Uploading Clean HD video to your storage channel...")
|
| 743 |
|
| 744 |
-
# স্টোরেজ চ্যানেলেও অরিজিনাল থাম্বনেইল, ডিউরেশন এবং সাইজ জেনারেট করে পাঠানো হচ্ছে যাতে সাদা ০:০০ শো না করে
|
| 745 |
thumb_path_storage = f"{original_file}_storage_thumb.jpg"
|
| 746 |
proc = await asyncio.create_subprocess_exec("ffmpeg", "-y", "-i", clean_upload_file, "-vframes", "1", thumb_path_storage, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
| 747 |
await proc.communicate()
|
|
@@ -764,12 +751,10 @@ async def handle_media_upload(client, message):
|
|
| 764 |
)
|
| 765 |
storage_msg_id = sent_to_channel.id
|
| 766 |
|
| 767 |
-
# আপনার নিজস্ব ডোমেইন বা সার্ভারের স্ট্রিমিং ও ডিরেক্ট ডাউনলোড লিংক জেনারেট
|
| 768 |
stream_link = f"{BACKEND_URL}/stream/{storage_msg_id}"
|
| 769 |
download_link = f"{BACKEND_URL}/download/{storage_msg_id}"
|
| 770 |
embed_link = stream_link
|
| 771 |
else:
|
| 772 |
-
# Byse.sx আপলোড মোড
|
| 773 |
await status_msg.edit_text("⏳ Uploading Clean HD video to byse.sx server...")
|
| 774 |
api_endpoint = "https://api.byse.sx/upload/server"
|
| 775 |
loop = asyncio.get_event_loop()
|
|
@@ -799,7 +784,6 @@ async def handle_media_upload(client, message):
|
|
| 799 |
await status_msg.delete()
|
| 800 |
return
|
| 801 |
|
| 802 |
-
# ৩. পাঠানোর জন্য ভিডিও ব্লার করা
|
| 803 |
telegram_file = clean_upload_file
|
| 804 |
if is_blur and not is_large_video:
|
| 805 |
await status_msg.edit_text(f"⏳ Applying {blur_percent}% blur for Telegram broadcast...")
|
|
@@ -815,7 +799,6 @@ async def handle_media_upload(client, message):
|
|
| 815 |
else:
|
| 816 |
ff_filter = ["-vf", f"boxblur={radius}:1"]
|
| 817 |
|
| 818 |
-
# জাইএফ ফাইলের ক্ষেত্রে অডিও ট্র্যাক বাদ দেওয়া হবে (-an) অন্যথায় কপি করা হবে
|
| 819 |
has_audio = not (message.animation or (message.document and message.document.mime_type and "gif" in message.document.mime_type))
|
| 820 |
audio_opts_blur = ["-an"] if not has_audio else []
|
| 821 |
|
|
@@ -827,7 +810,6 @@ async def handle_media_upload(client, message):
|
|
| 827 |
process_blur = await asyncio.create_subprocess_exec(*cmd_blur, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
| 828 |
await process_blur.communicate()
|
| 829 |
|
| 830 |
-
# বাগ সংশোধন: ফাইলের সাইজ ০-এর চেয়ে বেশি হলে তবেই আউটপুট ব্যবহার করা হবে, অন্যথায় অরিジナাল ফাইল ব্যবহৃত হবে
|
| 831 |
if process_blur.returncode == 0 and os.path.exists(blurred_file) and os.path.getsize(blurred_file) > 0:
|
| 832 |
telegram_file = blurred_file
|
| 833 |
|
|
@@ -839,7 +821,6 @@ async def handle_media_upload(client, message):
|
|
| 839 |
|
| 840 |
group_markup = InlineKeyboardMarkup([[InlineKeyboardButton("🎬 Watch Full Video Here 🔞", url=bot_link)]])
|
| 841 |
|
| 842 |
-
# অ্যাডমিন চ্যাটে সাকসেস মেসেজ ও লিংক পাঠানো হচ্ছে
|
| 843 |
admin_cap = (
|
| 844 |
f"✅ <b>Upload and Processing Complete!</b>\n\n"
|
| 845 |
f"🎬 <b>Stream/Watch Online Link:</b>\n<code>{stream_link}</code>\n\n"
|
|
@@ -856,7 +837,6 @@ async def handle_media_upload(client, message):
|
|
| 856 |
if media_type == "photo":
|
| 857 |
sent_to_admin = await client.send_photo(message.chat.id, telegram_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
|
| 858 |
else:
|
| 859 |
-
# Safe dimensions extraction for Videos and Animations
|
| 860 |
media = get_media_obj(message)
|
| 861 |
vid_duration = media.duration if media and hasattr(media, 'duration') and media.duration else 0
|
| 862 |
vid_width = media.width if media and hasattr(media, 'width') and media.width else 0
|
|
@@ -873,10 +853,9 @@ async def handle_media_upload(client, message):
|
|
| 873 |
thumb=thumb_path
|
| 874 |
)
|
| 875 |
|
| 876 |
-
# ক্র্যাশ-ফ্রি উপায়ে file_id রিড করার জন্য ইউনিভার্সাল এক্সট্রাক্টর
|
| 877 |
tg_file_id = get_msg_file_id(sent_to_admin)
|
| 878 |
if not tg_file_id:
|
| 879 |
-
tg_file_id = get_msg_file_id(message)
|
| 880 |
|
| 881 |
await status_msg.delete()
|
| 882 |
|
|
@@ -907,7 +886,7 @@ async def handle_media_upload(client, message):
|
|
| 907 |
except Exception as e: await message.reply(f"⚠️ Error occurred: {str(e)}")
|
| 908 |
finally:
|
| 909 |
for f in [original_file, watermarked_file, blurred_file, f"{original_file}_thumb.jpg" if original_file else None, f"{original_file}_storage_thumb.jpg" if original_file else None]:
|
| 910 |
-
if f
|
| 911 |
try: os.remove(f)
|
| 912 |
except: pass
|
| 913 |
|
|
@@ -1047,7 +1026,7 @@ async def catch_admin_steps(client, message):
|
|
| 1047 |
elif state.get("step") == "broadcast":
|
| 1048 |
await process_broadcast(client, message)
|
| 1049 |
|
| 1050 |
-
def run_flask(): app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)), threaded=True)
|
| 1051 |
|
| 1052 |
async def main():
|
| 1053 |
await bot.start()
|
|
|
|
| 108 |
await asyncio.to_thread(q.put, None)
|
| 109 |
return
|
| 110 |
|
| 111 |
+
# ডাটা রিড করে থ্রেড-সেফ কিউ-তে রাখা হচ্ছে
|
| 112 |
async for chunk in bot.stream_media(media):
|
| 113 |
await asyncio.to_thread(q.put, chunk)
|
| 114 |
except Exception as e:
|
|
|
|
| 124 |
try:
|
| 125 |
while True:
|
| 126 |
try:
|
| 127 |
+
# সর্বোচ্চ ১৫ সেকেন্ড অপেক্ষা করবে
|
| 128 |
chunk = q.get(timeout=15)
|
| 129 |
except queue.Empty:
|
| 130 |
break
|
|
|
|
| 132 |
break
|
| 133 |
yield chunk
|
| 134 |
except GeneratorExit:
|
| 135 |
+
# ইউজার যদি মাঝপথে ব্রাউজার ট্যাব কেটে দেয়
|
| 136 |
while not q.empty():
|
| 137 |
try: q.get_nowait()
|
| 138 |
except: break
|
|
|
|
| 420 |
|
| 421 |
args = message.command
|
| 422 |
if len(args) < 2:
|
| 423 |
+
return await message.reply("❌ <b>Group ID missing!</b>\n\nCorrect format:\n`/sendto -1003973566529`")
|
| 424 |
|
| 425 |
try:
|
| 426 |
group_id = int(args[1])
|
|
|
|
| 616 |
except Exception as e:
|
| 617 |
return {}
|
| 618 |
|
|
|
|
| 619 |
@bot.on_message((filters.video | filters.animation | filters.photo | filters.document) & filters.private & filters.user(ADMIN_IDS))
|
| 620 |
async def handle_media_upload(client, message):
|
| 621 |
global upload_mode
|
|
|
|
| 624 |
await process_broadcast(client, message)
|
| 625 |
return
|
| 626 |
|
|
|
|
| 627 |
is_video = message.video or (message.document and message.document.mime_type and "video" in message.document.mime_type)
|
| 628 |
is_animation = message.animation or (message.document and message.document.mime_type and "gif" in message.document.mime_type)
|
| 629 |
is_photo = message.photo or (message.document and message.document.mime_type and "image" in message.document.mime_type)
|
| 630 |
|
|
|
|
| 631 |
if not (is_video or is_animation or is_photo):
|
| 632 |
return
|
| 633 |
|
|
|
|
| 634 |
media_type = "video" if (is_video or is_animation) else "photo"
|
| 635 |
has_blur_caption = message.caption and "/blur" in message.caption.lower()
|
| 636 |
is_persistent_blur = bool(state.get("blur_percent"))
|
|
|
|
| 671 |
|
| 672 |
is_large_video = False
|
| 673 |
if media_type == "video":
|
|
|
|
| 674 |
media = get_media_obj(message)
|
| 675 |
duration = media.duration if media and hasattr(media, 'duration') and media.duration else 0
|
| 676 |
file_size = media.file_size if media and hasattr(media, 'file_size') and media.file_size else 0
|
|
|
|
| 688 |
original_file, watermarked_file, blurred_file = None, None, None
|
| 689 |
clean_upload_file, telegram_file, embed_link = None, None, None
|
| 690 |
|
|
|
|
| 691 |
last_update_time = time.time()
|
| 692 |
async def download_progress(current, total):
|
| 693 |
nonlocal last_update_time
|
|
|
|
| 699 |
last_update_time = now
|
| 700 |
except Exception:
|
| 701 |
pass
|
|
|
|
| 702 |
|
| 703 |
try:
|
| 704 |
original_file = await message.download(progress=download_progress)
|
| 705 |
clean_upload_file = original_file
|
| 706 |
|
|
|
|
| 707 |
if media_type == "video" and not is_large_video:
|
| 708 |
await status_msg.edit_text("⏳ Watermarking video... (HD + Superfast Processing)")
|
| 709 |
watermarked_file = f"{original_file}_wm.mp4"
|
| 710 |
|
|
|
|
| 711 |
has_audio = not (message.animation or (message.document and message.document.mime_type and "gif" in message.document.mime_type))
|
| 712 |
audio_opts = ["-an"] if not has_audio else ["-c:a", "copy"]
|
| 713 |
|
|
|
|
| 721 |
process = await asyncio.create_subprocess_exec(*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
| 722 |
await process.communicate()
|
| 723 |
|
|
|
|
| 724 |
if process.returncode == 0 and os.path.exists(watermarked_file) and os.path.getsize(watermarked_file) > 0:
|
| 725 |
clean_upload_file = watermarked_file
|
| 726 |
|
|
|
|
|
|
|
| 727 |
storage_msg_id = None
|
| 728 |
if media_type in ["video", "photo"]:
|
| 729 |
if upload_mode == "telegram":
|
| 730 |
await status_msg.edit_text("⏳ Uploading Clean HD video to your storage channel...")
|
| 731 |
|
|
|
|
| 732 |
thumb_path_storage = f"{original_file}_storage_thumb.jpg"
|
| 733 |
proc = await asyncio.create_subprocess_exec("ffmpeg", "-y", "-i", clean_upload_file, "-vframes", "1", thumb_path_storage, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
| 734 |
await proc.communicate()
|
|
|
|
| 751 |
)
|
| 752 |
storage_msg_id = sent_to_channel.id
|
| 753 |
|
|
|
|
| 754 |
stream_link = f"{BACKEND_URL}/stream/{storage_msg_id}"
|
| 755 |
download_link = f"{BACKEND_URL}/download/{storage_msg_id}"
|
| 756 |
embed_link = stream_link
|
| 757 |
else:
|
|
|
|
| 758 |
await status_msg.edit_text("⏳ Uploading Clean HD video to byse.sx server...")
|
| 759 |
api_endpoint = "https://api.byse.sx/upload/server"
|
| 760 |
loop = asyncio.get_event_loop()
|
|
|
|
| 784 |
await status_msg.delete()
|
| 785 |
return
|
| 786 |
|
|
|
|
| 787 |
telegram_file = clean_upload_file
|
| 788 |
if is_blur and not is_large_video:
|
| 789 |
await status_msg.edit_text(f"⏳ Applying {blur_percent}% blur for Telegram broadcast...")
|
|
|
|
| 799 |
else:
|
| 800 |
ff_filter = ["-vf", f"boxblur={radius}:1"]
|
| 801 |
|
|
|
|
| 802 |
has_audio = not (message.animation or (message.document and message.document.mime_type and "gif" in message.document.mime_type))
|
| 803 |
audio_opts_blur = ["-an"] if not has_audio else []
|
| 804 |
|
|
|
|
| 810 |
process_blur = await asyncio.create_subprocess_exec(*cmd_blur, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
| 811 |
await process_blur.communicate()
|
| 812 |
|
|
|
|
| 813 |
if process_blur.returncode == 0 and os.path.exists(blurred_file) and os.path.getsize(blurred_file) > 0:
|
| 814 |
telegram_file = blurred_file
|
| 815 |
|
|
|
|
| 821 |
|
| 822 |
group_markup = InlineKeyboardMarkup([[InlineKeyboardButton("🎬 Watch Full Video Here 🔞", url=bot_link)]])
|
| 823 |
|
|
|
|
| 824 |
admin_cap = (
|
| 825 |
f"✅ <b>Upload and Processing Complete!</b>\n\n"
|
| 826 |
f"🎬 <b>Stream/Watch Online Link:</b>\n<code>{stream_link}</code>\n\n"
|
|
|
|
| 837 |
if media_type == "photo":
|
| 838 |
sent_to_admin = await client.send_photo(message.chat.id, telegram_file, caption=admin_cap, parse_mode=enums.ParseMode.HTML)
|
| 839 |
else:
|
|
|
|
| 840 |
media = get_media_obj(message)
|
| 841 |
vid_duration = media.duration if media and hasattr(media, 'duration') and media.duration else 0
|
| 842 |
vid_width = media.width if media and hasattr(media, 'width') and media.width else 0
|
|
|
|
| 853 |
thumb=thumb_path
|
| 854 |
)
|
| 855 |
|
|
|
|
| 856 |
tg_file_id = get_msg_file_id(sent_to_admin)
|
| 857 |
if not tg_file_id:
|
| 858 |
+
tg_file_id = get_msg_file_id(message)
|
| 859 |
|
| 860 |
await status_msg.delete()
|
| 861 |
|
|
|
|
| 886 |
except Exception as e: await message.reply(f"⚠️ Error occurred: {str(e)}")
|
| 887 |
finally:
|
| 888 |
for f in [original_file, watermarked_file, blurred_file, f"{original_file}_thumb.jpg" if original_file else None, f"{original_file}_storage_thumb.jpg" if original_file else None]:
|
| 889 |
+
if f and os.path.exists(f):
|
| 890 |
try: os.remove(f)
|
| 891 |
except: pass
|
| 892 |
|
|
|
|
| 1026 |
elif state.get("step") == "broadcast":
|
| 1027 |
await process_broadcast(client, message)
|
| 1028 |
|
| 1029 |
+
def run_flask(): app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)), threaded=True)
|
| 1030 |
|
| 1031 |
async def main():
|
| 1032 |
await bot.start()
|