import base64
from fastapi import Query
import os
import time
import asyncio
import traceback
import re
import subprocess
from pathlib import Path

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse, StreamingResponse
import uvicorn

from pyrogram import Client, filters, enums
from pyrogram.types import Message
from pytgcalls import PyTgCalls, idle
from pytgcalls import filters as ptg_filters
from pytgcalls.types import MediaStream, AudioQuality, VideoQuality
from pytgcalls.types.stream import StreamEnded
from pytgcalls.filters import create
import yt_dlp
import edge_tts  # 🔴 CORE NEURAL ENGINE

import json
import pyrogram.raw as pyrogram_raw

import datetime
import pyrogram.raw as pyrogram_raw
import traceback
import random

import json
import os
from pathlib import Path

import concurrent.futures
import signal

import urllib.request
import urllib.error
# --- START OF REPLACEMENT BLOCK (Neural Welcome Matrix & Cache Flush) ---
import random
import unicodedata
# --- START OF REPLACEMENT BLOCK (Security Imports) ---
import urllib.error
import hmac       # 🔴 برای جلوگیری از حملات Timing Attack
import secrets    # 🔴 برای تولید توکن‌های امن
from fastapi.responses import JSONResponse, HTMLResponse, StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
# --- END OF REPLACEMENT BLOCK ---

# --- START OF REPLACEMENT BLOCK (Next-Gen Multilingual Azure Engine) ---
import uuid
# --- START OF NEW BLOCK (Neural AI Chatbot Variables) ---
from collections import deque
import datetime

# 🔴 لینک ورکرهای کلودفلر خود را اینجا بگذارید
AI_WORKER_NODES = [
    "https://ai1.afshinshadmanp.workers.dev/",
    "https://ai2.afshinshadmanp.workers.dev/"
]

# دیتابیس درون‌حافظه‌ای برای نگهداری تاریخچه چت (Context)
# فرمت: {chat_id_user_id: deque([{"role": "...", "parts": [{"text": "..."}]}])}
AI_CHAT_HISTORY = {}

# دیتابیس درون‌حافظه‌ای برای کنترل لیمیت روزانه
# فرمت: {user_id: {"date": "YYYY-MM-DD", "count": 0}}
AI_DAILY_LIMITS = {}

AI_MAX_HISTORY_TURNS = 10  # تعداد پیام‌هایی که ربات از هر کاربر به خاطر می‌سپارد (5 جفت سوال و جواب)
AI_MAX_DAILY_REQUESTS = 30 # سقف درخواست روزانه هر کاربر برای جلوگیری از لیمیت شدن API

# --- START OF NEW BLOCK: AI State Machine Globals ---
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery

# ماشین وضعیت برای مدیریت مکالمه چندمرحله‌ای هوش مصنوعی
# فرمت: {user_id: {"state": "IDLE" | "AWAITING_PROMPT", "mode": "flash", "timestamp": 1234567.89}}
# --- START OF NEW BLOCK: AI State Machine Globals ---
# ماشین وضعیت برای مدیریت مکالمه چندمرحله‌ای هوش مصنوعی متنی (بدون دکمه شیشه‌ای)
# فرمت: {user_id: {"state": "IDLE" | "AWAITING_MODE_SELECTION" | "AWAITING_PROMPT", "mode": "flash", "timestamp": 1234567.89}}
AI_SESSION_STATE = {}

def _smart_telegram_chunker(text: str, chunk_size: int = 3900) -> list:
    """
    تکه‌کننده هوشمند متن (Smart Markdown Chunker)
    متون طولانی را بدون شکستن ساختار کدهای برنامه‌نویسی و پاراگراف‌ها تقسیم می‌کند.
    """
    if not text: return []
    if len(text) <= chunk_size: return [text]

    chunks = []
    while text:
        if len(text) <= chunk_size:
            chunks.append(text)
            break

        split_index = text.rfind('\n\n', 0, chunk_size)
        if split_index == -1:
            split_index = text.rfind('\n', 0, chunk_size)
        if split_index == -1:
            split_index = text.rfind(' ', 0, chunk_size)
        if split_index == -1:
            split_index = chunk_size

        chunk = text[:split_index]

        if chunk.count('```') % 2 != 0:
            chunk += '\n```\n'
            text = '```\n' + text[split_index:].lstrip()
        else:
            text = text[split_index:].lstrip()

        chunks.append(chunk.strip())
    return chunks
# --- END OF NEW BLOCK ---
# --- END OF NEW BLOCK ---
# --- END OF NEW BLOCK ---
# --- LIVE STREAM CONTROL SYSTEM (MP3 SYNC-SAFE INJECTOR) ---
# --- START OF REPLACEMENT BLOCK 1 (Global Dict Fix) ---
LIVE_SYSTEM = {
    "is_armed": False,  
    "is_streaming": False,  
    "chat_id": None,
    "pipe_path": "/tmp/hacker_live.mp3", 
    "transcoder_proc": None,
    "mode": "live",
    "tts_queue": None, # 🔴 اینجا موقتاً None می‌گذاریم (از کرش سیستم جلوگیری می‌کند)
    "standby_active": False,
    "audio_queues": set(),
    "ring_buffer": [],
    "header_cache": None
}
# --- END OF REPLACEMENT BLOCK 1 ---
# --- START OF REPLACEMENT BLOCK (Admin Manager Persistence Matrix) ---


# مسیر ذخیره‌سازی هارد دیسک (دقیقاً متناسب با ساختار سرور شما)
ADMIN_DB_PATH = Path("/var/www/html/GAP#") / "admin_matrix_db.json"

# پایگاه داده درون‌حافظه‌ای (In-Memory)
ADMIN_MANAGER = {
    "active_chats": set(),
    "whitelisted_admins": set(),
    "ban_records": {},
    "BAN_LIMIT": 5,
    "TIME_WINDOW_SEC": 48 * 3600
}

_LAST_SAVED_STATE = None

# --- START OF REPLACEMENT BLOCK (Admin Matrix DB Upgraded) ---
def load_admin_matrix():
    global _LAST_SAVED_STATE
    try:
        if ADMIN_DB_PATH.exists():
            with open(ADMIN_DB_PATH, 'r', encoding='utf-8') as f:
                data = json.load(f)
                ADMIN_MANAGER["active_chats"] = set(data.get("active_chats", []))
                ADMIN_MANAGER["whitelisted_admins"] = set(data.get("whitelisted_admins", []))
                ADMIN_MANAGER["meow_cleaner"] = set(data.get("meow_cleaner", []))
                
                # 🔴 کلیدهای جدید سیستم امنیتی
                ADMIN_MANAGER["configured_chats"] = set(data.get("configured_chats", []))
                ADMIN_MANAGER["anti_swear"] = set(data.get("anti_swear", []))
                ADMIN_MANAGER["anti_spam"] = set(data.get("anti_spam", []))
                
                loaded_records = {}
                for chat_id_str, admins in data.get("ban_records", {}).items():
                    loaded_records[int(chat_id_str)] = {int(admin_id_str): history for admin_id_str, history in admins.items()}
                
                ADMIN_MANAGER["ban_records"] = loaded_records
                _LAST_SAVED_STATE = json.dumps(data, sort_keys=True)
            print("[ADMIN MATRIX] Persistent Database Loaded Successfully (V2.0).")
    except Exception as e:
        print(f"[ADMIN MATRIX] Boot Recovery Error: {e}")

load_admin_matrix()

async def admin_matrix_autosaver():
    global _LAST_SAVED_STATE
    while True:
        try:
            await asyncio.sleep(15)
            async with STATE_LOCK:
                # 🔴 استفاده از .copy() برای جلوگیری از RuntimeError در سیستم‌های Multi-Task
                export_data = {
                    "active_chats": list(ADMIN_MANAGER.setdefault("active_chats", set()).copy()),
                    "whitelisted_admins": list(ADMIN_MANAGER.setdefault("whitelisted_admins", set()).copy()),
                    "meow_cleaner": list(ADMIN_MANAGER.setdefault("meow_cleaner", set()).copy()),
                    "configured_chats": list(ADMIN_MANAGER.setdefault("configured_chats", set()).copy()),
                    "anti_swear": list(ADMIN_MANAGER.setdefault("anti_swear", set()).copy()),
                    "anti_spam": list(ADMIN_MANAGER.setdefault("anti_spam", set()).copy()),
                    "ban_records": {k: v.copy() for k, v in ADMIN_MANAGER.setdefault("ban_records", {}).items()}
                }
            
            current_state_json = json.dumps(export_data, sort_keys=True)
            if current_state_json != _LAST_SAVED_STATE:
                def _write_atomic():
                    tmp_file = f"{ADMIN_DB_PATH}.tmp"
                    with open(tmp_file, 'w', encoding='utf-8') as f:
                        f.write(current_state_json)
                    os.replace(tmp_file, ADMIN_DB_PATH)
                await asyncio.to_thread(_write_atomic)
                _LAST_SAVED_STATE = current_state_json
        except Exception as e:
            print(f"[DB SAVER ERROR] {e}") # اضافه شدن لاگ برای دیباگ خاموش

# 🔴 سیستم مدیریت کلاینت‌های وب‌سوکت برای برودکست لحظه‌ای
ACTIVE_WEBSOCKETS = set()

# --- START OF REPLACEMENT BLOCK (Core System Mutex & Process Terminator) ---

# 🔴 استخر پردازشی ایزوله (Thread Pool) برای عملیات I/O-Bound (جلوگیری از Starvation و فریز سرور)
# این استخر تعداد تردها را محدود کرده و از خفگی Event Loop اصلی پایتون جلوگیری می‌کند.
SYSTEM_IO_POOL = concurrent.futures.ThreadPoolExecutor(max_workers=16, thread_name_prefix="Matrix_IO")

# 🔴 قفل اتمیک (Mutex Lock) برای محافظت از State ماشین هنگام تغییرات همزمان (Race Conditions)
STATE_LOCK = asyncio.Lock()

async def _safe_terminate_process(proc):
    """قاتل بی‌رحم پروسه‌های زامبی در سطح Kernel لینوکس (SIGKILL)"""
    if not proc: return
    try:
        if proc.returncode is None:
            # 1. بستن شریان‌های ورودی/خروجی (File Descriptors) برای جلوگیری از Broken Pipe
            for fd in [proc.stdin, proc.stdout, proc.stderr]:
                if fd and not getattr(fd, 'is_closing', lambda: True)():
                    try: fd.close()
                    except: pass
            # 2. شلیک سیگنال قطعی خاتمه به سیستم‌عامل
            try: 
                proc.kill()
                os.kill(proc.pid, signal.SIGKILL)
            except: pass
            # 3. اطمینان از خروج کامل از جدول پروسه‌های OS با تایم‌اوت
            try: await asyncio.wait_for(proc.wait(), timeout=1.5)
            except asyncio.TimeoutError: pass
    except Exception as e:
        print(f"[KERNEL LOG] Terminate fault: {e}")
# --- END OF REPLACEMENT BLOCK (Core System Mutex & Process Terminator) ---

# --- START OF REPLACEMENT BLOCK 1 (_deep_probe_stream Sniper V15) ---
async def _deep_probe_stream(url: str) -> tuple[bool, str]:
    """
    هسته اعتبارسنجی سطح کرنل (V15 - S-Tier)
    ادغام موتور Sniper پایتون برای دور زدن ۱۰۰ درصدی فایروال‌های سخت‌گیر (مانند Persiran)
    و استفاده از FFprobe برای مابقی شبکه‌ها.
    """
    import asyncio
    import urllib.request
    import ssl
    
    if not url.startswith("http"):
        return False, "پروتکل نامعتبر است."

    # 🔴 تزریق موتور تک‌تیرانداز (Sniper Engine) اختصاصی برای دور زدن WAF پارساتي‌وي
    if "persiran.online" in url:
        try:
            def _sniper_check():
                headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
                    'Accept': '*/*',
                    'Referer': 'https://www.persiran.com/',
                    'Origin': 'https://www.persiran.com'
                }
                ctx = ssl.create_default_context()
                ctx.check_hostname = False
                ctx.verify_mode = ssl.CERT_NONE
                
                req = urllib.request.Request(url, headers=headers)
                # تایم‌اوت ۵ ثانیه برای شکار سریع
                with urllib.request.urlopen(req, context=ctx, timeout=5.0) as res:
                    data = res.read().decode('utf-8', errors='ignore')
                    if "#EXTM3U" in data:
                        return True, "سیگنال محافظت‌شده پایدار (بای‌پَس با Sniper 🟢)"
                    return False, "تله کپچا یا تغییر ساختار سایت (WAF Trap)"
            
            success, msg = await asyncio.to_thread(_sniper_check)
            return success, msg
        except Exception as e:
            return False, f"مسدود توسط فایروال: {type(e).__name__}"

    # 🟢 مابقی لینک‌ها با موتور FFprobe بررسی می‌شوند
    base_domain = url.split('/')[0] + "//" + url.split('/')[2] + "/" if "://" in url else "https://google.com/"
    user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
    headers_str = f"Referer: {base_domain}\r\nOrigin: {base_domain[:-1]}\r\nAccept: */*\r\n"

    cmd = [
        "ffprobe", 
        "-v", "error", 
        "-user_agent", user_agent,
        "-headers", headers_str,
        "-show_entries", "format=format_name", 
        "-of", "default=noprint_wrappers=1:nokey=1", 
        url
    ]

    try:
        proc = await asyncio.create_subprocess_exec(
            *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=4.0)
        
        if proc.returncode == 0:
            fmt = stdout.decode('utf-8').strip()
            return True, f"سیگنال پایدار و معتبر ({fmt})"
        else:
            err = stderr.decode('utf-8').lower()
            if "name or service not known" in err or "resolve hostname" in err:
                return False, "دامنه منقضی یا حذف شده است (DNS Dead)"
            elif "403" in err or "forbidden" in err:
                return False, "دسترسی مسدود شد (WAF 403)"
            elif "404" in err:
                return False, "سیگنال آفلاین است (404 Not Found)"
            else:
                return False, "سرور مقصد پاسخ معتبر نمی‌دهد."
                
    except asyncio.TimeoutError:
        try: proc.kill()
        except: pass
        return False, "تایم‌اوت شبکه (لینک مرده یا کند است)"
    except Exception as e:
        return False, f"خطای کرنل: {type(e).__name__}"
# --- END OF REPLACEMENT BLOCK 1 ---

# --- START OF REPLACEMENT BLOCK (Cloud Extractor & Auto-Heal Matrix V15) ---
# --- START OF REPLACEMENT BLOCK (Anti-Stutter Cloud Extractor V16) ---
def _extract_direct_url(url: str, channel_name: str = "") -> str:
    """موتور استخراج ابری با معماری Anti-Stutter (ضد لگ و قطعی)"""
    ydl_opts = {
        # 🔴 شاهکار S-Tier: جلوگیری از Muxing زنده (دلیل اصلی قطعی‌های چند ثانیه‌ای).
        # با اجبار به دریافت فرمت‌های 94/93 (Native HLS) که صدا و تصویر از قبل توسط سرور گوگل ادغام شده‌اند،
        # پردازش همزمان حذف شده و استریم بدون یک میلی‌ثانیه قطعی یا بافرینگ در تلگرام پخش می‌شود.
        'format': '94/93/92/91/b[height<=480]/best', 
        'noplaylist': True,
        'quiet': True,
        'no_warnings': True,
        'simulate': True,
        'live_from_start': False, # دریافت استریم دقیقاً از لحظه حال (جلوگیری از بافرینگ حافظه پنهان)
        'extractor_args': {
            'youtube': {
                # استفاده انحصاری از کلاینت موبایل برای دریافت پایدارترین خروجی HLS
                'player_client': ['android', 'ios'],
                'player_skip': ['webpage', 'configs', 'js'] # نهایت سرعت استخراج در صدم ثانیه
            }
        }
    }
    
    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        try:
            info = ydl.extract_info(url, download=False)
            if info:
                # سیستم هوشمند برای پیدا کردن استریم زنده از داخل نتایج سرچ
                if 'entries' in info and info['entries']:
                    for entry in info['entries']:
                        if entry.get('is_live'):
                            return entry.get('url') or entry.get('manifest_url')
                    return info['entries'][0].get('url') or info['entries'][0].get('manifest_url')
                
                raw_link = info.get('url') or info.get('manifest_url')
                if raw_link: return raw_link
        except Exception as e:
            err_str = str(e).lower()
            # عبور نرم از ارورهای متداول استریم‌های پایان‌یافته
            if "not currently live" in err_str or "404" in err_str or "offline" in err_str:
                pass
            else:
                raise Exception(f"انسداد فایروال گوگل: {str(e)}")

        # سیستم بک‌آپ (Fallback) با سرچ هوشمند لایو جایگزین
        if channel_name:
            try:
                fallback_url = f"ytsearch1:{channel_name} live پخش زنده"
                info = ydl.extract_info(fallback_url, download=False)
                if 'entries' in info and info['entries']:
                    for entry in info['entries']:
                        if entry.get('is_live'):
                            return entry.get('url') or entry.get('manifest_url')
                    return info['entries'][0].get('url') or info['entries'][0].get('manifest_url')
            except Exception:
                pass
                
        raise Exception("سیستم بک‌آپ: پخش زنده این شبکه در حال حاضر در کلود وجود ندارد.")
# --- END OF REPLACEMENT BLOCK ---

# --- START OF REPLACEMENT BLOCK 2 (handle_ws_play_tv) ---
async def handle_ws_play_tv(url: str, channel_name: str, chat_id: int):
    await broadcast_ws({"type": "log", "msg": f"🔍 هدایت سیگنال: آغاز اتصال به شبکه {channel_name}...", "level": "info"})
    try:
        is_cloud_stream = "youtube.com" in url or "youtu.be" in url or url.startswith("ytsearch")
        
        if is_cloud_stream:
            await broadcast_ws({"type": "log", "msg": "⚡ موتور Auto-Cloud: جستجوی لایو زنده و استخراج ضدتحریم...", "level": "ff-log"})
            loop = asyncio.get_running_loop()
            raw_url = await loop.run_in_executor(SYSTEM_IO_POOL, _extract_direct_url, url, channel_name)
            if not raw_url:
                raise Exception("استخراج داینامیک ناموفق بود. لایوی یافت نشد.")
        else:
            raw_url = url
            is_valid, probe_log = await _deep_probe_stream(raw_url)
            if not is_valid:
                raise Exception(probe_log)
            
        await broadcast_ws({"type": "log", "msg": "✅ سیگنال پایدار تایید شد. در حال کانفیگ هسته تلگرام...", "level": "info"})

        current_vol = CHAT_VOLUMES.get(chat_id, 100)

        if LIVE_SYSTEM.get("tts_queue"):
            while not LIVE_SYSTEM["tts_queue"].empty():
                try: 
                    LIVE_SYSTEM["tts_queue"].get_nowait()
                    LIVE_SYSTEM["tts_queue"].task_done()
                except: pass
        if "tts_event" in LIVE_SYSTEM:
            LIVE_SYSTEM["tts_event"].set()
        LIVE_SYSTEM.pop("frozen_media_state", None)

        base_domain = raw_url.split('/')[0] + "//" + raw_url.split('/')[2] + "/" if "://" in raw_url else "https://google.com/"
        
        # 🔴 شاهکار تزریق داینامیک هدرها برای دور زدن فایروال سایت‌های محافظت‌شده حین استریم
        if "persiran.online" in raw_url:
            custom_ref = "https://www.persiran.com/"
            custom_orig = "https://www.persiran.com"
        else:
            custom_ref = base_domain
            custom_orig = base_domain[:-1]
            
        media_stream = MediaStream(
            raw_url, 
            audio_parameters=AudioQuality.HIGH, 
            video_parameters=VideoQuality.SD_480p,
            headers={
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
                'Referer': custom_ref,
                'Origin': custom_orig
            }
        )
        
        release_file_usage(chat_id)
        
        is_audio_only_now = LIVE_SYSTEM.get("standby_active", False) or not LIVE_SYSTEM.get("media_is_video", False)
        await resilient_play(chat_id, media_stream, current_vol, force_reconnect=is_audio_only_now)
        
        LIVE_SYSTEM.update({
            "media_playing": True, "media_paused": False, 
            "media_start_time": time.time(), "media_total_pause": 0,
            "media_file_path": raw_url, "media_is_video": True,
            "media_is_radio": True, 
            "media_title": f"📺 LIVE: {channel_name}",
            "standby_active": False
        })
        
        await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": True})
        await broadcast_ws({"type": "log", "msg": f"📡 تلویزیون {channel_name} با تصویر و صدا روی آنتن رفت.", "level": "success"})
        
    except Exception as e:
        await broadcast_ws({"type": "log", "msg": f"🛑 عملیات متوقف شد [{channel_name}]: {str(e)}", "level": "error"})
# --- END OF REPLACEMENT BLOCK 2 ---

# --- START OF REPLACEMENT BLOCK (Resilient Play & Stream Normalizer V9) ---
from pyrogram.errors import FloodWait

# --- START OF REPLACEMENT BLOCK (Anti-Crash Stream Normalizer V10) ---
def build_optimized_stream(file_path: str, is_video: bool) -> MediaStream:
    """
    موتور رندرینگ هوشمند V10 (Anti-Crash & Anti-Freeze)
    حل مشکل عدم پخش: استفاده از اتو-مپینگ FFmpeg به جای فورس-مپینگ
    """
    base_ffmpeg_args = " -hide_banner -loglevel error "

    if is_video:
        # برای ویدیو: کنترل ترافیک شبکه (UDP Drop Guard) بدون دخالت در لاین‌ها
        ff_params = base_ffmpeg_args + " -b:v 800k -maxrate 800k -bufsize 1600k "
        return MediaStream(file_path, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ffmpeg_parameters=ff_params)
    else:
        # برای صدا: استفاده از vn- (Video Null) برای دراپ کردن امنِ کاورآرت بدون کرش
        ff_params = base_ffmpeg_args + " -vn -b:a 128k "
        return MediaStream(file_path, audio_parameters=AudioQuality.HIGH, ffmpeg_parameters=ff_params)
# --- END OF REPLACEMENT BLOCK ---


async def resilient_play(chat_id: int, stream: MediaStream, vol: int = 100, force_reconnect: bool = False):
    """تزریق‌گر اتمیک با قفل‌های امنیتی ضد-فریز (Ghost-EOF Guard)"""
    
    # 🔴 شاهکار معماری V9: قفل Hot-Swap باید قبل از هر اقدامی روشن شود تا 
    # سیگنال‌های مرگ استریم قبلی (Ghost EOF) استریم جدید را در ۳ ثانیه اول خفه نکنند!
    LIVE_SYSTEM["is_hot_swapping"] = True

    try:
        if force_reconnect:
            raise Exception("Force reconnect to upgrade Audio to Video Call.")
            
        # 🔴 استراتژی Soft-Pause: توقف نرم استریم قبلی برای تخلیه بافر FFmpeg در رم
        try:
            if LIVE_SYSTEM.get("media_playing"):
                await call.pause(chat_id)
                await asyncio.sleep(0.3) 
        except: pass

        if hasattr(call, 'change_stream'):
            await call.change_stream(chat_id, stream)
        else:
            await call.play(chat_id, stream)

    except Exception as e_change:
        error_change_str = str(e_change).lower()
        try:
            if "force reconnect" not in error_change_str:
                try: await call.leave_call(chat_id)
                except: pass
                await asyncio.sleep(1.2) # مکث استراتژیک برای تخلیه کش رم تلگرام
            
            await call.play(chat_id, stream)
            
        except FloodWait as fw:
            try: await broadcast_ws({"type": "log", "msg": f"🛑 محدودیت FloodWait: {fw.value} ثانیه.", "level": "error"})
            except: pass
            raise Exception(f"محدودیت امنیتی تلگرام (FloodWait): ربات برای {fw.value} ثانیه قفل شد.")
            
        except Exception as e_play:
            error_str = f"{type(e_play).__name__} {str(e_play)}".lower()
            if "alreadyjoined" in error_str or "not in a call" in error_str or "timeouterror" in error_str:
                try: await call.leave_call(chat_id)
                except: pass
                await asyncio.sleep(1.5)
                try: await call.play(chat_id, stream)
                except Exception as final_e: raise Exception(f"خطای غیرقابل بازگشت کرنل: {type(final_e).__name__}")
            else:
                raise Exception(f"خطای ناشناخته کرنل تلگرام: {type(e_play).__name__}")
                
    finally:
        # تنظیم اتمیک ولوم
        try: await call.change_volume_call(chat_id, vol)
        except: pass
        
        # 🔴 تمدید قفل مصونیت به ۴ ثانیه (زمان کافی برای مرگ کامل پروسه استریم قبلی)
        async def _release_swap_lock():
            await asyncio.sleep(4.0)
            LIVE_SYSTEM["is_hot_swapping"] = False
        asyncio.create_task(_release_swap_lock())
# --- END OF REPLACEMENT BLOCK ---
    
async def broadcast_ws(payload: dict):
    """توزیع بلادرنگ با معماری Non-Blocking Scatter-Gather و تایم‌اوت سخت‌افزاری"""
    if not ACTIVE_WEBSOCKETS: 
        return
        
    payload_str = json.dumps(payload)
    dead_ws = set()

    async def _fire_and_forget(ws):
        try:
            # 🔴 گارد محافظ: جلوگیری از فریز شدن سیستم به دلیل لگ شبکه کلاینت
            await asyncio.wait_for(ws.send_text(payload_str), timeout=1.2)
        except Exception:
            dead_ws.add(ws)

    # شلیک موازی O(1) به تمامی کلاینت‌ها بدون منتظر ماندن برای پاسخ تک‌تک آن‌ها
    await asyncio.gather(*[_fire_and_forget(ws) for ws in ACTIVE_WEBSOCKETS], return_exceptions=True)
    
    # پاکسازی بی‌سروصدای کلاینت‌های مرده (Memory Leak Guard)
    if dead_ws:
        ACTIVE_WEBSOCKETS.difference_update(dead_ws)
# --- END OF REPLACEMENT BLOCK (Zero-Latency Broadcaster) ---




# --- START OF REPLACEMENT BLOCK (handle_ws_play_media Update) ---
async def handle_ws_play_media(query: str, is_video: bool, chat_id: int):
    await broadcast_ws({"type": "log", "msg": f"🔍 در حال استخراج و پردازش مدیا: {query}", "level": "info"})
    try:
        loop = asyncio.get_running_loop()
        file_path = await loop.run_in_executor(SYSTEM_IO_POOL, _download_yt, query, is_video)
        await broadcast_ws({"type": "log", "msg": "🚀 آماده‌سازی و تزریق استریم به تلگرام (Auto-Join)...", "level": "info"})
        
        current_vol = CHAT_VOLUMES.get(chat_id, 100)

        # 🔴 استفاده از موتور نرم‌الایزر اتمیک (Anti-Freeze Guard)
        media_stream = build_optimized_stream(file_path, is_video)

        # 🔴 پاکسازی عمیق استیت هوش مصنوعی (Purge TTS/Frozen State)
        if LIVE_SYSTEM.get("tts_queue"):
            while not LIVE_SYSTEM["tts_queue"].empty():
                try: 
                    LIVE_SYSTEM["tts_queue"].get_nowait()
                    LIVE_SYSTEM["tts_queue"].task_done()
                except: pass
        if "tts_event" in LIVE_SYSTEM:
            LIVE_SYSTEM["tts_event"].set()
        LIVE_SYSTEM.pop("frozen_media_state", None)

        track_file_usage(chat_id, file_path)
        await resilient_play(chat_id, media_stream, current_vol)
        
        LIVE_SYSTEM.update({
            "media_playing": True, "media_paused": False, 
            "media_start_time": time.time(), "media_total_pause": 0,
            "media_file_path": file_path, "media_is_video": is_video,
            "media_is_radio": False,
            "media_title": query[:40] + "..." if len(query) > 40 else query
        })
        
        await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
        await broadcast_ws({"type": "log", "msg": "🎧 استریم ابری با موفقیت سینک و آغاز شد.", "level": "success"})
    except Exception as e:
        await broadcast_ws({"type": "log", "msg": f"خطا در تونل پخش ابری: {type(e).__name__} - {str(e)}", "level": "error"})
# --- END OF REPLACEMENT BLOCK ---

async def handle_ws_play_radio(url: str, station_name: str, chat_id: int):
    await broadcast_ws({"type": "log", "msg": f"📻 اعتبارسنجی گره ارتباطی: {station_name}", "level": "info"})
    try:
        # 🔴 Pre-flight Security Check
        if not await asyncio.to_thread(_ping_stream, url):
            raise Exception("سرور مبدأ پاسخ نمی‌دهد یا IP سرور شما را مسدود (Geo-Block) کرده است.")
            
        current_vol = CHAT_VOLUMES.get(chat_id, 100)
        # این بخش را در handle_ws_play_radio جایگزین کنید
        media_stream = MediaStream(
            url, 
            audio_parameters=AudioQuality.HIGH,
            headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'}
        )

        # 🔴 پاکسازی عمیق استیت هوش مصنوعی (Purge TTS/Frozen State)
        if LIVE_SYSTEM.get("tts_queue"):
            while not LIVE_SYSTEM["tts_queue"].empty():
                try: 
                    LIVE_SYSTEM["tts_queue"].get_nowait()
                    LIVE_SYSTEM["tts_queue"].task_done()
                except: pass
        if "tts_event" in LIVE_SYSTEM:
            LIVE_SYSTEM["tts_event"].set()
        LIVE_SYSTEM.pop("frozen_media_state", None)

        release_file_usage(chat_id)
        await resilient_play(chat_id, media_stream, current_vol)
        
        LIVE_SYSTEM.update({
            "media_playing": True, "media_paused": False, 
            "media_start_time": time.time(), "media_total_pause": 0,
            "media_file_path": url, "media_is_video": False,
            "media_is_radio": True,
            "media_title": f"🔴 LIVE: {station_name}"
        })
        
        await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": True})
        await broadcast_ws({"type": "log", "msg": "📡 استریم بدون تاخیر (Zero-Latency) متصل شد.", "level": "success"})
    except Exception as e:
        await broadcast_ws({"type": "log", "msg": f"⚠️ توقف اتصال: {str(e)}", "level": "error"})


# --- START OF REPLACEMENT BLOCK (State Machine Media Controller) ---
async def handle_ws_media_ctrl(action: str, chat_id: int):
    # 🔴 استفاده از قفل اتمیک (STATE_LOCK) برای تضمین یکپارچگی State ماشین
    async with STATE_LOCK:
        try:
            # 🔴 گارد محافظ معماری: کنترل مدیا (مگر دکمه توقف) در زمان صحبت هوش مصنوعی قفل می‌شود
            ai_is_talking = "frozen_media_state" in LIVE_SYSTEM or (LIVE_SYSTEM.get("tts_queue") and not LIVE_SYSTEM["tts_queue"].empty())
            
            if ai_is_talking and action != "stop":
                await broadcast_ws({"type": "log", "msg": "⚠️ کنترل‌ها قفل است: هوش مصنوعی در حال صحبت می‌باشد.", "level": "warn"})
                return

            if action == "pause":
                if LIVE_SYSTEM.get("media_paused"): return
                try:
                    await call.pause(chat_id)
                except Exception:
                    pass # 🔴 جلوگیری از کرش NotInCallError
                LIVE_SYSTEM.update({"media_paused": True, "media_pause_time": time.time()})
                await broadcast_ws({"type": "media_status", "status": "paused", "title": LIVE_SYSTEM.get("media_title", ""), "is_radio": LIVE_SYSTEM.get("media_is_radio", False)})
                await broadcast_ws({"type": "log", "msg": "⏸ استریم موقتاً متوقف شد.", "level": "info"})
                
            elif action == "resume":
                if not LIVE_SYSTEM.get("media_paused"): return
                try:
                    await call.resume(chat_id)
                except Exception:
                    pass
                LIVE_SYSTEM["media_paused"] = False
                if LIVE_SYSTEM.get("media_pause_time"):
                    LIVE_SYSTEM["media_total_pause"] = LIVE_SYSTEM.get("media_total_pause", 0) + (time.time() - LIVE_SYSTEM["media_pause_time"])
                    LIVE_SYSTEM["media_pause_time"] = None
                await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM.get("media_title", ""), "is_radio": LIVE_SYSTEM.get("media_is_radio", False)})
                await broadcast_ws({"type": "log", "msg": "▶️ استریم ادامه یافت.", "level": "info"})
                
            elif action == "stop":
                release_file_usage(chat_id)
                
                # 🔴 پاکسازی ضربتی صف هوش مصنوعی در زمان فشرده شدن دکمه Stop
                if LIVE_SYSTEM.get("tts_queue"):
                    while not LIVE_SYSTEM["tts_queue"].empty():
                        try: 
                            LIVE_SYSTEM["tts_queue"].get_nowait()
                            LIVE_SYSTEM["tts_queue"].task_done()
                        except: pass
                if "tts_event" in LIVE_SYSTEM:
                    LIVE_SYSTEM["tts_event"].set()
                LIVE_SYSTEM.pop("frozen_media_state", None)

                try:
                    standby_stream = MediaStream("/tmp/standby.mp3", audio_parameters=AudioQuality.HIGH)
                    await call.change_stream(chat_id, standby_stream)
                except Exception:
                    pass # 🔴 خروج امن در صورت عدم حضور در ویس‌چت
                
                LIVE_SYSTEM.update({
                    "media_playing": False, "media_paused": False, 
                    "media_file_path": None, "media_is_radio": False,
                    "media_is_video": False, "standby_active": True
                })
                await broadcast_ws({"type": "media_status", "status": "idle", "title": "", "is_radio": False})
                await broadcast_ws({"type": "log", "msg": "⏹ پخش متوقف شد و سیستم در حالت استندبای قرار گرفت.", "level": "info"})
                
            elif action in ["skip_fwd", "skip_bwd"]:
                if not LIVE_SYSTEM.get("media_playing") or not LIVE_SYSTEM.get("media_file_path"): return
                if LIVE_SYSTEM.get("media_is_radio"):
                    await broadcast_ws({"type": "log", "msg": "⚠️ امکان جابجایی زمان (Seek) در استریم‌های زنده رادیویی وجود ندارد.", "level": "error"})
                    return
                
                pause_time = LIVE_SYSTEM.get("media_total_pause", 0)
                if LIVE_SYSTEM.get("media_paused") and LIVE_SYSTEM.get("media_pause_time"):
                    pause_time += (time.time() - LIVE_SYSTEM["media_pause_time"])
                    
                elapsed = time.time() - LIVE_SYSTEM.get("media_start_time", time.time()) - pause_time
                offset = 15 if action == "skip_fwd" else -15
                new_pos = max(0, int(elapsed + offset))
                
                await broadcast_ws({"type": "log", "msg": f"⏳ Fast-Seeking به ثانیه {new_pos}...", "level": "info"})
                orig_file = LIVE_SYSTEM["media_file_path"]
                ext = orig_file.split('.')[-1]
                seek_file = f"/tmp/seek_{int(time.time() * 1000)}.{ext}"
                
                proc = await asyncio.create_subprocess_exec(
                    "ffmpeg", "-y", "-ss", str(new_pos), "-i", orig_file, "-c", "copy", seek_file,
                    stdout=asyncio.subprocess.DEVNULL, 
                    stderr=asyncio.subprocess.DEVNULL
                )
                await proc.wait()
                
                if not os.path.exists(seek_file) or os.path.getsize(seek_file) < 1024:
                    raise Exception("رسیدن به انتهای فایل یا عدم وجود Keyframe.")
                
                is_video = LIVE_SYSTEM.get("media_is_video", False)
                current_vol = CHAT_VOLUMES.get(chat_id, 100)
                media_stream = MediaStream(seek_file, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p) if is_video else MediaStream(seek_file, audio_parameters=AudioQuality.HIGH)
                
                track_file_usage(chat_id, seek_file)
                await resilient_play(chat_id, media_stream, current_vol)
                
                LIVE_SYSTEM.update({"media_start_time": time.time() - new_pos, "media_total_pause": 0, "media_paused": False, "media_pause_time": None})
                await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM.get("media_title", ""), "is_radio": False})
                await broadcast_ws({"type": "log", "msg": "✅ موقعیت استریم با موفقیت سینک شد.", "level": "success"})
        except Exception as e:
            await broadcast_ws({"type": "log", "msg": f"خطای کنترلر مدیا: {type(e).__name__} - {str(e)}", "level": "error"})
# --- END OF REPLACEMENT BLOCK (State Machine Media Controller) ---


class NeuralWelcomeMatrix:
    def __init__(self):
        self.history = {}  
        self.active_participants = set()
        self.cooldown_seconds = 86400  
        self.boot_time = time.time()  
        
        self.templates_with_name = [
            "خوش اومدی {name} عزیز",
            "{name} جان، به جمع ما خوش اومدی، صفا آوردی.",
            "{name} جان خیلی خوش اومدی، امیدوارم لحظات خوبی رو کنارمون داشته باشی."
        ]
        self.templates_anonymous = [
            "سلام دوست عزیز، به جمع ما خیلی خوش اومدی.",
            "حضور شما باعث افتخاره، خوش اومدی دوست من.",
            "سلام، به این ویس‌چت خیلی خوش اومدی، صفا آوردی."
        ]

        self.en_to_fa_map = {
            'a': 'ا', 'b': 'ب', 'c': 'ک', 'd': 'د', 'e': 'ا', 'f': 'ف',
            'g': 'گ', 'h': 'ح', 'i': 'ی', 'j': 'ج', 'k': 'ک', 'l': 'ل',
            'm': 'م', 'n': 'ن', 'o': 'و', 'p': 'پ', 'q': 'ق', 'r': 'ر',
            's': 'س', 't': 'ت', 'u': 'و', 'v': 'و', 'w': 'و', 'x': 'کس',
            'y': 'ی', 'z': 'ز',
            'ch': 'چ', 'sh': 'ش', 'kh': 'خ', 'zh': 'ژ', 'gh': 'ق', 'ph': 'ف'
        }

    def reset_cache(self):
        """پاکسازی کامل مخزن در هر بار ریستارت یا استارت سرور برای جلوگیری از تداخل آیدی‌ها"""
        self.history.clear()
        self.active_participants.clear()
        self.boot_time = time.time()
        print("[WELCOME MATRIX] Repository cache successfully flushed on boot.")

    def _clean_and_translate_name(self, raw_name: str) -> str:
        if not raw_name:
            return ""
        
        cleaned = ''.join(c for c in raw_name if not unicodedata.category(c).startswith('S') and not unicodedata.category(c).startswith('P')).strip()
        if not cleaned:
            return ""

        is_persian = any('\u0600' <= c <= '\u06FF' for c in cleaned)
        if is_persian:
            return cleaned.split()[0]

        cleaned = cleaned.lower().split()[0]
        persian_name = ""
        skip_next = False
        
        for i in range(len(cleaned)):
            if skip_next:
                skip_next = False
                continue
                
            if i < len(cleaned) - 1:
                digraph = cleaned[i:i+2]
                if digraph in self.en_to_fa_map:
                    persian_name += self.en_to_fa_map[digraph]
                    skip_next = True
                    continue
                
            char = cleaned[i]
            if char in self.en_to_fa_map:
                if not persian_name or persian_name[-1] != self.en_to_fa_map[char]:
                    persian_name += self.en_to_fa_map[char]
                
        return persian_name if len(persian_name) > 1 else ""

    async def generate_welcome(self, user_id: int, raw_name: str):
        now = time.time()
        
        # گارد ضد اسپم در زمان روشن شدن ربات (15 ثانیه گریس تایم)
        if now - self.boot_time < 15:
            self.history[user_id] = now
            return None

        if user_id in self.history and (now - self.history[user_id]) < self.cooldown_seconds:
            return None  
            
        self.history[user_id] = now
        
        persian_name = self._clean_and_translate_name(raw_name)
        if persian_name:
            text = random.choice(self.templates_with_name).format(name=persian_name)
        else:
            text = random.choice(self.templates_anonymous)
            
        return text

welcome_matrix = NeuralWelcomeMatrix()
welcome_matrix.reset_cache() # پاکسازی خودکار در لحظه استارت سرور
LIVE_SYSTEM["welcome_enabled"] = False
# --- END OF REPLACEMENT BLOCK ---

app_web = FastAPI()
# --- START OF REPLACEMENT BLOCK (Web Security Firewall Middleware) ---
app_web = FastAPI(docs_url=None, redoc_url=None, openapi_url=None) # 🔴 غیرفعال کردن داکیومنت‌های API برای جلوگیری از اسکن هکرها

# مسدود کردن درخواست‌های Cross-Origin
app_web.add_middleware(
    CORSMiddleware,
    allow_origins=["*"], # در صورت داشتن دامنه اختصاصی، فقط نام دامنه خود را بنویسید
    allow_methods=["GET"],
    allow_headers=["*"],
)

@app_web.middleware("http")
async def security_headers_middleware(request, call_next):
    """دیوار آتشین HTTP: مخفی‌سازی خطاها و تزریق هدرهای CSP"""
    try:
        response = await call_next(request)
    except Exception as e:
        # 🔴 خاموش کردن خطا در محیط Production (پنهان کردن Traceback از مرورگر)
        # لاگ فقط در کنسول سرور چاپ می‌شود و کاربر فقط ارور 500 می‌بیند
        print(f"[SECURITY GUARD] Blocked Server Error Leak: {e}")
        return JSONResponse(status_code=500, content={"status": "error", "message": "Internal Server Error"})

    # 🔴 پیاده‌سازی سخت‌گیرانه Content Security Policy (CSP) برای جلوگیری از حملات XSS
    # فقط به Tailwind و فونت‌های گوگل اجازه لود شدن می‌دهد.
    csp = (
        "default-src 'self'; "
        "script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; "
        "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; "
        "font-src 'self' https://fonts.gstatic.com; "
        "connect-src 'self' ws: wss:; "
        "img-src 'self' data:;"
    )
    
    response.headers["Content-Security-Policy"] = csp
    response.headers["X-Content-Type-Options"] = "nosniff" # جلوگیری از حملات MIME-Sniffing
    response.headers["X-Frame-Options"] = "DENY" # جلوگیری از حملات Clickjacking
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Server"] = "HUBEMA-Tactical-OS" # 🔴 مخفی کردن نام واقعی وب‌سرور (Uvicorn/FastAPI)
    
    return response
# --- END OF REPLACEMENT BLOCK ---
# --- CONFIGURATION ---
API_ID = 938729
API_HASH = "1783381e0c97a4100053f671a5a06f62"
AUTH_USERS = [212289182, 815938892, 1304288104]
BASE_DIR = Path("/var/www/html/GAP#")
DOWNLOAD_DIR = BASE_DIR / "downloads"

PANEL_USERNAME = "admin"
PANEL_PASSWORD = "SystemOverride_2026!"

CHAT_VOLUMES = {} 

DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)

app = Client("my_account", api_id=API_ID, api_hash=API_HASH, workdir=str(BASE_DIR))
call = PyTgCalls(app)

# --- UTILITY FUNCTIONS ---
def normalize_farsi(text: str) -> str:
    if not text:
        return ""
    return text.replace("ي", "ی").replace("ك", "ک").replace("\u200c", " ").strip()

# --- START OF REPLACEMENT BLOCK (Quantum Auto-Heal Matrix Downloader V25 - S-TIER) ---
def _download_yt(query: str, is_video: bool = False) -> str:
    """
    هسته استخراج مدیا - سطح GOD MODE (The Ultimate Global & Persian Matrix V25)
    بروزرسانی: حذف گره‌های سوخته بر اساس تست ترمینال و شیفت هوشمند ترافیک به
    موتور بی‌نظیر و رایگان SoundCloud و بای‌پَس Native یوتیوب.
    """
    import urllib.parse
    import urllib.request
    import json
    import re
    import shutil
    import ssl
    import os
    import time

    base_opts = {
        'outtmpl': str(DOWNLOAD_DIR / '%(id)s.%(ext)s'),
        'noplaylist': True,
        'quiet': True,
        'no_warnings': True,
        'nocheckcertificate': True,
        'socket_timeout': 15,
        'http_headers': {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
            'Accept-Language': 'en-US,en;q=0.9,fa;q=0.8',
        }
    }

    is_url = query.startswith("http")
    vid_id = None
    diagnostics_log = []
    success_file = None

    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    
    clean_query = re.sub(r'[^\w\s\u0600-\u06FF\u0698\u067E\u0686\u06AF\-]', ' ', query).strip() if not is_url else query

    def log_diag(node, msg, status="info"):
        """موتور دیباگر عمیق و هوشمند"""
        icons = {"info": "⏳", "success": "✅", "error": "❌", "warn": "⚠️", "hack": "⚡"}
        diagnostics_log.append(f"[{node}] {icons.get(status, '▪')} {msg}")

    # =====================================================================
    # 🔴 فاز ۱: ماتریس اختصاصی ایران (ویدیو -> آپارات | صوت -> رادیوجوان و APIهای ایرانی)
    # =====================================================================
    if not is_url:
        is_persian_query = any('\u0600' <= c <= '\u06FF' for c in clean_query)
        
        # --- 🎬 جستجوی ویدیویی در آپارات ---
        if is_video and is_persian_query:
            log_diag("Aparat-Engine", "در حال رهگیری ویدیو در سرورهای آپارات...", "info")
            try:
                aparat_search = f"https://www.aparat.com/search/{urllib.parse.quote(clean_query)}"
                req = urllib.request.Request(aparat_search, headers={'User-Agent': base_opts['http_headers']['User-Agent']})
                with urllib.request.urlopen(req, timeout=8, context=ctx) as res:
                    html = res.read().decode('utf-8', errors='ignore')
                    aparat_ids = re.findall(r'href="/v/([^/"]+)"', html)
                    
                    if aparat_ids:
                        target_aparat = f"https://www.aparat.com/v/{aparat_ids[0]}"
                        log_diag("Aparat-Engine", f"تارگت آپارات قفل شد: {aparat_ids[0][:10]}...", "hack")
                        aprt_opts = base_opts.copy()
                        aprt_opts['format'] = 'bestvideo[height<=480]+bestaudio/best'
                        with yt_dlp.YoutubeDL(aprt_opts) as ydl:
                            info = ydl.extract_info(target_aparat, download=True)
                            fp = ydl.prepare_filename(info)
                            if os.path.exists(fp):
                                log_diag("Aparat-Engine", "مکش ویدیو از آپارات موفق بود.", "success")
                                return fp
            except Exception as e:
                log_diag("Aparat-Engine", f"خطا: {type(e).__name__}", "warn")

        # --- 🎵 جستجوی صوتی در رادیوجوان و API های داخلی ---
        if not is_video:
            log_diag("RadioJavan", "بررسی دیتابیس رادیو جوان...", "info")
            try:
                rj_search = f"https://www.radiojavan.com/search?q={urllib.parse.quote(clean_query)}"
                req = urllib.request.Request(rj_search, headers={'User-Agent': 'Mozilla/5.0'})
                with urllib.request.urlopen(req, timeout=5, context=ctx) as res:
                    html = res.read().decode('utf-8', errors='ignore')
                    rj_links = re.findall(r'href="/mp3s/mp3/([^"]+)"', html)
                    if rj_links:
                        rj_target = f"https://www.radiojavan.com/mp3s/mp3/{rj_links[0]}"
                        log_diag("RadioJavan", "تارگت شناسایی شد، در حال دانلود...", "hack")
                        rj_opts = base_opts.copy()
                        rj_opts['format'] = 'bestaudio/best'
                        with yt_dlp.YoutubeDL(rj_opts) as ydl:
                            info = ydl.extract_info(rj_target, download=True)
                            fp = ydl.prepare_filename(info)
                            if os.path.exists(fp):
                                log_diag("RadioJavan", "دانلود مستقیم از RJ موفق بود.", "success")
                                return fp
            except Exception as e:
                log_diag("RadioJavan", f"ردیابی ناموفق: {type(e).__name__}", "warn")

            log_diag("Persian-API", "اسکن API های موسیقی داخلی (Ahangify/Nex1)...", "info")
            api_endpoints = [
                f"https://api.majid-api.ir/music/ahangify?action=search&s={urllib.parse.quote(clean_query)}",
                f"https://api.ir/music/melodify?action=search&q={urllib.parse.quote(clean_query)}"
            ]
            for endpoint in api_endpoints:
                try:
                    req = urllib.request.Request(endpoint, headers=base_opts['http_headers'])
                    with urllib.request.urlopen(req, timeout=4, context=ctx) as res:
                        data = json.loads(res.read().decode('utf-8'))
                        mp3_links = re.findall(r'https?://[^\s"\'\[\]]+\.mp3', json.dumps(data))
                        if mp3_links:
                            log_diag("Persian-API", "لینک مستقیم استخراج شد.", "hack")
                            out_path = str(DOWNLOAD_DIR / f"api_fa_{int(time.time())}.mp3")
                            dl_req = urllib.request.Request(mp3_links[0], headers=base_opts['http_headers'])
                            with urllib.request.urlopen(dl_req, timeout=60, context=ctx) as dl_res:
                                with open(out_path, 'wb') as f: shutil.copyfileobj(dl_res, f)
                            if os.path.exists(out_path) and os.path.getsize(out_path) > 100 * 1024:
                                log_diag("Persian-API", "فایل با موفقیت مکش شد.", "success")
                                return out_path
                except Exception:
                    pass

    # =====================================================================
    # 🔴 فاز ۲: سیستم قدرتمند و رایگان SoundCloud (بای‌پَس تحریم یوتیوب)
    # =====================================================================
    if not is_url and not is_video and not success_file:
        log_diag("SoundCloud", "شکار از طریق دیتابیس عظیم SoundCloud (Native)...", "info")
        try:
            sc_opts = base_opts.copy()
            sc_opts['format'] = 'bestaudio/best'
            with yt_dlp.YoutubeDL(sc_opts) as ydl:
                # استفاده از موتور جستجوی ساندکلاد داخل خود yt-dlp به صورت رایگان
                info = ydl.extract_info(f"scsearch1:{clean_query}", download=True)
                if info and 'entries' in info and info['entries']:
                    fp = ydl.prepare_filename(info['entries'][0])
                    if os.path.exists(fp) and os.path.getsize(fp) > 50 * 1024:
                        log_diag("SoundCloud", "مکش صوت با سرعت نور از SoundCloud انجام شد.", "success")
                        success_file = fp
        except Exception as e:
            log_diag("SoundCloud", f"خطا در ساندکلاد: {type(e).__name__} - شیفت به یوتیوب...", "warn")

    if success_file:
        return success_file

    # =====================================================================
    # 🔴 فاز ۲.۵: موتور استخراج جهانی (Universal Global Matrix)
    # پشتیبانی قطعی از: Nex1Music, Tarafdari, VK, TikTok, Streamable و +۱۰۰۰ گره تایید شده
    # =====================================================================
    if is_url and not success_file:
        # فیلتر کردن لینک‌های یوتیوب (چون یوتیوب موتور ضد-فایروال فوق‌سنگین خودش را در فاز 3 دارد)
        is_yt_link = any(x in query.lower() for x in ["youtube.com", "youtu.be"])
        
        if not is_yt_link:
            # استخراج نام دامنه به صورت اتمیک برای لاگ‌های UI هکری
            try: 
                domain_name = urllib.parse.urlparse(query).netloc.replace("www.", "")
            except: 
                domain_name = "Global-Node"
                
            # برجسته‌سازی گره‌های تایید شده در اسکنر شما
            verified_nodes = ["nex1music", "tarafdari", "vk", "tiktok", "archive", "facebook", "streamable", "soundcloud", "mixcloud", "bandcamp", "tunein", "youku", "peertube"]
            node_tag = domain_name.split('.')[0].upper() if any(v in domain_name.lower() for v in verified_nodes) else domain_name.upper()
            
            log_diag(node_tag, f"رهگیری لینک مستقیم... کانکت شدن به دیتاسنتر {domain_name}", "info")
            try:
                global_opts = base_opts.copy()
                global_opts.update({
                    # تنظیمات استراتژیک برای حفظ بهترین کیفیت صدا و تصویر
                    'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best' if is_video else 'bestaudio/best',
                    'geo_bypass': True,
                    'nocheckcertificate': True,
                    # 🔴 شاهکار معماری Anti-Block: استفاده از Impersonate برای جعل هویت مرورگر 
                    # (باعث می‌شود سایت‌هایی مثل Nex1Music ربات را ربات تشخیص ندهند و مسدود نکنند)
                    'extractor_args': {'generic': {'impersonate': 'chrome'}} 
                })
                
                with yt_dlp.YoutubeDL(global_opts) as ydl:
                    info = ydl.extract_info(query, download=True)
                    if info:
                        candidate_file = ydl.prepare_filename(info)
                        # گارد سلامت فایل: بررسی اینکه دیتاسنتر فایل 0 بایتی (فیک) نداده باشد
                        if os.path.exists(candidate_file) and os.path.getsize(candidate_file) > 10 * 1024: 
                            log_diag(node_tag, f"مکش دیتا از {domain_name} با موفقیت انجام شد.", "success")
                            success_file = candidate_file
            except Exception as e:
                log_diag(node_tag, f"انسداد توسط فایروال سایت: {type(e).__name__}", "warn")
                
        if success_file:
            return success_file

    # =====================================================================
    # 🔴 فاز ۳: استخراج شناسه یوتیوب و دانلود با Native yt-dlp (Embedded Bypass)
    # =====================================================================
    # 🔴 فاز ۳: استخراج شناسه یوتیوب و دانلود با Native yt-dlp (Embedded Bypass)
    # =====================================================================
    if is_url:
        v_match = re.search(r'(?:v=|youtu\.be\/|shorts\/|live\/)([\w-]+)', query)
        if v_match: vid_id = v_match.group(1)
        target_yt_url = query if not vid_id else f"https://www.youtube.com/watch?v={vid_id}"
    else:
        if len(clean_query) < 2: clean_query = "Trending Media"
        log_diag("YT-Search", "استخراج شناسه یوتیوب از شبکه...", "info")
        try:
            search_url = f"https://www.youtube.com/results?search_query={urllib.parse.quote(clean_query)}"
            req = urllib.request.Request(search_url, headers=base_opts['http_headers'])
            with urllib.request.urlopen(req, timeout=8, context=ctx) as res:
                html = res.read().decode('utf-8', errors='ignore')
                found_ids = re.findall(r'"videoId":"([a-zA-Z0-9_-]{11})"', html)
                if not found_ids: found_ids = re.findall(r'/watch\?v=([a-zA-Z0-9_-]{11})', html)
                if found_ids:
                    for candidate in found_ids:
                        if len(candidate) == 11 and candidate != "UFk4_Ybx7yk":
                            vid_id = candidate; break
                    if not vid_id: vid_id = found_ids[0]
        except Exception as e:
            log_diag("YT-Search", f"خطای جستجو: {type(e).__name__}", "error")

        if not vid_id:
            debug_output = "\n".join(f" ├ {log}" for log in diagnostics_log)
            raise Exception(f"موتور جستجو موفق به یافتن فایل نشد.\n\n📋 **گزارش دیباگر:**\n{debug_output}")
        target_yt_url = f"https://www.youtube.com/watch?v={vid_id}"

    # اجرای پروتکل Anti-Bot سطح 7 روی یوتیوب
    try:
        log_diag("Core-DLP", "اجرای پروتکل ضد-فایروال Native YT (Embedded Client Spoofing)...", "info")
        dlp_opts = base_opts.copy()
        
        dlp_opts.update({
            'format': 'best[height<=480][ext=mp4]/bestvideo[height<=480][ext=mp4]+bestaudio[ext=m4a]/best' if is_video else 'bestaudio[ext=m4a]/bestaudio/best',
            'source_address': '0.0.0.0', 
            'geo_bypass': True,
            'nocheckcertificate': True,
            
            # 🔴 شاهکار معماری V7: استفاده قطعی از کلاینت‌های ضد-لاگین
            'extractor_args': {
                'youtube': {
                    'client': ['web_embedded', 'android', 'ios'], 
                    'player_client': ['web_embedded', 'android', 'ios'],
                    'player_skip': ['webpage', 'configs', 'js'] 
                }
            }
        })
        
        with yt_dlp.YoutubeDL(dlp_opts) as ydl:
            info = ydl.extract_info(target_yt_url, download=True)
            candidate_file = ydl.prepare_filename(info)
            if os.path.exists(candidate_file) and os.path.getsize(candidate_file) > 50 * 1024:
                log_diag("Core-DLP", "سد فایروال یوتیوب با موفقیت شکسته شد.", "success")
                success_file = candidate_file
    except Exception as e:
        err_text = str(e).lower()
        err_reason = "Bot Check (Sign-in Required)" if "sign in" in err_text or "bot" in err_text else ("IP Blocked (403)" if "403" in err_text else type(e).__name__)
        log_diag("Core-DLP", f"مسدود توسط فایروال گوگل: {err_reason}", "error")

    if success_file:
        return success_file

    # =====================================================================
    # 🔴 خروجی نهایی دیباگر (در صورت شکست تمام لایه‌ها)
    # =====================================================================
    debug_output = "\n".join(f" ├ {log}" for log in diagnostics_log)
    final_exception = (
        f"🛑 **[ SYSTEM OVERRIDE FAILED ]**\n"
        f"تمامی منابع استخراج (SoundCloud/Aparat/YouTube) توسط دیتاسنتر محدود شده‌اند.\n\n"
        f"📋 **گزارش دقیق سیستم (Deep Debug):**\n"
        f"{debug_output}\n\n"
        f"💡 **تکنیک میانبر (Bypass):**\n"
        f"فایل آهنگ یا ویدیو را در گروه فوروارد کنید و روی آن کلمه **پخش** را ریپلای کنید."
    )
    raise Exception(final_exception)
# --- END OF REPLACEMENT BLOCK ---

async def safe_edit_text(message: Message, text: str, retries: int = 3):
    for attempt in range(retries):
        try:
            await message.edit_text(text)
            return
        except Exception as e:
            if "database is locked" in str(e).lower() and attempt < retries - 1:
                await asyncio.sleep(0.7)
            else:
                pass 

async def auto_delete_message(msg: Message, delay: int = 5):
    await asyncio.sleep(delay)
    try:
        await msg.delete()
    except Exception:
        pass

async def send_traceback_to_me(message_text: str):
    try:
        print(f"\n[DEBUG LOGGER] {message_text[:200]}...")
        await app.send_message("me", message_text[-4000:])
    except Exception as e:
        print(f"Cannot send to Telegram: {e}")

active_streams_map = {} 
file_reference_count = {} 

def track_file_usage(chat_id: int, file_path: str):
    release_file_usage(chat_id)
    active_streams_map[chat_id] = str(file_path)
    file_reference_count[str(file_path)] = file_reference_count.get(str(file_path), 0) + 1

def release_file_usage(chat_id: int):
    file_path = active_streams_map.pop(chat_id, None)
    if file_path:
        if file_reference_count.get(file_path, 0) > 0:
            file_reference_count[file_path] -= 1
        

# --- START OF REPLACEMENT BLOCK (Smart Garbage Collector) ---
async def garbage_collector():
    """زباله‌روب اتمیک با اسکن عمیق و محافظت قطعی از RAM و هارد سرور"""
    while True:
        try:
            now = time.time()
            # 1. پاکسازی کش دانلودهای بیکار
            for file_path in DOWNLOAD_DIR.glob("*"):
                if file_path.is_file():
                    path_str = str(file_path)
                    if path_str not in file_reference_count or file_reference_count.get(path_str, 0) <= 0:
                        file_age = now - file_path.stat().st_ctime
                        if file_age > 3600: 
                            try: file_path.unlink(missing_ok=True)
                            except: pass
                            
            # 2. 🔴 پاکسازی حیاتی لوله‌های نامدار (Named Pipes) و فایل‌های موقت صوتی
            for temp_file in Path("/tmp").glob("*"):
                filename = temp_file.name
                if filename.startswith(("tts_", "resume_", "seek_", "hacker_live_")):
                    # محافظت از لوله اصلی استندبای
                    if filename == "standby.mp3": continue 
                    
                    is_pipe = temp_file.is_fifo() if hasattr(temp_file, 'is_fifo') else False
                    age_limit = 120 if is_pipe else 300  # Pipeها باید سریع‌تر از حافظه تخلیه شوند
                    
                    if now - temp_file.stat().st_ctime > age_limit:
                        try: temp_file.unlink(missing_ok=True)
                        except: pass
        except Exception as e:
            pass
        await asyncio.sleep(1800)
# --- END OF REPLACEMENT BLOCK (Smart Garbage Collector) ---
# --- START OF REPLACEMENT BLOCK (Admin Manager Core Engine) ---
async def get_chat_owner_id(client: Client, chat_id: int) -> int:
    """پیدا کردن خودکار مالک اصلی گروه برای ارسال گزارش محرمانه"""
    try:
        async for admin in client.get_chat_members(chat_id, filter=enums.ChatMembersFilter.ADMINISTRATORS):
            if admin.status == enums.ChatMemberStatus.OWNER:
                return admin.user.id
    except: pass
    return None

from pyrogram.types import ChatPrivileges  # 🔴 ایمپورت حیاتی برای معماری V2

async def execute_admin_demotion(client: Client, chat_id: int, admin_id: int, admin_name: str, ban_history: list):
    """هسته مجازات: خلع درجه اتمیک با معماری ضد-کِرَش و هشدار هوشمند به مالک"""
    try:
        action_text = ""
        try:
            # تلاش برای خلع درجه اتمیک
            await client.promote_chat_member(
                chat_id=chat_id,
                user_id=admin_id,
                privileges=ChatPrivileges(
                    is_anonymous=False, can_manage_chat=False, can_delete_messages=False,
                    can_manage_video_chats=False, can_restrict_members=False, can_promote_members=False,
                    can_change_info=False, can_invite_users=False, can_pin_messages=False,
                    can_post_messages=False, can_edit_messages=False
                )
            )
            action_text = f"✅ ادمین **[{admin_name}](tg://user?id={admin_id})** به دلیل عبور از خط قرمزِ سیستم (بیش از {ADMIN_MANAGER['BAN_LIMIT']} بن) با موفقیت **عزل شد**."
        except Exception as api_err:
            # Fallback: اگر ربات سازنده آن ادمین نباشد، تلگرام اجازه عزل نمی‌دهد
            action_text = (f"⚠️ **هشدار امنیتی فوق حاد:** ادمین **[{admin_name}](tg://user?id={admin_id})** از خط قرمز عبور کرد "
                           f"اما ربات دسترسی خلع درجه ایشان را ندارد (احتمالاً توسط مالک اصلی پروموت شده است). لطفاً سریعاً دستی اقدام کنید!\n"
                           f"کد خطا: `{type(api_err).__name__}`")

        owner_id = await get_chat_owner_id(client, chat_id)
        if owner_id:
            history_text = "\n".join([f" ├ 🎯 **[{item[2]}](tg://user?id={item[1]})** `[ID: {item[1]}]`" for item in ban_history])
            report_msg = (
                f"🚨 **[ آژیر قرمز - سیستم مانیتورینگ ادمین‌ها ]**\n"
                f"━━━━━━━━━━━━━━━━━━\n\n"
                f"{action_text}\n\n"
                f"📋 **لیست کاربران اخراج شده توسط این شخص در ۴۸ ساعت گذشته:**\n{history_text}\n\n"
                f"🛡 *هوش مصنوعی Tactical OS*\n"
                f"━━━━━━━━━━━━━━━━━━"
            )
            await client.send_message(owner_id, report_msg, disable_web_page_preview=True)
            
        # پاکسازی کش پس از اجرای عملیات برای جلوگیری از لوپ بی‌نهایت
        async with STATE_LOCK:
            if chat_id in ADMIN_MANAGER.setdefault("ban_records", {}) and admin_id in ADMIN_MANAGER["ban_records"][chat_id]:
                del ADMIN_MANAGER["ban_records"][chat_id][admin_id]
            
    except Exception as e:
        await send_traceback_to_me(f"خطای بحرانی در پروسه عزل ادمین {admin_id}:\n{e}")

async def track_admin_action(client: Client, chat_id: int, admin_user, target_user):
    """ثبت اکشن بن و بررسی رول‌های زمانی (Rolling Time Window)"""
    if chat_id not in ADMIN_MANAGER["active_chats"]: return
        
    admin_id = admin_user.id
    # فیلتر هوشمند: مالک گروه، ربات، یا افراد معاف‌شده بررسی نمی‌شوند
    if admin_id in ADMIN_MANAGER["whitelisted_admins"] or admin_user.is_self: return
        
    now = time.time()
    
    # استفاده از Mutex Lock برای جلوگیری از Race Condition در دیتابیس
    async with STATE_LOCK:
        if chat_id not in ADMIN_MANAGER["ban_records"]:
            ADMIN_MANAGER["ban_records"][chat_id] = {}
        if admin_id not in ADMIN_MANAGER["ban_records"][chat_id]:
            ADMIN_MANAGER["ban_records"][chat_id][admin_id] = []
            
        # پاکسازی خودکار بن‌هایی که از 48 ساعت گذشته‌اند (Garbage Collection محلی)
        time_limit = now - ADMIN_MANAGER["TIME_WINDOW_SEC"]
        valid_records = [rec for rec in ADMIN_MANAGER["ban_records"][chat_id][admin_id] if rec[0] > time_limit]
        
        target_name = target_user.first_name or "کاربر ناشناس"
        valid_records.append((now, target_user.id, target_name))
        
        ADMIN_MANAGER["ban_records"][chat_id][admin_id] = valid_records
        current_bans = len(valid_records)
        
    # در صورت تخطی از لیمیت، تسک مجازات به صورت Non-Blocking شلیک می‌شود
    if current_bans >= ADMIN_MANAGER["BAN_LIMIT"]:
        admin_name = admin_user.first_name or "Unknown"
        asyncio.create_task(execute_admin_demotion(client, chat_id, admin_id, admin_name, valid_records))
# --- END OF REPLACEMENT BLOCK (Admin Manager Core Engine) ---

# --- START OF REPLACEMENT BLOCK (Auth & Security Matrix) ---
async def auth_check(_, __, message: Message):
    try:
        if not message: return False
        uid = message.from_user.id if message.from_user else None
        cid = message.chat.id if message.chat else None
        sid = message.sender_chat.id if message.sender_chat else None

        # 1. دسترسی کامل به خود اکانت (Saved Messages یا ارسال مستقیم)
        if message.from_user and getattr(message.from_user, "is_self", False):
            return True
            
        # 2. دسترسی به ادمین‌های تایید شده در سیستم
        if uid and uid in AUTH_USERS:
            return True
            
        # 3. دسترسی در کانال‌ها/گروه‌هایی که پیام به اسم خود چت ارسال می‌شود
        if sid and cid and sid == cid:
            return True

        return False
    except Exception as e:
        print(f"[AUTH ERROR] {e}")
        return False

is_auth = filters.create(auth_check)
# --- END OF REPLACEMENT BLOCK ---

# --- OS-LEVEL MATRIX CORE (BULLETPROOF INJECTOR & TTS) ---
def get_audio_duration(file_path):
    try:
        out = subprocess.check_output([
            "ffprobe", "-v", "error", "-show_entries",
            "format=duration", "-of",
            "default=noprint_wrappers=1:nokey=1", file_path
        ], timeout=2.0)
        return float(out.strip())
    except Exception:
        return 5.0



# --- START OF REPLACEMENT BLOCK 3 (Queue Methods Fix) ---
async def tts_queue_worker():
    while True:
        try:
            # 🔴 استفاده از get() به جای pop(0) - منتظر می‌ماند تا آیتمی وارد صف شود بدون مصرف CPU
            next_file = await LIVE_SYSTEM["tts_queue"].get()
            
            chat_id = LIVE_SYSTEM.get("chat_id")
            if chat_id and LIVE_SYSTEM.get("is_streaming"):
                LIVE_SYSTEM["standby_active"] = False
                
                # فریز کردن زمان دقیق پخش مدیا *قبل* از شروع TTS
                if "frozen_media_state" not in LIVE_SYSTEM:
                    prev_media = LIVE_SYSTEM.get("media_file_path")
                    is_prev_video = LIVE_SYSTEM.get("media_is_video", False)
                    is_playing = LIVE_SYSTEM.get("media_playing", False)
                    is_paused = LIVE_SYSTEM.get("media_paused", False)
                    
                    pause_time = LIVE_SYSTEM.get("media_total_pause", 0)
                    if is_paused and LIVE_SYSTEM.get("media_pause_time"):
                        pause_time += (time.time() - LIVE_SYSTEM.get("media_pause_time"))
                        
                    start_time = LIVE_SYSTEM.get("media_start_time")
                    elapsed = (time.time() - start_time - pause_time) if start_time else 0
                    
                    LIVE_SYSTEM["frozen_media_state"] = {
                        "file": prev_media,
                        "is_video": is_prev_video,
                        "was_playing": (is_playing and not is_paused),
                        "is_paused": is_paused,
                        "elapsed_at_freeze": max(0, int(elapsed)),
                        "vol": CHAT_VOLUMES.get(chat_id, 100)
                    }

                duration = await asyncio.to_thread(get_audio_duration, next_file)
                tts_stream = MediaStream(next_file, audio_parameters=AudioQuality.HIGH)
                if "tts_event" in LIVE_SYSTEM:
                    LIVE_SYSTEM["tts_event"].clear()
                    
                await resilient_play(chat_id, tts_stream, LIVE_SYSTEM["frozen_media_state"]["vol"])
                
                try:
                    await asyncio.wait_for(LIVE_SYSTEM["tts_event"].wait(), timeout=duration + 1.5)
                except asyncio.TimeoutError:
                    pass
                    
                try: os.remove(next_file)
                except: pass
                
                # 🔴 بازگردانی نقطه-زن مدیا (Smart Revert)
                if LIVE_SYSTEM["tts_queue"].empty() and "frozen_media_state" in LIVE_SYSTEM:
                    frozen = LIVE_SYSTEM.pop("frozen_media_state")
                    if frozen["file"] and frozen["file"] == LIVE_SYSTEM.get("media_file_path"):
                        play_file = frozen["file"]
                        if not LIVE_SYSTEM.get("media_is_radio"):
                            await broadcast_ws({"type": "log", "msg": "🔄 همگام‌سازی زمان... بازگردانی نقطه-زن مدیا.", "level": "info"})
                            ext = frozen["file"].split('.')[-1] if '.' in frozen["file"] else "mp4"
                            seek_file = f"/tmp/resume_{int(time.time() * 1000)}.{ext}"
                            
                            proc = await asyncio.create_subprocess_exec(
                                "ffmpeg", "-y", "-ss", str(frozen["elapsed_at_freeze"]), "-i", frozen["file"], "-c", "copy", seek_file,
                                stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL
                            )
                            await proc.wait()
                            
                            if os.path.exists(seek_file) and os.path.getsize(seek_file) > 1024:
                                play_file = seek_file
                                track_file_usage(chat_id, seek_file)
                                LIVE_SYSTEM["media_start_time"] = time.time() - frozen["elapsed_at_freeze"]
                                LIVE_SYSTEM["media_total_pause"] = 0
                                LIVE_SYSTEM["media_pause_time"] = time.time() if frozen["is_paused"] else None
                            else:
                                await broadcast_ws({"type": "log", "msg": "⚠️ هشدار: برش مدیا شکست خورد، فایل اصلی لود شد.", "level": "error"})
                        
                        if frozen["is_video"]:
                            revert_stream = MediaStream(play_file, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p)
                        else:
                            revert_stream = MediaStream(play_file, audio_parameters=AudioQuality.HIGH)
                            
                        if frozen["is_paused"]:
                            await broadcast_ws({"type": "log", "msg": "⏸ در حال بازگردانی استریم به حالت متوقف (Silent Revert)...", "level": "info"})
                            await resilient_play(chat_id, revert_stream, 0)
                            await asyncio.sleep(0.6)
                            await call.pause(chat_id)
                            try: await call.change_volume_call(chat_id, frozen["vol"])
                            except: pass
                            LIVE_SYSTEM["media_paused"] = True
                            LIVE_SYSTEM["media_playing"] = True
                            LIVE_SYSTEM["media_pause_time"] = time.time()
                            await broadcast_ws({"type": "media_status", "status": "paused", "title": LIVE_SYSTEM.get("media_title", ""), "is_radio": LIVE_SYSTEM.get("media_is_radio", False)})
                        else:
                            await resilient_play(chat_id, revert_stream, frozen["vol"])
            
            # آزادسازی تسک از صف
            LIVE_SYSTEM["tts_queue"].task_done()
        except Exception:
            await asyncio.sleep(0.5)




def _advanced_prosody_injector(text: str) -> str:
    """آماده‌سازی متن برای موتورهای هوشمند چندزبانه مایکروسافت"""
    if not text: return ""
    
    replacements = {
        " است ": "ه ", " می‌روم ": " میرم ", " می‌شود ": " میشه ",
        " هستم ": "م ", " هستی ": "ی ", " خوش آمدی": "خوش اومدی",
        " جان ": "جان، "
    }
    for formal, informal in replacements.items():
        text = text.replace(formal, informal)
        
    # تزریق مکث‌های نرم
    text = re.sub(r'([.!?])\s*', r'\1 ... ', text)
    return text

async def process_tts(text: str, voice: str):
    """هسته پردازشی با استفاده از مدل‌های V-Next مایکروسافت (کاملاً رایگان، نامحدود و طبیعی)"""
    try:
        out_path = f"/tmp/tts_{uuid.uuid4().hex}.mp3"
        humanized_text = _advanced_prosody_injector(text)
        
        active_gender = LIVE_SYSTEM.get("welcome_voice_gender", "male")
        
        # 🔴 شاهکار مخفی: استفاده از مدل‌های V-Next چندزبانه (Multilingual) به جای فرید و دلارا
        # این صداها با هوش مصنوعی احساسی طراحی شده‌اند و فارسی را با نفس‌گیری انسانی می‌خوانند
        if active_gender == "female":
            target_voice = "en-US-AvaMultilingualNeural"  # صدای زنانه بسیار طبیعی و نرم
        else:
            target_voice = "en-US-AndrewMultilingualNeural"  # صدای مردانه جذاب و واقعی

        try:
            # 🔴 استیج 1: استفاده از موتور پیشرفته و طبیعی Multilingual
            communicate = edge_tts.Communicate(humanized_text, target_voice)
            await communicate.save(out_path)
            
            try:
                gender_fa = "آقا" if active_gender == "male" else "خانوم"
                await broadcast_ws({"type": "log", "msg": f"✅ موتور نسل جدید Multilingual (رایگان) با صدای {gender_fa} اجرا شد.", "level": "success"})
            except: pass
            
        except Exception as e:
            print(f"[V-NEXT ERROR] {e}. Falling back to standard Iranian voices.")
            # 🟡 استیج 2: سیستم Fallback به موتورهای استاندارد (فقط در صورتی که سرور لینوکس شما از این مدل‌ها پشتیبانی نکند)
            fallback_voice = "fa-IR-DilaraNeural" if active_gender == "female" else "fa-IR-FaridNeural"
            communicate = edge_tts.Communicate(humanized_text, fallback_voice, rate="+4%")
            await communicate.save(out_path)
            
            try: await broadcast_ws({"type": "log", "msg": "⚠️ موتور V-Next پاسخ نداد. سوییچ به صدای رباتیک پشتیبان.", "level": "error"})
            except: pass

        await LIVE_SYSTEM["tts_queue"].put(out_path) # 🔴 استفاده از متد قدرتمند put
        
    except Exception as e:
        print(f"[NEXT-GEN TTS FATAL ERROR] Neural pipeline crashed: {e}")
        try: await broadcast_ws({"type": "log", "msg": f"❌ خطای موتور صوتی: {e}", "level": "error"})
        except: pass
# --- END OF REPLACEMENT BLOCK ---

# --- START OF REPLACEMENT BLOCK (PyTgCalls Stream End Fix - PROPER ASYNC FILTER) ---

@call.on_update()
async def universal_pytgcalls_handler(client: PyTgCalls, update):
    """هسته مرکزی و ایزوله پردازش رویدادهای صوتی (کاملا مقاوم در برابر Ghost Events و قطعی‌های ناگهانی)"""
    try:
        update_type = type(update).__name__
        chat_id = getattr(update, "chat_id", None)
        
        if not chat_id: 
            return

        status_attr = getattr(update, "status", None)
        status_str = str(status_attr).upper() if status_attr else update_type.upper()

        # ==========================================
        # 1. هندل کردن رویداد پایان استریم (مقاوم شده)
        # ==========================================
        if "ENDED" in status_str and "STREAM" in status_str:
            if LIVE_SYSTEM.get("is_armed") and LIVE_SYSTEM.get("chat_id") == chat_id:
                if LIVE_SYSTEM.get("mode") == "tts":
                    if "tts_event" in LIVE_SYSTEM:
                        LIVE_SYSTEM["tts_event"].set()
                # 🔴 گارد محافظتی: اگر مدیا در حال پخش بود و ما در زمان Hot-Swap (تغییر آهنگ) نیستیم،
                # یعنی آهنگ واقعاً به اتمام رسیده است! پس باید UI را هم آپدیت کنیم.
                elif not LIVE_SYSTEM.get("is_hot_swapping"):
                    if LIVE_SYSTEM.get("media_playing"):
                        LIVE_SYSTEM.update({"media_playing": False, "media_paused": False, "media_file_path": None, "standby_active": True})
                        asyncio.create_task(broadcast_ws({"type": "media_status", "status": "idle", "title": "", "is_radio": False}))
                        
                    try:
                        standby_stream = MediaStream("/tmp/standby.mp3", audio_parameters=AudioQuality.HIGH)
                        await call.change_stream(chat_id, standby_stream)
                    except: pass
            return

        # ==========================================
        # 2. کلاسترینگ رویدادهای قطع ارتباط (گارد محافظ)
        # ==========================================
        is_terminated = any(trigger in status_str for trigger in [
            "KICKED", "CLOSED_VOICE_CHAT", "LEFT_CALL", "LEFT_GROUP_CALL"
        ])

        if is_terminated:
            # 🔴 نجات دهنده اصلی: اگر سیستم در حال ریستارت استریم برای رفع لگ است، این رویداد فیک است!
            if LIVE_SYSTEM.get("is_hot_swapping"):
                return

            LIVE_SYSTEM["is_streaming"] = False
            LIVE_SYSTEM["media_playing"] = False
            release_file_usage(chat_id)
            welcome_matrix.active_participants.clear()

            # 🔴 شاهکار معماری: تخلیه اتمیک صف صوتی و بیدار کردن Worker برای جلوگیری از زامبی شدن پردازش‌ها
            if LIVE_SYSTEM.get("tts_queue"):
                while not LIVE_SYSTEM["tts_queue"].empty():
                    try: 
                        LIVE_SYSTEM["tts_queue"].get_nowait()
                        LIVE_SYSTEM["tts_queue"].task_done()
                    except: pass
            if "tts_event" in LIVE_SYSTEM:
                LIVE_SYSTEM["tts_event"].set()
            LIVE_SYSTEM.pop("frozen_media_state", None)

            msg = "ارتباط به دلیل اخراج یا بن شدن قطع شد!" if "KICKED" in status_str else \
                  "ویس‌چت توسط ادمین گروه بسته شد." if "CLOSED" in status_str else \
                  "ربات از ویس‌چت خارج شد."

            await broadcast_ws({"type": "vc_event", "event": "closed", "chat_id": chat_id, "msg": f"[CRITICAL] {msg}"})

        elif "MUTED" in status_str:
            await broadcast_ws({"type": "vc_event", "event": "muted", "chat_id": chat_id, "msg": "[WARN] میکروفون شما توسط ادمین Mute شد!"})

    except Exception:
        pass

# --- UI / UX ARCHITECTURE ---
HTML_LOCKED = """
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HUBEMA | System Locked</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Fira+Code:wght@600&display=swap" rel="stylesheet">
    <script>
        tailwind.config = { darkMode: 'class', theme: { extend: { fontFamily: { sans: ['Inter', 'sans-serif'], mono: ['Fira Code', 'monospace'] } } } }
    </script>
</head>
<body class="bg-slate-50 dark:bg-[#050505] text-slate-800 dark:text-slate-200 h-screen w-screen overflow-hidden flex flex-col items-center justify-center p-4">
    <div class="relative bg-white dark:bg-[#0a0a0c] border border-slate-200 dark:border-rose-500/30 rounded-3xl p-8 md:p-12 max-w-lg w-full text-center shadow-2xl dark:shadow-rose-500/10 overflow-hidden">
        <div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-rose-500 to-orange-500 shadow-[0_0_20px_rgba(244,63,94,0.6)]"></div>
        <div class="w-20 h-20 mx-auto bg-rose-100 dark:bg-rose-500/10 rounded-full flex items-center justify-center mb-6">
            <svg class="w-10 h-10 text-rose-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path></svg>
        </div>
        <h1 class="text-2xl md:text-3xl font-mono font-bold tracking-widest text-slate-900 dark:text-rose-500 mb-4 uppercase">[ ACCESS DENIED ]</h1>
        <p class="text-sm md:text-base text-slate-500 dark:text-slate-400 leading-relaxed mb-8">
            The Tactical Voice Uplink is currently disarmed and locked.<br class="hidden md:block">
            You must activate the panel via the <span class="font-bold text-slate-700 dark:text-slate-300">Telegram Master Node</span> before initiating a connection.
        </p>
        <div class="inline-block px-6 py-2 rounded-full border border-rose-200 dark:border-rose-500/30 bg-rose-50 dark:bg-rose-500/5 text-rose-600 dark:text-rose-400 text-xs font-mono font-bold tracking-[0.2em] uppercase">
            System Offline
        </div>
    </div>
</body>
</html>
"""

# --- START OF REPLACEMENT BLOCK: FULL HTML_PANEL ---
HTML_PANEL = """
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
    <title>HUBEMA | Tactical OS Matrix</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&family=Fira+Code:wght@400;600&display=swap" rel="stylesheet">
    <script>
        tailwind.config = {
            darkMode: 'class',
            theme: {
                extend: {
                    fontFamily: { sans: ['Inter', 'sans-serif'], mono: ['Fira Code', 'monospace'] },
                    colors: {
                        hubema: { 50: '#f0fdfa', 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 900: '#134e4a' },
                        sys: { dark: '#090a0f', card: '#12141c', light: '#f8fafc', panel: '#1a1d27' }
                    },
                    animation: { 'pulse-fast': 'pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite', 'slide-up': 'slideUp 0.4s ease-out forwards' },
                    keyframes: { slideUp: { '0%': { opacity: 0, transform: 'translateY(20px)' }, '100%': { opacity: 1, transform: 'translateY(0)' } } }
                }
            }
        }
    </script>
    <style>
        body { -webkit-tap-highlight-color: transparent; }
        ::-webkit-scrollbar { width: 4px; height: 4px; }
        ::-webkit-scrollbar-track { background: transparent; }
        ::-webkit-scrollbar-thumb { background: #334155; border-radius: 10px; }
        .glass-panel { background: rgba(18, 20, 28, 0.7); backdrop-filter: blur(20px); border: 1px solid rgba(255,255,255,0.05); }
        .light .glass-panel { background: rgba(255, 255, 255, 0.8); border: 1px solid rgba(0,0,0,0.05); }
        .chat-item { transition: all 0.2s ease; border-left: 2px solid transparent; }
        .chat-item:hover { background: rgba(255,255,255,0.03); }
        .chat-item.active { background: rgba(20, 184, 166, 0.1); border-left-color: #14b8a6; }
        input[type=range]::-webkit-slider-thumb { appearance: none; width: 16px; height: 16px; border-radius: 50%; background: #14b8a6; cursor: pointer; transition: 0.2s; box-shadow: 0 0 10px rgba(20,184,166,0.5); }
        input[type=range]::-webkit-slider-thumb:hover { transform: scale(1.2); }
        
        .radio-scroller { display: flex; overflow-x: auto; gap: 0.75rem; padding-bottom: 0.5rem; scroll-behavior: smooth; }
        .radio-scroller::-webkit-scrollbar { height: 2px; }
        .radio-chip { flex: 0 0 auto; padding: 0.5rem 1rem; border-radius: 999px; font-size: 0.7rem; font-weight: bold; cursor: pointer; transition: all 0.2s; border: 1px solid rgba(255,255,255,0.1); display: flex; align-items: center; gap: 0.5rem; }
        .radio-chip:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
        
        .tv-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 0.75rem; }
        .tv-card { background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 1rem 0.5rem; text-align: center; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem; }
        .tv-card:hover { background: rgba(14, 165, 233, 0.1); border-color: rgba(14, 165, 233, 0.4); transform: translateY(-3px); box-shadow: 0 10px 25px rgba(14, 165, 233, 0.15); }
        .tv-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; background: linear-gradient(135deg, #38bdf8, #0284c7); color: white; box-shadow: 0 4px 10px rgba(2, 132, 199, 0.3); font-weight: 800; }
        .tv-name { font-size: 0.7rem; font-weight: 700; color: #e2e8f0; letter-spacing: 0.05em; }
        .tv-section-title { font-size: 0.65rem; font-weight: 800; color: #64748b; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.5rem; margin-top: 0.5rem; display: flex; align-items: center; gap: 0.35rem; }
    </style>
</head>
<body class="bg-sys-light dark:bg-sys-dark text-slate-800 dark:text-slate-200 h-screen w-full overflow-hidden flex flex-col font-sans transition-colors duration-500">
    <!-- MODAL -->
    <div id="hubemaModal" class="fixed inset-0 bg-black/60 backdrop-blur-md z-[99999] flex items-center justify-center opacity-0 pointer-events-none transition-opacity duration-300">
        <div id="modalBox" class="bg-white dark:bg-sys-card border border-slate-200 dark:border-slate-800 rounded-3xl shadow-2xl p-8 w-[90%] max-w-sm text-center transform scale-95 transition-transform duration-300">
            <div id="modalIcon" class="mx-auto w-16 h-16 mb-4 rounded-full flex items-center justify-center"></div>
            <h3 class="text-xl font-bold mb-2 text-slate-900 dark:text-white" id="modalTitle">Alert</h3>
            <p class="text-sm text-slate-500 dark:text-slate-400 mb-8 leading-relaxed" id="modalMsg">...</p>
            <button onclick="closeModal()" class="w-full py-3.5 rounded-xl font-semibold bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700 text-slate-900 dark:text-white transition-all active:scale-95">ACKNOWLEDGE</button>
        </div>
    </div>
    
    <!-- LOGIN GATE -->
    <div id="loginGate" class="fixed inset-0 z-[1000] flex items-center justify-center bg-sys-light dark:bg-sys-dark transition-opacity duration-700 px-4">
        <div class="glass-panel p-8 rounded-3xl shadow-2xl w-full max-w-md relative overflow-hidden animate-slide-up">
            <div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-hubema-400 to-blue-500"></div>
            <h2 class="text-2xl font-bold mb-8 text-slate-900 dark:text-white tracking-tight flex items-center gap-3">
                <svg class="w-6 h-6 text-hubema-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path></svg>
                Secure Terminal
            </h2>
            <div class="space-y-5">
                <div><input type="text" id="authUser" placeholder="Operator Node" class="w-full bg-slate-100 dark:bg-black/50 border border-slate-200 dark:border-slate-800 rounded-xl px-4 py-3.5 focus:outline-none focus:ring-2 focus:ring-hubema-500 text-slate-900 dark:text-white transition-all"></div>
                <div><input type="password" id="authPass" placeholder="Cryptographic Key" class="w-full bg-slate-100 dark:bg-black/50 border border-slate-200 dark:border-slate-800 rounded-xl px-4 py-3.5 focus:outline-none focus:ring-2 focus:ring-hubema-500 text-slate-900 dark:text-white transition-all"></div>
                <button onclick="verifyAccess()" class="w-full mt-4 py-4 rounded-xl font-bold text-white bg-gradient-to-r from-hubema-600 to-hubema-400 hover:from-hubema-500 hover:to-hubema-300 shadow-lg shadow-hubema-500/30 transition-all active:scale-95 uppercase tracking-wide">Initialize Handshake</button>
            </div>
        </div>
    </div>

    <!-- MAIN DASHBOARD -->
    <div id="mainCore" class="flex flex-col h-full w-full opacity-0 pointer-events-none transition-opacity duration-700">
        <!-- HEADER -->
        <header class="h-16 glass-panel border-b border-slate-200 dark:border-slate-800/50 flex items-center justify-between px-6 z-10 shrink-0">
            <div class="flex items-center gap-4">
                <div class="w-8 h-8 rounded-lg bg-gradient-to-br from-hubema-600 to-hubema-400 flex items-center justify-center shadow-lg shadow-hubema-500/20">
                    <svg class="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>
                </div>
                <div>
                    <h1 class="text-lg font-extrabold tracking-tight text-slate-900 dark:text-white leading-none">HUBEMA <span class="text-hubema-500 font-light">OS</span></h1>
                    <p class="text-[10px] text-slate-500 font-mono tracking-widest mt-1">TELEGRAM NEURAL BRIDGE v5.0</p>
                </div>
            </div>
            <div class="flex items-center gap-4">
                <button onclick="fetchDialogs()" class="px-4 py-1.5 rounded-full text-[11px] font-bold bg-slate-200/50 dark:bg-black/40 border border-slate-300 dark:border-slate-800 text-slate-600 dark:text-slate-400 hover:text-hubema-500 transition-all flex items-center gap-2 active:scale-95 shadow-sm">
                    <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
                    SYNC CHATS
                </button>
                <div class="flex items-center gap-2 bg-slate-200/50 dark:bg-black/40 px-3 py-1.5 rounded-full border border-slate-300 dark:border-slate-800">
                    <span class="relative flex h-2 w-2"><span id="statusPing" class="animate-ping absolute inline-flex h-full w-full rounded-full bg-slate-400 opacity-75"></span><span id="statusDot" class="relative inline-flex rounded-full h-2 w-2 bg-slate-500"></span></span>
                    <span id="sysStatus" class="text-[10px] font-bold tracking-widest text-slate-600 dark:text-slate-400">STANDBY</span>
                </div>
                <button onclick="toggleTheme()" class="p-2 rounded-full hover:bg-slate-200 dark:hover:bg-slate-800 transition-all active:scale-95">
                    <svg id="themeIcon" class="w-5 h-5 text-slate-800 dark:text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24"></svg>
                </button>
            </div>
        </header>

        <div class="flex-1 flex overflow-hidden">
            <!-- SIDEBAR -->
            <aside class="w-72 glass-panel border-r border-slate-200 dark:border-slate-800/50 flex flex-col shrink-0 z-0 bg-white/30 dark:bg-sys-panel/50">
                <div class="p-4 border-b border-slate-200 dark:border-slate-800/50">
                    <h2 class="text-xs font-bold text-slate-500 uppercase tracking-widest mb-3 flex justify-between items-center">
                        Active Directories
                        <span id="chatCountBadge" class="bg-hubema-500/20 text-hubema-500 px-2 py-0.5 rounded-full text-[9px]">0</span>
                    </h2>
                    <div class="relative">
                        <input type="text" id="chatSearch" placeholder="Search targets..." class="w-full bg-slate-100 dark:bg-black/40 border border-slate-300 dark:border-slate-700 rounded-lg pl-8 pr-3 py-2 text-xs focus:outline-none focus:ring-1 focus:ring-hubema-500 text-slate-900 dark:text-white transition-all">
                        <svg class="w-4 h-4 text-slate-400 absolute left-2.5 top-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
                    </div>
                </div>
                <div id="dialogsList" class="flex-1 overflow-y-auto p-2 space-y-1">
                    <div class="text-center text-xs text-slate-500 mt-10">Click 'SYNC CHATS' to load Telegram Matrix.</div>
                </div>
            </aside>

            <!-- MAIN WORKSPACE -->
            <main class="flex-1 flex flex-col relative overflow-hidden bg-slate-50 dark:bg-[#0b0c10]">
                <div class="h-14 border-b border-slate-200 dark:border-slate-800/50 flex items-center px-6 bg-white/50 dark:bg-black/20 backdrop-blur-sm shrink-0">
                    <div class="flex flex-col">
                        <span class="text-[10px] text-slate-500 uppercase tracking-widest font-mono">Current Target Node</span>
                        <span id="activeChatTitle" class="text-sm font-bold text-slate-900 dark:text-white truncate max-w-md">None Selected</span>
                    </div>
                </div>

                <div class="flex-1 overflow-y-auto p-6 grid grid-cols-1 lg:grid-cols-12 gap-6">
                    <div class="lg:col-span-7 flex flex-col gap-6">
                        
                        <!-- 4-Tab Navigator -->
                        <div class="flex bg-slate-200 dark:bg-black/50 p-1.5 rounded-2xl border border-slate-300 dark:border-slate-800 shrink-0">
                            <button id="tabLive" onclick="switchUIMode('live')" class="flex-1 py-2 rounded-xl text-[11px] font-bold bg-white dark:bg-sys-card shadow-md text-hubema-500 transition-all tracking-wider uppercase">🎙 Uplink</button>
                            <button id="tabMedia" onclick="switchUIMode('media')" class="flex-1 py-2 rounded-xl text-[11px] font-bold text-slate-500 opacity-70 hover:text-slate-700 dark:hover:text-slate-300 transition-all tracking-wider uppercase">🎬 Media</button>
                            <button id="tabTV" onclick="switchUIMode('tv')" class="flex-1 py-2 rounded-xl text-[11px] font-bold text-slate-500 opacity-70 hover:text-slate-700 dark:hover:text-slate-300 transition-all tracking-wider uppercase">📺 Live TV</button>
                            <button id="tabNeural" onclick="switchUIMode('tts')" class="flex-1 py-2 rounded-xl text-[11px] font-bold text-slate-500 opacity-70 hover:text-slate-700 dark:hover:text-slate-300 transition-all tracking-wider uppercase">🧠 Neural</button>
                        </div>

                        <!-- 🎙 LIVE UPLINK PANEL -->
                        <div id="panelLive" class="glass-panel p-5 rounded-3xl grid grid-cols-2 gap-5 transition-all duration-300 shrink-0">
                            <div>
                                <label class="block text-[10px] font-bold text-slate-500 mb-2 uppercase tracking-wider">Voice Encryption</label>
                                <select id="voiceMode" class="w-full appearance-none bg-slate-100 dark:bg-black/50 border border-slate-200 dark:border-slate-800 text-slate-800 dark:text-slate-200 text-xs font-semibold rounded-xl px-3 py-2.5 focus:outline-none focus:ring-1 focus:ring-hubema-500 cursor-pointer"><option value="normal">Clear Voice (Bypass)</option><option value="hacker">Hacker Distortion (Encrypted)</option></select>
                            </div>
                            <div>
                                <div class="flex justify-between items-center mb-2"><label class="block text-[10px] font-bold text-slate-500 uppercase tracking-wider">Distortion Depth</label><span id="depthVal" class="text-[10px] font-bold text-hubema-500 bg-hubema-500/10 px-1.5 py-0.5 rounded">5</span></div>
                                <input type="range" id="hackDepth" min="1" max="10" value="5" class="w-full h-1.5 bg-slate-200 dark:bg-slate-800 rounded-lg appearance-none cursor-pointer mt-1">
                            </div>
                            <button id="micBtn" class="col-span-2 py-3.5 rounded-xl font-bold text-white bg-gradient-to-r from-hubema-600 to-hubema-400 hover:from-hubema-500 hover:to-hubema-300 shadow-lg shadow-hubema-500/25 transition-all active:scale-95 flex items-center justify-center gap-2 uppercase tracking-wider text-sm mt-2"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg><span id="micBtnText">Establish Tunnel</span></button>
                        </div>

                        <!-- 🎬 CLOUD MEDIA PLAYER & RADIO PANEL -->
                        <div id="panelMedia" class="hidden glass-panel p-5 rounded-3xl flex-col gap-4 transition-all shrink-0">
                            <div class="flex flex-col gap-3 border-b border-slate-200 dark:border-slate-800/50 pb-4">
                                <label class="text-[10px] font-bold text-slate-500 uppercase tracking-wider">Search Cloud Database</label>
                                <input type="text" id="mediaQuery" placeholder="Search song title or enter YouTube URL..." class="w-full bg-slate-100 dark:bg-black/60 border border-slate-300 dark:border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:ring-1 focus:ring-sky-500 text-slate-900 dark:text-white transition-all text-xs">
                                <div class="flex gap-2">
                                    <button onclick="reqPlayMedia(false)" class="flex-1 py-3 rounded-xl bg-gradient-to-r from-sky-500 to-sky-600 hover:from-sky-400 hover:to-sky-500 text-white text-xs font-bold transition-all active:scale-95 shadow-lg shadow-sky-500/20 flex items-center justify-center gap-2">🎵 پخش موزیک</button>
                                    <button onclick="reqPlayMedia(true)" class="flex-1 py-3 rounded-xl bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-400 hover:to-indigo-500 text-white text-xs font-bold transition-all active:scale-95 shadow-lg shadow-indigo-500/20 flex items-center justify-center gap-2">🎥 پخش ویدیو</button>
                                </div>
                            </div>
                            <div class="flex flex-col gap-2 pt-1">
                                <label class="text-[10px] font-bold text-rose-500 uppercase tracking-wider flex items-center gap-1"><span class="w-1.5 h-1.5 bg-rose-500 rounded-full animate-pulse"></span> Live Radio Nodes</label>
                                <div class="radio-scroller">
                                    <button onclick="reqPlayRadio('http://lofi.stream.laut.fm/lofi', 'Lofi Beats Radio')" class="radio-chip bg-slate-200/50 dark:bg-black/40 hover:bg-rose-500 hover:text-white hover:border-rose-500 dark:text-slate-300">🎧 Lofi Beats</button>
                                    <button onclick="reqPlayRadio('http://icecast.vrtcdn.be/stubru_tijdloze-high.mp3', 'Electronic Studio')" class="radio-chip bg-slate-200/50 dark:bg-black/40 hover:bg-rose-500 hover:text-white hover:border-rose-500 dark:text-slate-300">⚡ Electronic Dance</button>
                                    <button onclick="reqPlayRadio('http://stream.srg-ssr.ch/m/rsc_de/mp3_128', 'Swiss Classical')" class="radio-chip bg-slate-200/50 dark:bg-black/40 hover:bg-rose-500 hover:text-white hover:border-rose-500 dark:text-slate-300">🎻 Classical Stream</button>
                                    <button onclick="reqPlayRadio('https://listen.radioking.com/ws52ptbbd48uv', 'Persian Mix')" class="radio-chip bg-slate-200/50 dark:bg-black/40 hover:bg-rose-500 hover:text-white hover:border-rose-500 dark:text-slate-300">📻 Persian Mix</button>
                                </div>
                            </div>
                        </div>
                        
                       <!-- --- START OF REPLACEMENT BLOCK 3: panelTV --- -->
                        <!-- --- START OF REPLACEMENT BLOCK 3: panelTV --- -->
                        <!-- 📺 LIVE TV PANEL (Ultimate Global Matrix - Datacenter Safe) -->
                        <!-- --- START OF REPLACEMENT BLOCK 3: panelTV (Ultimate Auto-Ping Grid) --- -->
                        <div id="panelTV" class="hidden glass-panel p-5 rounded-3xl flex-col gap-5 transition-all shrink-0 max-h-[70vh] overflow-y-auto" style="scrollbar-width: thin; scrollbar-color: #475569 transparent;">
                            
                            <div class="flex justify-between items-center border-b border-slate-200 dark:border-slate-800/50 pb-3 sticky top-0 bg-white/80 dark:bg-[#12141c]/90 backdrop-blur-md z-10">
                                <label class="text-xs font-bold text-blue-500 uppercase tracking-wider flex items-center gap-1.5">
                                    <span class="relative flex h-2 w-2 mr-1"><span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75"></span><span class="relative inline-flex rounded-full h-2 w-2 bg-blue-500"></span></span>
                                    Auto-Scanning Matrix Nodes
                                </label>
                                <button onclick="triggerTVScan()" class="bg-blue-500/10 hover:bg-blue-500/20 text-blue-500 border border-blue-500/30 px-3 py-1.5 rounded-lg text-[9px] font-bold uppercase tracking-widest transition-all active:scale-95 flex items-center gap-1.5">
                                    <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg> Force Rescan
                                </button>
                            </div>
                            
                            <div class="bg-blue-500/5 border border-blue-500/20 p-3 rounded-2xl">
                                <div class="flex gap-2">
                                    <input type="text" id="tvCustomUrl" placeholder="Enter custom .m3u8 stream URL..." class="flex-1 bg-white dark:bg-black/60 border border-slate-300 dark:border-slate-700 rounded-xl px-4 py-2 focus:outline-none focus:ring-1 focus:ring-blue-500 text-slate-900 dark:text-white transition-all text-xs font-mono">
                                    <button onclick="reqCustomTV()" class="px-5 py-2 rounded-xl bg-gradient-to-r from-blue-600 to-blue-500 hover:from-blue-500 hover:to-blue-400 text-white text-[10px] font-bold transition-all active:scale-95 shadow-lg shadow-blue-500/30 tracking-widest">INJECT</button>
                                </div>
                            </div>

                            <style>
                                /* Grid پیشرفته و ریسپانسیو برای حذف اسکرول افقی */
                                .tv-grid-dynamic { display: grid; grid-template-columns: repeat(auto-fill, minmax(115px, 1fr)); gap: 0.75rem; }
                                /* انیمیشن‌ها و مرتب‌سازی خودکار */
                                .tv-node-wrap { transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); }
                                /* وضعیت خاکستری (در حال اسکن) - اولویت میانی */
                                .node-scanning { filter: grayscale(100%); opacity: 0.6; order: 50; animation: pulse-border 1.5s infinite; pointer-events: none; }
                                /* وضعیت روشن (در دسترس) - پرش به بالا */
                                .node-online { filter: grayscale(0%); opacity: 1; order: 1; cursor: pointer; transform: scale(1); }
                                .node-online:hover { transform: translateY(-3px) scale(1.02); box-shadow: 0 10px 25px rgba(56, 189, 248, 0.2); border-color: rgba(56, 189, 248, 0.5); }
                                /* وضعیت سوخته (غیرقابل دسترس) - سقوط به پایین */
                                .node-offline { filter: grayscale(100%); opacity: 0.25; order: 99; pointer-events: none; background: rgba(0,0,0,0.5); border-color: rgba(255,0,0,0.2); }
                                
                                @keyframes pulse-border { 0% { border-color: rgba(100,116,139,0.2); } 50% { border-color: rgba(56,189,248,0.5); } 100% { border-color: rgba(100,116,139,0.2); } }
                            </style>

                            <!-- کانتینرهای دسته‌بندی -->
                            <div class="tv-section-title mt-2"><span class="w-1.5 h-1.5 bg-emerald-500 rounded-full"></span> 🇮🇷 Persian & Entertainment</div>
                            <div id="grid-persian" class="tv-grid-dynamic"></div>

                            <div class="tv-section-title mt-4"><span class="w-1.5 h-1.5 bg-blue-500 rounded-full"></span> 🌍 Global & UK News</div>
                            <div id="grid-global" class="tv-grid-dynamic"></div>

                            <div class="tv-section-title mt-4"><span class="w-1.5 h-1.5 bg-rose-500 rounded-full"></span> 🇺🇸 US Networks</div>
                            <div id="grid-us" class="tv-grid-dynamic"></div>

                            <div class="tv-section-title mt-4"><span class="w-1.5 h-1.5 bg-red-500 rounded-full"></span> 🇹🇷 Turkey & Europe</div>
                            <div id="grid-tr" class="tv-grid-dynamic"></div>

                        </div>

                        <script>
                            // --- START OF REPLACEMENT BLOCK (UI Matrix Nodes - Purged & Stable) ---
                            // --- START OF REPLACEMENT BLOCK 2 (HTML UI Nodes: The Ultimate Matrix) ---
                                const MATRIX_NODES = [
                                    // 🔴 NEWS & POLITICS
                                    { id: 'n_bbc', cat: 'persian', name: 'BBC Persian', icon: 'BB', color: 'from-red-600 to-red-900', url: 'https://www.youtube.com/@BBCPersian/live' },
                                    { id: 'n_intl', cat: 'persian', name: 'Iran Intl', icon: 'IN', color: 'from-red-600 to-black', url: 'https://www.youtube.com/@iranintltv/live' },
                                    { id: 'n_afghan', cat: 'persian', name: 'Afghan Intl', icon: 'AF', color: 'from-red-500 to-rose-800', url: 'ytsearch1:Afghanistan International Live' },
                                    { id: 'n_voa', cat: 'persian', name: 'VOA Farsi', icon: 'VO', color: 'from-blue-700 to-blue-900', url: 'https://www.youtube.com/@VOAFarsi/live' },
                                    { id: 'n_farda', cat: 'persian', name: 'Radio Farda', icon: 'RF', color: 'from-orange-500 to-orange-700', url: 'https://www.youtube.com/@RadioFarda/live' },
                                    { id: 'n_manoto', cat: 'persian', name: 'Manoto TV', icon: 'MN', color: 'from-slate-700 to-black', url: 'ytsearch1:Manoto Live پخش زنده' },
                                    { id: 'n_pars', cat: 'persian', name: 'Pars TV', icon: 'PT', color: 'from-sky-600 to-blue-800', url: 'ytsearch1:Pars TV Live پخش زنده' },
                                    { id: 'n_channel1', cat: 'persian', name: 'Channel One', icon: 'C1', color: 'from-blue-500 to-indigo-700', url: 'ytsearch1:Kanal Yek TV Live شهرام همایون' },
                                    { id: 'n_euronews_fa', cat: 'persian', name: 'Euronews FA', icon: 'EU', color: 'from-blue-400 to-cyan-600', url: 'ytsearch1:Euronews Farsi Live' },

                                    // 💎 GEM NETWORK
                                    { id: 'g_tv', cat: 'persian', name: 'GEM TV', icon: 'G1', color: 'from-fuchsia-600 to-pink-800', url: 'ytsearch1:GEM TV Live پخش زنده' },
                                    { id: 'g_series', cat: 'persian', name: 'GEM Series', icon: 'GS', color: 'from-pink-500 to-rose-700', url: 'ytsearch1:GEM Series Live پخش زنده' },
                                    { id: 'g_movie', cat: 'persian', name: 'GEM Movies', icon: 'GM', color: 'from-rose-600 to-red-800', url: 'ytsearch1:GEM Movies Live پخش زنده' },
                                    { id: 'g_bolly', cat: 'persian', name: 'GEM Bolly', icon: 'GB', color: 'from-orange-500 to-amber-600', url: 'ytsearch1:GEM Bollywood Live پخش زنده' },
                                    { id: 'g_kids', cat: 'persian', name: 'GEM Kids', icon: 'GK', color: 'from-fuchsia-400 to-purple-600', url: 'ytsearch1:GEM Kids Live پخش زنده' },
                                    { id: 'g_junior', cat: 'persian', name: 'GEM Junior', icon: 'GJ', color: 'from-purple-400 to-fuchsia-500', url: 'ytsearch1:GEM Junior Live پخش زنده' },
                                    { id: 'g_life', cat: 'persian', name: 'GEM Life', icon: 'GL', color: 'from-teal-400 to-emerald-600', url: 'ytsearch1:GEM Life Live پخش زنده' },
                                    { id: 'g_rubix', cat: 'persian', name: 'GEM Rubix', icon: 'GR', color: 'from-rose-400 to-pink-600', url: 'ytsearch1:GEM Rubix Live پخش زنده' },

                                    // 🟣 PERSIANA NETWORK
                                    { id: 'p_one', cat: 'persian', name: 'Persiana One', icon: 'P1', color: 'from-indigo-600 to-violet-900', url: 'ytsearch1:Persiana One Live پخش زنده' },
                                    { id: 'p_family', cat: 'persian', name: 'Persiana Fam', icon: 'PF', color: 'from-violet-600 to-purple-900', url: 'ytsearch1:Persiana Family Live پخش زنده' },
                                    { id: 'p_cinema', cat: 'persian', name: 'Persiana Cine', icon: 'PC', color: 'from-purple-600 to-indigo-900', url: 'ytsearch1:Persiana Cinema Live پخش زنده' },
                                    { id: 'p_music', cat: 'persian', name: 'Persiana Mus', icon: 'PM', color: 'from-indigo-500 to-blue-800', url: 'ytsearch1:Persiana Music Live پخش زنده' },
                                    { id: 'p_sports', cat: 'persian', name: 'Persiana Sp', icon: 'PS', color: 'from-blue-600 to-cyan-800', url: 'ytsearch1:Persiana Sports Live پخش زنده' },
                                    { id: 'p_comedy', cat: 'persian', name: 'Persiana Com', icon: 'PCo', color: 'from-violet-500 to-fuchsia-700', url: 'ytsearch1:Persiana Comedy Live پخش زنده' },

                                    // 🎵 MUSIC & ENTERTAINMENT
                                    { id: 'm_pmc', cat: 'persian', name: 'PMC Music', icon: 'PM', color: 'from-slate-800 to-black', url: 'ytsearch1:PMC Music Live پخش زنده' },
                                    { id: 'm_rjtv', cat: 'persian', name: 'Radio Javan', icon: 'RJ', color: 'from-red-600 to-red-900', url: 'ytsearch1:Radio Javan TV Live' },
                                    { id: 'm_tapesh', cat: 'persian', name: 'Tapesh TV', icon: 'TP', color: 'from-amber-500 to-orange-700', url: 'ytsearch1:Tapesh TV Live پخش زنده' },
                                    { id: 'm_avang', cat: 'persian', name: 'Avang TV', icon: 'AV', color: 'from-indigo-600 to-blue-900', url: 'ytsearch1:Avang TV Live پخش زنده' },
                                    { id: 'e_mbc', cat: 'persian', name: 'MBC Persia', icon: 'MB', color: 'from-sky-500 to-blue-700', url: 'ytsearch1:MBC Persia Live پخش زنده' },
                                    { id: 'e_4u', cat: 'persian', name: '4U TV', icon: '4U', color: 'from-orange-400 to-rose-500', url: 'ytsearch1:4U TV Live پخش زنده' },
                                    { id: 'e_itn', cat: 'persian', name: 'ITN TV', icon: 'IT', color: 'from-blue-500 to-indigo-600', url: 'ytsearch1:ITN TV Live پخش زنده حمید شب خیز' },

                                    // 🟢 IRIB & DOMESTIC
                                    { id: 'irib_1', cat: 'persian', name: 'Shabake 1', icon: 'IR1', color: 'from-emerald-600 to-teal-800', url: 'ytsearch1:شبکه یک پخش زنده' },
                                    { id: 'irib_3', cat: 'persian', name: 'Shabake 3', icon: 'IR3', color: 'from-emerald-500 to-teal-700', url: 'ytsearch1:شبکه سه پخش زنده' },
                                    { id: 'irib_varzesh', cat: 'persian', name: 'Varzesh TV', icon: 'IRV', color: 'from-teal-600 to-emerald-800', url: 'ytsearch1:شبکه ورزش پخش زنده' },
                                    { id: 'irib_khabar', cat: 'persian', name: 'Khabar TV', icon: 'IRK', color: 'from-cyan-600 to-blue-800', url: 'ytsearch1:شبکه خبر پخش زنده' },
                                    { id: 'irib_nasim', cat: 'persian', name: 'Nasim TV', icon: 'IRN', color: 'from-green-500 to-emerald-600', url: 'ytsearch1:شبکه نسیم پخش زنده' },
                                    { id: 'irib_pooya', cat: 'persian', name: 'Pooya TV', icon: 'IRP', color: 'from-lime-500 to-green-600', url: 'ytsearch1:شبکه پویا پخش زنده' },
                                    { id: 'e_ifilm', cat: 'persian', name: 'iFilm Farsi', icon: 'IF', color: 'from-orange-500 to-red-600', url: 'ytsearch1: ifilm Farsi' },

                                    // 🌍 GLOBAL NEWS
                                    { id: 'gb1', cat: 'global', name: 'Al Jazeera', icon: 'AJ', color: 'from-amber-500 to-yellow-700', url: 'https://www.youtube.com/@aljazeeraenglish/live' },
                                    { id: 'gb2', cat: 'global', name: 'Sky News UK', icon: 'SK', color: 'from-red-600 to-red-800', url: 'https://www.youtube.com/@SkyNews/live' },
                                    { id: 'us1', cat: 'us', name: 'ABC News', icon: 'AB', color: 'from-slate-800 to-black', url: 'https://www.youtube.com/@ABCNews/live' },
                                    { id: 'us5', cat: 'us', name: 'NASA TV', icon: 'NA', color: 'from-blue-900 to-black', url: 'https://www.youtube.com/@NASA/live' },
                                    { id: 'tr1', cat: 'tr', name: 'TRT 1', icon: 'T1', color: 'from-teal-500 to-teal-700', url: 'https://tv-trt1.medya.trt.com.tr/master.m3u8' },
                                    { id: 'tr5', cat: 'tr', name: 'Show TV', icon: 'SH', color: 'from-rose-500 to-red-600', url: 'https://www.youtube.com/@ShowTV/live' }
                                ];
                                // --- END OF REPLACEMENT BLOCK 2 ---
                            // --- END OF REPLACEMENT BLOCK ---

                            let hasScannedTV = false;

                            // رندر اولیه استاتیک DOM
                            function initTVMatrix() {
                                MATRIX_NODES.forEach(node => {
                                    const grid = document.getElementById(`grid-${node.cat}`);
                                    if(grid) {
                                        const el = document.createElement('div');
                                        el.id = `node_${node.id}`;
                                        el.className = `tv-node-wrap node-scanning bg-white/5 dark:bg-black/20 border border-slate-200 dark:border-slate-800 rounded-2xl p-3 flex flex-col items-center justify-center gap-2`;
                                        el.onclick = () => { if(el.classList.contains('node-online')) reqPlayTV(node.url, node.name); };
                                        el.innerHTML = `<div class="w-10 h-10 rounded-xl flex items-center justify-center text-sm bg-gradient-to-br ${node.color} text-white font-bold shadow-lg">${node.icon}</div><div class="text-[10px] font-bold text-slate-700 dark:text-slate-300 text-center uppercase tracking-widest">${node.name}</div>`;
                                        grid.appendChild(el);
                                    }
                                });
                            }
                            initTVMatrix();

                            // شلیک درخواست پینگ گروهی به بک‌اند
                            function triggerTVScan() {
                                if (!ws || ws.readyState !== WebSocket.OPEN) return;
                                
                                // ریست وضعیت ظاهری
                                MATRIX_NODES.forEach(n => {
                                    const el = document.getElementById(`node_${n.id}`);
                                    if(el) el.className = `tv-node-wrap node-scanning bg-white/5 dark:bg-black/20 border border-slate-200 dark:border-slate-800 rounded-2xl p-3 flex flex-col items-center justify-center gap-2`;
                                });
                                
                                const payload = MATRIX_NODES.map(n => ({id: n.id, url: n.url}));
                                ws.send(JSON.stringify({ type: "ping_tv_network", nodes: payload }));
                                hasScannedTV = true;
                            }

                            // این تابع در بلوک وب‌سوکت پایین‌تر استفاده می‌شود تا DOM را آپدیت کند
                            window.updateTVNodeStatus = function(id, status) {
                                const el = document.getElementById(`node_${id}`);
                                if(el) {
                                    el.classList.remove('node-scanning', 'node-online', 'node-offline');
                                    el.classList.add(status === 'online' ? 'node-online' : 'node-offline');
                                }
                            };
                        </script>
                        <!-- --- END OF REPLACEMENT BLOCK 3 --- -->
                        <!-- --- END OF REPLACEMENT BLOCK 3 --- -->

                        <!-- 🧠 NEURAL CHAT PANEL -->
                        <div id="panelNeural" class="hidden glass-panel p-5 rounded-3xl flex-col gap-4 transition-all duration-300 flex-1 min-h-[350px]">
                            <div class="flex justify-between items-center"><label class="text-xs font-bold text-purple-500 uppercase tracking-wider flex items-center gap-1.5"><svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg> AI Synth Matrix</label><select id="aiVoice" class="appearance-none bg-slate-100 dark:bg-black/50 border border-slate-200 dark:border-slate-800 text-slate-800 dark:text-slate-200 text-[10px] font-bold rounded-lg px-2 py-1 focus:outline-none cursor-pointer"><optgroup label="Persian (Native)"><option value="fa-IR-FaridNeural">فارسی - فرید</option><option value="fa-IR-DilaraNeural">فارسی - دلارا</option></optgroup><optgroup label="International (Multilingual)"><option value="en-US-ChristopherNeural">English - Chris</option><option value="en-US-AriaNeural">English - Aria</option></optgroup></select></div>
                            <div id="chatHistory" class="flex-1 bg-white/50 dark:bg-black/30 rounded-xl p-4 overflow-y-auto flex flex-col gap-3 border border-slate-200 dark:border-slate-800/50 inner-shadow scroll-smooth"><div class="text-center text-[10px] text-slate-400 font-mono">-- NEURAL LINK ESTABLISHED --</div></div>
                            <div class="relative flex items-end gap-2 shrink-0"><textarea id="aiText" rows="1" placeholder="Type sequence..." class="flex-1 bg-slate-100 dark:bg-black/60 border border-slate-300 dark:border-slate-700 rounded-xl pl-4 pr-10 py-3 focus:outline-none focus:ring-1 focus:ring-purple-500 text-slate-900 dark:text-white transition-all text-xs resize-none overflow-hidden max-h-[100px]"></textarea><button id="sendAiBtn" class="absolute right-1.5 bottom-1.5 p-1.5 rounded-lg bg-purple-500 text-white hover:bg-purple-600 transition-all active:scale-95 shadow-md flex items-center justify-center"><svg class="w-4 h-4 ml-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/></svg></button></div>
                        </div>
                    </div>

                    <div class="lg:col-span-5 flex flex-col gap-6">
                        <!-- UNIVERSAL DASHBOARD CONTROLS (ALWAYS VISIBLE) -->
                        <div class="bg-slate-100 dark:bg-black/40 rounded-3xl p-5 flex flex-col items-center justify-center border border-slate-200 dark:border-slate-800/50 shadow-inner relative overflow-hidden shrink-0">
                            <div id="mediaStatusBadge" class="absolute top-3 right-3 text-[8px] font-mono bg-slate-200 dark:bg-slate-800 px-2 py-1 rounded text-slate-500 shadow-sm border border-slate-300 dark:border-slate-700 z-10">IDLE</div>
                            <div id="mediaTrackName" class="text-xs font-bold text-slate-700 dark:text-slate-300 text-center mb-4 mt-2 px-6 w-full truncate font-mono">No Media Loaded</div>
                            
                            <div class="flex items-center gap-5">
                                <button id="btnSeekBwd" onclick="reqMediaCtrl('skip_bwd')" class="p-2.5 rounded-full bg-white dark:bg-sys-card border border-slate-200 dark:border-slate-700 hover:text-sky-500 transition-all active:scale-90 shadow-sm text-slate-600 dark:text-slate-400"><svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0019 16V8a1 1 0 00-1.6-.8l-5.333 4zM4.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0011 16V8a1 1 0 00-1.6-.8l-5.334 4z"/></svg></button>
                                <button onclick="reqMediaCtrl('toggle')" class="w-14 h-14 rounded-full bg-gradient-to-tr from-sky-600 to-sky-400 text-white flex items-center justify-center shadow-lg shadow-sky-500/30 hover:scale-105 active:scale-95 transition-all"><svg id="mediaToggleIcon" class="w-6 h-6 ml-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/></svg></button>
                                <button id="btnSeekFwd" onclick="reqMediaCtrl('skip_fwd')" class="p-2.5 rounded-full bg-white dark:bg-sys-card border border-slate-200 dark:border-slate-700 hover:text-sky-500 transition-all active:scale-90 shadow-sm text-slate-600 dark:text-slate-400"><svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.933 12.8a1 1 0 000-1.6L6.6 7.2A1 1 0 005 8v8a1 1 0 001.6.8l5.333-4zM19.933 12.8a1 1 0 000-1.6l-5.333-4A1 1 0 0013 8v8a1 1 0 001.6.8l5.333-4z"/></svg></button>
                            </div>
                            <button onclick="reqMediaCtrl('stop')" class="mt-5 px-5 py-1.5 rounded-full border border-rose-500/50 text-[10px] font-bold text-rose-500 hover:bg-rose-500/10 transition-all uppercase tracking-widest active:scale-95">Stop Playback</button>
                        </div>
                    
                        <!-- --- REPLACEMENT BLOCK FOR CONTROL BUTTONS IN HTML_PANEL --- -->
                        <div class="grid grid-cols-3 gap-4 shrink-0">
                            <!-- دکمه جدید خوش‌آمدگویی هوشمند -->
                            <button id="toggleWelcomeBtn" onclick="reqToggleWelcome()" class="py-3.5 rounded-2xl font-bold text-slate-700 dark:text-slate-300 bg-slate-200 dark:bg-slate-800 hover:bg-slate-300 dark:hover:bg-slate-700 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-transparent shadow-sm relative overflow-hidden group">
                                <div id="welcomePulse" class="absolute inset-0 bg-purple-500/20 animate-pulse hidden"></div>
                                <svg id="welcomeIcon" class="w-5 h-5 text-slate-400 z-10 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
                                <span id="welcomeText" class="text-[9px] uppercase tracking-widest z-10">Smart Welcome: OFF</span>
                            </button>

                            <button id="tgMuteBtn" class="py-3.5 rounded-2xl font-bold text-slate-700 dark:text-slate-300 bg-slate-200 dark:bg-slate-800 hover:bg-slate-300 dark:hover:bg-slate-700 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-transparent shadow-sm"><svg id="muteIcon" class="w-5 h-5 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg><span id="muteText" class="text-[9px] uppercase tracking-widest">VC Unmuted</span></button>
                            
                            <button id="killVcBtn" class="py-3.5 rounded-2xl font-bold text-rose-600 dark:text-rose-500 bg-rose-50 dark:bg-rose-500/10 hover:bg-rose-100 dark:hover:bg-rose-500/20 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-rose-200 dark:border-rose-500/30 shadow-sm"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"></path></svg><span class="text-[9px] uppercase tracking-widest">Disconnect Node</span></button>
                        </div>
<!-- --- END REPLACEMENT BLOCK --- -->
                        <div class="glass-panel rounded-3xl p-5 flex-1 flex flex-col border border-slate-200 dark:border-slate-800 min-h-[200px]">
                            <div class="flex items-center gap-2 mb-3 border-b border-slate-200 dark:border-slate-800/50 pb-2 shrink-0"><svg class="w-3.5 h-3.5 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg><span class="text-[10px] font-bold text-slate-500 uppercase tracking-widest">Live Kernel Logs</span></div>
                            <div id="termLog" class="flex-1 overflow-y-auto space-y-1.5 font-mono text-[10px] text-slate-600 dark:text-slate-400 pr-2"><div><span class="text-slate-400 dark:text-slate-500 mr-2">[SYS]</span><span class="text-blue-500 dark:text-blue-400">Tactical OS Boot Sequence Complete.</span></div></div>
                        </div>
                    </div>
                </div>
            </main>
        </div>
    </div>
    
    <script>

    // --- INSERT INTO JAVASCRIPT SECTION OF HTML_PANEL ---
        let isWelcomeActive = false;

        function reqToggleWelcome() {
            haptic(30); 
            if (!ws || ws.readyState !== WebSocket.OPEN) return;
            isWelcomeActive = !isWelcomeActive; 
            ws.send(JSON.stringify({ type: "toggle_welcome", state: isWelcomeActive }));
            updateWelcomeUI(isWelcomeActive);
        }

        function updateWelcomeUI(state) {
            isWelcomeActive = state;
            const btn = document.getElementById("toggleWelcomeBtn");
            const icon = document.getElementById("welcomeIcon");
            const text = document.getElementById("welcomeText");
            const pulse = document.getElementById("welcomePulse");
            
            if (state) {
                btn.className = "py-3.5 rounded-2xl font-bold text-purple-600 dark:text-purple-400 bg-purple-50 dark:bg-purple-500/10 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-purple-300 dark:border-purple-500/30 shadow-sm relative overflow-hidden group";
                icon.className = "w-5 h-5 text-purple-500 z-10 transition-colors";
                text.innerText = "Smart Welcome: ON";
                pulse.classList.remove("hidden");
            } else {
                btn.className = "py-3.5 rounded-2xl font-bold text-slate-700 dark:text-slate-300 bg-slate-200 dark:bg-slate-800 hover:bg-slate-300 dark:hover:bg-slate-700 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-transparent shadow-sm relative overflow-hidden group";
                icon.className = "w-5 h-5 text-slate-400 z-10 transition-colors";
                text.innerText = "Smart Welcome: OFF";
                pulse.classList.add("hidden");
            }
        }

        // داخل ws.onmessage این خط را برای دریافت استتوس از سرور اضافه کنید:
        // if(data.type === "welcome_state") { updateWelcomeUI(data.state); }
// --- END INSERT ---

        const haptic = (pattern) => { if(navigator.vibrate) navigator.vibrate(pattern); };
        
        const toggleTheme = () => {
            const html = document.documentElement, icon = document.getElementById('themeIcon'); haptic(30);
            if(html.classList.contains('dark')) {
                html.classList.remove('dark'); localStorage.setItem('theme', 'light');
                icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>';
            } else {
                html.classList.add('dark'); localStorage.setItem('theme', 'dark');
                icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>';
            }
        };
        if(localStorage.getItem('theme') !== 'light') toggleTheme(); else { document.getElementById('themeIcon').innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>'; }

        function showModal(title, msg, isError = false) {
            haptic(isError ? [50, 50, 50] : 50);
            const m = document.getElementById("hubemaModal"), b = document.getElementById("modalBox"), i = document.getElementById("modalIcon");
            document.getElementById("modalTitle").innerText = title; document.getElementById("modalMsg").innerText = msg;
            i.className = isError ? "mx-auto w-16 h-16 mb-4 rounded-full flex items-center justify-center bg-rose-500/10 text-rose-500" : "mx-auto w-16 h-16 mb-4 rounded-full flex items-center justify-center bg-hubema-500/10 text-hubema-500";
            i.innerHTML = isError ? '<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>' : '<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>';
            m.classList.remove("opacity-0", "pointer-events-none"); b.classList.remove("scale-95"); b.classList.add("scale-100");
        }

        function closeModal() {
            haptic(20); const m = document.getElementById("hubemaModal"), b = document.getElementById("modalBox");
            m.classList.add("opacity-0", "pointer-events-none"); b.classList.remove("scale-100"); b.classList.add("scale-95");
        }

        let authToken = localStorage.getItem("hubema_auth_token") || "";
        let ws, mediaRecorder, isConnecting = false, isBotMuted = false, blockData = false;
        let currentMode = "live", activeChatId = null, mediaCurrentState = "stopped";
        let dialogsData = [];

        document.addEventListener("DOMContentLoaded", () => {
            if(authToken) {
                document.getElementById("loginGate").style.display = "none";
                document.getElementById("mainCore").classList.remove("opacity-0", "pointer-events-none");
                initWebSocketSilent();
            }
        });

        function verifyAccess() {
            haptic(40);
            const u = document.getElementById("authUser").value, p = document.getElementById("authPass").value;
            if(!u || !p) { showModal("AUTH FAILED", "Operator credentials are required.", true); return; }
            authToken = btoa(u + ":" + p); localStorage.setItem("hubema_auth_token", authToken);
            const gate = document.getElementById("loginGate"), core = document.getElementById("mainCore");
            gate.classList.add("opacity-0"); 
            setTimeout(() => { gate.style.display = "none"; core.classList.remove("opacity-0", "pointer-events-none"); initWebSocketSilent(); }, 700);
        }

        function log(msg, type = "info") {
            const d = new Date(), time = `${d.getHours().toString().padStart(2,'0')}:${d.getMinutes().toString().padStart(2,'0')}:${d.getSeconds().toString().padStart(2,'0')}`;
            const div = document.createElement("div"); div.className = "animate-slide-up leading-relaxed";
            let colorClass = type === 'error' ? "text-rose-500 font-semibold" : (type === 'success' ? "text-hubema-500 font-semibold" : (type === 'ff-log' ? "text-purple-500 font-bold" : "text-slate-600 dark:text-slate-400"));
            div.innerHTML = `<span class="text-slate-400 dark:text-slate-500 mr-2">[${time}]</span><span class="${colorClass}">${msg}</span>`; 
            const termLog = document.getElementById("termLog");
            termLog.appendChild(div); 
            if (termLog.childElementCount > 100) termLog.removeChild(termLog.firstChild);
            termLog.scrollTop = termLog.scrollHeight;
        }

        function updateSysStatus(state) {
            const ping = document.getElementById("statusPing"), dot = document.getElementById("statusDot"), txt = document.getElementById("sysStatus");
            if(state === 'LIVE') {
                ping.className = "animate-ping absolute inline-flex h-full w-full rounded-full bg-rose-400 opacity-75"; dot.className = "relative inline-flex rounded-full h-2 w-2 bg-rose-500";
                txt.innerText = "UPLINK ACTIVE"; txt.className = "text-[10px] font-bold tracking-widest text-rose-500";
            } else if(state === 'NEURAL') {
                ping.className = "animate-ping absolute inline-flex h-full w-full rounded-full bg-purple-400 opacity-75"; dot.className = "relative inline-flex rounded-full h-2 w-2 bg-purple-500";
                txt.innerText = "NEURAL LINK"; txt.className = "text-[10px] font-bold tracking-widest text-purple-500";
            } else if(state === 'MEDIA') {
                ping.className = "animate-ping absolute inline-flex h-full w-full rounded-full bg-sky-400 opacity-75"; dot.className = "relative inline-flex rounded-full h-2 w-2 bg-sky-500";
                txt.innerText = "MEDIA ENGINE"; txt.className = "text-[10px] font-bold tracking-widest text-sky-500";
            } else if(state === 'TV') {
                ping.className = "animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75"; dot.className = "relative inline-flex rounded-full h-2 w-2 bg-blue-500";
                txt.innerText = "LIVE TV STREAM"; txt.className = "text-[10px] font-bold tracking-widest text-blue-500";
            } else {
                ping.className = "animate-ping absolute inline-flex h-full w-full rounded-full bg-slate-400 opacity-75"; dot.className = "relative inline-flex rounded-full h-2 w-2 bg-slate-500";
                txt.innerText = "STANDBY"; txt.className = "text-[10px] font-bold tracking-widest text-slate-600 dark:text-slate-400";
            }
        }

        function switchUIMode(mode) {
            haptic(20); if (currentMode === mode) return; currentMode = mode;
            
            const tabs = { live: document.getElementById("tabLive"), media: document.getElementById("tabMedia"), tv: document.getElementById("tabTV"), tts: document.getElementById("tabNeural") };
            const panels = { live: document.getElementById("panelLive"), media: document.getElementById("panelMedia"), tv: document.getElementById("panelTV"), tts: document.getElementById("panelNeural") };
            
            const idleCls = "flex-1 py-2 rounded-xl text-[11px] font-bold text-slate-500 opacity-70 hover:text-slate-700 dark:hover:text-slate-300 transition-all tracking-wider uppercase";
            
            Object.values(tabs).forEach(t => t.className = idleCls);
            Object.values(panels).forEach(p => p.classList.add("hidden"));
            
            if (mode === 'tts') {
                tabs.tts.className = "flex-1 py-2 rounded-xl text-[11px] font-bold bg-white dark:bg-sys-card shadow-md text-purple-500 transition-all tracking-wider uppercase";
                panels.tts.classList.remove("hidden"); panels.tts.classList.add("flex");
                updateSysStatus('NEURAL'); if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: "switch_mode", mode: "tts" }));
            } else if (mode === 'media') {
                tabs.media.className = "flex-1 py-2 rounded-xl text-[11px] font-bold bg-white dark:bg-sys-card shadow-md text-sky-500 transition-all tracking-wider uppercase";
                panels.media.classList.remove("hidden"); panels.media.classList.add("flex");
                updateSysStatus('MEDIA'); if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: "switch_mode", mode: "live" }));
            } else if (mode === 'tv') {
                tabs.tv.className = "flex-1 py-2 rounded-xl text-[11px] font-bold bg-white dark:bg-sys-card shadow-md text-blue-500 transition-all tracking-wider uppercase";
                panels.tv.classList.remove("hidden"); panels.tv.classList.add("flex");
                updateSysStatus('TV'); if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: "switch_mode", mode: "live" }));
                
                // 🔴 شاهکار UX: سینک خودکار لیست گروه‌ها به محض ورود به بخش تلویزیون (بدون نیاز به کلیک کاربر)
                // با استفاده از شرط زیر، جلوگیری می‌کنیم که با هر بار سوییچ کردن تب، به API تلگرام فشار بیاید (جلوگیری از لیمیت شدن ربات)
                if (dialogsData.length === 0) {
                    setTimeout(() => fetchDialogs(), 100);
                }

                // شلیک پینگ هوشمند شبکه‌ها هنگام ورود به تب تلویزیون
                if(typeof hasScannedTV !== 'undefined' && !hasScannedTV) {
                    setTimeout(() => triggerTVScan(), 300);
                }
            } else {
                tabs.live.className = "flex-1 py-2 rounded-xl text-[11px] font-bold bg-white dark:bg-sys-card shadow-md text-hubema-500 transition-all tracking-wider uppercase";
                panels.live.classList.remove("hidden");
                updateSysStatus('STANDBY'); if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: "switch_mode", mode: "live" }));
            }
            
            if(mediaRecorder && mediaRecorder.state === "recording") { blockData = true; mediaRecorder.stop(); } setMicBtnState('idle');
        }

        // --- MEDIA CONTROLLER FUNCTIONS ---
        function reqPlayMedia(isVideo) {
            haptic(20); const queryInput = document.getElementById("mediaQuery"); const query = queryInput.value.trim();
            if(!activeChatId) { showModal("NO DIRECTORY", "لطفاً ابتدا یک گروه انتخاب کنید.", true); return; }
            if(!query) { queryInput.classList.add("ring-2", "ring-rose-500"); setTimeout(() => queryInput.classList.remove("ring-2", "ring-rose-500"), 1000); showModal("MISSING DATA", "نام آهنگ، فیلم یا لینک را وارد کنید.", true); return; }
            if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "play_media", query: query, is_video: isVideo })); queryInput.value = ""; }
        }
        
        function reqPlayRadio(url, name) {
            haptic(20);
            if(!activeChatId) { showModal("NO DIRECTORY", "لطفاً ابتدا یک گروه انتخاب کنید.", true); return; }
            if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "play_radio", url: url, name: name })); }
        }
        
        function reqPlayTV(url, name) {
            haptic(20);
            if(!activeChatId) { showModal("NO DIRECTORY", "لطفاً ابتدا یک گروه انتخاب کنید.", true); return; }
            if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "play_tv", url: url, name: name })); }
        }
        
        function reqCustomTV() {
            haptic(20);
            const urlInput = document.getElementById("tvCustomUrl"); const url = urlInput.value.trim();
            if(!activeChatId) { showModal("NO DIRECTORY", "لطفاً ابتدا یک گروه انتخاب کنید.", true); return; }
            if(!url) { urlInput.classList.add("ring-2", "ring-rose-500"); setTimeout(() => urlInput.classList.remove("ring-2", "ring-rose-500"), 1000); showModal("MISSING URL", "لینک M3U8 شبکه را وارد کنید.", true); return; }
            if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "play_tv", url: url, name: "Custom TV Stream" })); urlInput.value = ""; }
        }

        function reqMediaCtrl(action) {
            haptic(15);
            if (mediaCurrentState === "stopped" || mediaCurrentState === "idle") { log("سیستم در حال حاضر پخشی ندارد.", "error"); return; }
            if (ws && ws.readyState === WebSocket.OPEN) {
                if(action === 'toggle') action = (mediaCurrentState === 'playing') ? 'pause' : 'resume';
                ws.send(JSON.stringify({ type: "media_ctrl", action: action }));
            }
        }

        function initWebSocketSilent() {
            if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) return;
            ws = new WebSocket((window.location.protocol === "https:" ? "wss:" : "ws:") + "//" + window.location.host + "/ws?token=" + authToken);
            
            // 🔴 هوک چرخه حیات (Lifecycle): فراخوانی اتوماتیک دایرکتوری‌ها بلافاصله پس از ایجاد اتصال
            ws.onopen = () => {
                fetchDialogs();
                // پیش‌بارگذاری نامحسوس شبکه‌های تلویزیونی در بک‌گراند
                if(typeof hasScannedTV !== 'undefined' && !hasScannedTV) {
                    setTimeout(() => triggerTVScan(), 700);
                }
            };
            
            ws.onmessage = (event) => { 
                try {
                    const data = JSON.parse(event.data); 
                    if(data.type === "log") log(data.msg, data.level || "info"); 
                    if(data.type === "dialogs_list") { dialogsData = data.data; document.getElementById("chatCountBadge").innerText = dialogsData.length; filterDialogs(); }
                    if(data.type === "vc_status_check") { const dialog = dialogsData.find(d => d.id === data.chat_id); if(dialog) dialog.vc_status = data.status; filterDialogs(); }
                    
                    // هندلینگ داشبورد سراسری مدیا 
                    if(data.type === "media_status") {
                        mediaCurrentState = data.status;
                        const badge = document.getElementById("mediaStatusBadge");
                        const trackName = document.getElementById("mediaTrackName");
                        const toggleIcon = document.getElementById("mediaToggleIcon");
                        const fwdBtn = document.getElementById("btnSeekFwd");
                        const bwdBtn = document.getElementById("btnSeekBwd");
                        
                        if(data.title) trackName.innerText = data.title;
                        
                        // قفل کردن دکمه‌های Seek برای رادیو و تلویزیون زنده
                        if (data.is_radio) {
                            fwdBtn.style.opacity = "0.2"; fwdBtn.style.pointerEvents = "none";
                            bwdBtn.style.opacity = "0.2"; bwdBtn.style.pointerEvents = "none";
                        } else {
                            fwdBtn.style.opacity = "1"; fwdBtn.style.pointerEvents = "auto";
                            bwdBtn.style.opacity = "1"; bwdBtn.style.pointerEvents = "auto";
                        }
                        
                        if(data.status === "playing") { 
                            badge.innerText = data.is_radio ? "ON AIR" : "PLAYING"; 
                            badge.className = data.is_radio ? "absolute top-3 right-3 text-[8px] font-bold bg-rose-500/20 text-rose-500 px-2 py-1 rounded shadow-sm border border-rose-500/30 animate-pulse tracking-widest z-10" : "absolute top-3 right-3 text-[8px] font-mono bg-sky-500/10 text-sky-500 px-2 py-1 rounded shadow-sm border border-sky-500/30 animate-pulse z-10"; 
                            toggleIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 9v6m4-6v6m7-3a9 9 0 11-18 0 9 9 0 0118 0z" />'; 
                        } else if (data.status === "paused") { 
                            badge.innerText = "PAUSED"; 
                            badge.className = "absolute top-3 right-3 text-[8px] font-mono bg-amber-500/10 text-amber-500 px-2 py-1 rounded shadow-sm border border-amber-500/30 z-10"; 
                            toggleIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>'; 
                        } else { 
                            badge.innerText = "IDLE"; 
                            badge.className = "absolute top-3 right-3 text-[8px] font-mono bg-slate-200 dark:bg-slate-800 px-2 py-1 rounded text-slate-500 shadow-sm border border-slate-300 dark:border-slate-700 z-10"; 
                            trackName.innerText = "No Media Loaded"; 
                            toggleIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>'; 
                            fwdBtn.style.opacity = "1"; fwdBtn.style.pointerEvents = "auto";
                            bwdBtn.style.opacity = "1"; bwdBtn.style.pointerEvents = "auto";
                        }
                    }

                    if(data.type === "vc_event") {
                        if (["kicked", "closed", "left"].includes(data.event)) { 
                            showModal("UPLINK SEVERED", data.msg, true); switchUIMode('live'); updateSysStatus('STANDBY'); 
                            if (mediaRecorder && mediaRecorder.state === "recording") { blockData = true; mediaRecorder.stop(); }
                            if (data.chat_id) { const d = dialogsData.find(x => x.id === data.chat_id); if(d) d.vc_status = "inactive"; filterDialogs(); } 
                        } else if (data.event === "muted") { 
                            showModal("MICROPHONE MUTED", data.msg, true); isBotMuted = true; 
                            document.getElementById("tgMuteBtn").className = "py-3.5 rounded-2xl font-bold text-amber-600 dark:text-amber-500 bg-amber-50 dark:bg-amber-500/10 hover:bg-amber-100 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-amber-200 shadow-sm"; 
                            document.getElementById("muteIcon").className = "w-5 h-5 text-amber-500"; 
                            document.getElementById("muteIcon").innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2"></path>'; 
                            document.getElementById("muteText").innerText = "VC Muted By Admin"; 
                        }
                    }
                    // پردازش و آپدیت زنده لیست شبکه‌ها بر اساس پینگ
                    if(data.type === "tv_ping_result") {
                        if (window.updateTVNodeStatus) {
                            window.updateTVNodeStatus(data.id, data.status);
                        }
                    }
                } catch(e){} 
            };
            
            ws.onclose = (e) => { 
                if(e.code === 1008) { 
                    localStorage.removeItem("hubema_auth_token"); authToken = "";
                    showModal("ACCESS DENIED", "Security Handshake Failed. Connection Dropped.", true); 
                    const gate = document.getElementById("loginGate"), core = document.getElementById("mainCore");
                    core.classList.add("opacity-0", "pointer-events-none"); gate.style.display = "flex"; 
                    setTimeout(() => gate.classList.remove("opacity-0"), 50);
                } else { setTimeout(initWebSocketSilent, 3000); } 
            };
        }

        function fetchDialogs() { haptic(30); if(ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "fetch_dialogs" })); document.getElementById("dialogsList").innerHTML = '<div class="text-center text-xs text-slate-500 mt-10 animate-pulse">Syncing nodes...</div>'; } }

        function filterDialogs() {
            const query = document.getElementById("chatSearch").value.toLowerCase(), list = document.getElementById("dialogsList"); list.innerHTML = "";
            dialogsData.filter(d => d.title.toLowerCase().includes(query)).forEach(d => {
                const div = document.createElement("div"), icon = d.type.includes("CHANNEL") ? "📢" : "👥";
                div.className = `chat-item p-3 rounded-lg cursor-pointer flex items-center gap-3 ${activeChatId === d.id ? 'active' : ''}`;
                div.onclick = () => { haptic(20); activeChatId = d.id; document.getElementById("activeChatTitle").innerText = d.title; filterDialogs(); if(ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "set_target", chat_id: d.id, title: d.title })); } };
                let badgeHtml = "", dotClass = "bg-slate-400 dark:bg-slate-600";
                if (d.vc_status === "active") { badgeHtml = `<span class="flex items-center gap-1 text-[8px] font-bold text-emerald-500 bg-emerald-500/10 px-1.5 py-0.5 rounded-sm shadow-sm"><span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span>VC OPEN</span>`; dotClass = "bg-emerald-500 shadow-[0_0_5px_#10b981]"; } else if (d.vc_status === "inactive") { badgeHtml = `<span class="flex items-center gap-1 text-[8px] font-bold text-slate-500 bg-slate-500/10 px-1.5 py-0.5 rounded-sm"><span class="w-1.5 h-1.5 rounded-full bg-slate-500"></span>VC OFFLINE</span>`; dotClass = "bg-rose-500"; }
                div.innerHTML = `<div class="w-8 h-8 rounded-full bg-slate-200 dark:bg-slate-800 flex items-center justify-center text-xs shrink-0 relative transition-all">${icon}<div class="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full border-2 border-white dark:border-sys-panel transition-colors duration-300 ${dotClass}"></div></div><div class="flex-1 min-w-0"><div class="text-[11px] font-bold text-slate-900 dark:text-white truncate">${d.title}</div><div class="flex items-center justify-between mt-0.5"><div class="text-[9px] text-slate-500 font-mono">${d.type}</div><div>${badgeHtml}</div></div></div>`;
                list.appendChild(div);
            });
        }
        document.getElementById("chatSearch").addEventListener("input", filterDialogs);

        function setMicBtnState(state) {
            const btn = document.getElementById("micBtn"), textSpan = document.getElementById("micBtnText");
            if(state === 'active') { btn.className = "col-span-2 py-3.5 rounded-xl font-bold text-rose-600 dark:text-rose-400 bg-rose-100 dark:bg-rose-500/10 border border-rose-300 dark:border-rose-500/30 transition-all active:scale-95 flex items-center justify-center gap-2 uppercase tracking-wider text-sm mt-2 animate-pulse"; textSpan.innerText = "TERMINATE INJECTION"; } else { btn.className = "col-span-2 py-3.5 rounded-xl font-bold text-white bg-gradient-to-r from-hubema-600 to-hubema-400 hover:from-hubema-500 hover:to-hubema-300 shadow-lg shadow-hubema-500/25 transition-all active:scale-95 flex items-center justify-center gap-2 uppercase tracking-wider text-sm mt-2"; textSpan.innerText = "Establish Tunnel"; }
        }

        async function establishTunnel() {
            if(!activeChatId) { showModal("NO TARGET", "Select a target chat from the left panel before initiating Uplink.", true); return; }
            if(isConnecting) return; isConnecting = true; log("Acquiring hardware lock...", "info");
            try {
                const stream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true } });
                if(!ws || ws.readyState !== WebSocket.OPEN) { initWebSocketSilent(); await new Promise(r => setTimeout(r, 1000)); }
                if (ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify({ type: "config", mode: document.getElementById("voiceMode").value, depth: document.getElementById("hackDepth").value }));
                    let opts = MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? { mimeType: 'audio/webm;codecs=opus' } : { mimeType: 'audio/mp4;codecs=mp4a.40.2' };
                    mediaRecorder = new MediaRecorder(stream, opts);
                    mediaRecorder.ondataavailable = (event) => { if (!blockData && currentMode === 'live') { if (event.data.size > 0 && ws.bufferedAmount <= 8192) ws.send(event.data); } };
                    mediaRecorder.start(250); setMicBtnState('active'); updateSysStatus('LIVE');
                }
            } catch (err) { showModal("HARDWARE FAULT", err.message, true); log(`MIC FAULT: ${err.message}`, "error"); }
            isConnecting = false;
        }

        document.getElementById("micBtn").onclick = async () => { haptic(50); if (mediaRecorder && mediaRecorder.state === "recording") { blockData = true; mediaRecorder.stop(); updateSysStatus('STANDBY'); setMicBtnState('idle'); } else { blockData = false; await establishTunnel(); } };

        document.getElementById("tgMuteBtn").onclick = () => {
            haptic(30); if (!ws || ws.readyState !== WebSocket.OPEN || !activeChatId) return;
            isBotMuted = !isBotMuted; ws.send(JSON.stringify({ type: "toggle_mute", state: isBotMuted }));
            const icon = document.getElementById("muteIcon"), text = document.getElementById("muteText");
            if(isBotMuted) { document.getElementById("tgMuteBtn").className = "py-3.5 rounded-2xl font-bold text-amber-600 dark:text-amber-500 bg-amber-50 dark:bg-amber-500/10 hover:bg-amber-100 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-amber-200 shadow-sm"; icon.className = "w-5 h-5 text-amber-500"; icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2"></path>'; text.innerText = "VC Muted"; } else { document.getElementById("tgMuteBtn").className = "py-3.5 rounded-2xl font-bold text-slate-700 dark:text-slate-300 bg-slate-200 dark:bg-slate-800 hover:bg-slate-300 transition-all active:scale-95 flex flex-col items-center justify-center gap-1 border border-transparent shadow-sm"; icon.className = "w-5 h-5 text-emerald-500"; icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path>'; text.innerText = "VC Unmuted"; }
        };
        
        document.getElementById("killVcBtn").onclick = () => { 
            haptic([40, 60, 40]); 
            if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: "leave_vc" })); 
            if (mediaRecorder && mediaRecorder.state === "recording") mediaRecorder.stop(); 
            
            // 🔴 کِلین‌آپ کامل DOM و حافظه کلاینت (رفع تضمینی باگ فریز و گیر کردن UI)
            updateSysStatus('STANDBY'); 
            setMicBtnState('idle'); 
            activeChatId = null;
            document.getElementById("activeChatTitle").innerText = "None Selected";
            filterDialogs();
        };

        document.getElementById("voiceMode").addEventListener("change", () => { haptic(20); if(mediaRecorder && mediaRecorder.state === "recording") { ws.send(JSON.stringify({ type: "config", mode: document.getElementById("voiceMode").value, depth: document.getElementById("hackDepth").value })); } });
        document.getElementById("hackDepth").addEventListener("input", (e) => { document.getElementById('depthVal').innerText = e.target.value; });
        document.getElementById("hackDepth").addEventListener("change", () => { haptic(20); if(mediaRecorder && mediaRecorder.state === "recording") { ws.send(JSON.stringify({ type: "config", mode: document.getElementById("voiceMode").value, depth: document.getElementById("hackDepth").value })); } });

        document.getElementById("sendAiBtn").onclick = () => { haptic(20); const t = document.getElementById("aiText").value.trim(), v = document.getElementById("aiVoice").value; if (!t || !activeChatId) { showModal("NO TARGET", "Please select a chat directory from the left panel.", true); return; } if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: "tts_transmit", text: t, voice: v })); const d = new Date(), tm = `${d.getHours().toString().padStart(2,'0')}:${d.getMinutes().toString().padStart(2,'0')}`; const msgDiv = document.createElement("div"); msgDiv.className = "flex flex-col items-end animate-slide-up w-full mt-2"; msgDiv.innerHTML = `<div class="bg-gradient-to-br from-purple-500 to-purple-600 text-white text-[12px] rounded-2xl rounded-tr-sm px-3 py-2 max-w-[85%] break-words shadow-sm">${t}</div><span class="text-[9px] text-slate-400 mt-1">${tm}</span>`; document.getElementById("chatHistory").appendChild(msgDiv); document.getElementById("chatHistory").scrollTop = document.getElementById("chatHistory").scrollHeight; document.getElementById("aiText").value = ""; document.getElementById("aiText").style.height = 'auto'; } };
        document.getElementById("aiText").addEventListener("keydown", (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); document.getElementById("sendAiBtn").click(); } });
        document.getElementById("aiText").addEventListener('input', function() { this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; });
    </script>
</body>
</html>
"""
# --- END OF REPLACEMENT BLOCK 3 ---


@app_web.get("/")
async def serve_panel():
    headers = {
        "Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
        "Pragma": "no-cache",
        "Expires": "0"
    }
    if not LIVE_SYSTEM.get("is_armed"):
        return HTMLResponse(HTML_LOCKED, headers=headers)
    return HTMLResponse(HTML_PANEL, headers=headers)

@app_web.get("/live_stream.webm")
async def internal_radio_server():
    queue = asyncio.Queue()
    LIVE_SYSTEM["audio_queues"].add(queue)
    async def stream_generator():
        try:
            if LIVE_SYSTEM["header_cache"]: yield LIVE_SYSTEM["header_cache"]
            while True:
                chunk = await queue.get()
                if chunk is None: break
                yield chunk
        except: pass
        finally: LIVE_SYSTEM["audio_queues"].discard(queue)
    return StreamingResponse(stream_generator(), media_type="audio/webm")

@app_web.get("/live_stream.mp3")
async def live_stream_endpoint():
    queue = asyncio.Queue(maxsize=300)
    LIVE_SYSTEM["audio_queues"].add(queue)
    async def stream_generator():
        try:
            for chunk in list(LIVE_SYSTEM["ring_buffer"]): yield chunk
            while True:
                chunk = await queue.get()
                if chunk is None: break
                yield chunk
        except: pass
        finally: LIVE_SYSTEM["audio_queues"].discard(queue)
    return StreamingResponse(stream_generator(), media_type="audio/mpeg")

@app_web.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, token: str = Query(None)):
    await websocket.accept()
    
    async def send_ui_log(msg: str, level: str = "success"):
        try: await websocket.send_text(f'{{"type":"log", "msg":"{msg}", "level":"{level}"}}')
        except: pass

    expected_token = base64.b64encode(f"{PANEL_USERNAME}:{PANEL_PASSWORD}".encode()).decode()
    
    # 🔴 آپدیت امنیتی: استفاده از hmac برای جلوگیری از حملات Timing Attack در کرک کردن پسورد
    # به جای مقایسه ساده (token != expected_token)
    is_authenticated = False
    if token:
        try:
            is_authenticated = hmac.compare_digest(token.encode('utf-8'), expected_token.encode('utf-8'))
        except: pass

    if not is_authenticated:
        await websocket.close(code=1008)
        return
        
    if not LIVE_SYSTEM.get("is_armed"):
        await send_ui_log("SYSTEM LOCKED: Use 'پنل روشن' in bot first.", "error")
        await websocket.close(code=1008)
        return
        
    await send_ui_log("TCP Handshake Verified. Initializing Master Engine...", "success")
    ws_is_open = True
    LIVE_SYSTEM["is_streaming"] = True
    ACTIVE_WEBSOCKETS.add(websocket)
    
    # 🔴 شاهکار UX: تزریق وضعیت فعلی سیستم به کلاینت در لحظه اتصال (Hydration)
    try:
        current_status = "playing" if (LIVE_SYSTEM.get("media_playing") and not LIVE_SYSTEM.get("media_paused")) else ("paused" if LIVE_SYSTEM.get("media_paused") else "idle")
        await websocket.send_text(json.dumps({
            "type": "media_status",
            "status": current_status,
            "title": LIVE_SYSTEM.get("media_title", ""),
            "is_radio": LIVE_SYSTEM.get("media_is_radio", False)
        }))
        
        await websocket.send_text(json.dumps({
            "type": "welcome_state", 
            "state": LIVE_SYSTEM.get("welcome_enabled", False)
        }))
        
        if LIVE_SYSTEM.get("chat_id"):
            await websocket.send_text(json.dumps({
                "type": "set_target", 
                "chat_id": LIVE_SYSTEM["chat_id"], 
                "title": "Connected Node"
            }))
    except: pass
    
    fifo_fd = None
    swap_counter = 0
    current_pipe = ""
    pipe_ready_event = asyncio.Event()
    
    try:
        async def spawn_transcoder(mode: str, depth: int):
            nonlocal swap_counter, fifo_fd, current_pipe
            swap_counter += 1
            pipe_ready_event.clear()
            
            is_hot_swap = (fifo_fd is not None)
            
            old_pipe = current_pipe
            old_fd = fifo_fd
            current_pipe = f"/tmp/hacker_live_{swap_counter}_{int(time.time()*1000)}.mp3"
            
            os.mkfifo(current_pipe)
            fifo_fd = os.open(current_pipe, os.O_RDWR | os.O_NONBLOCK)
            
            # 🔴 حذف قطعی زودرس (Premature Teardown):
            # لوله قبلی (old_fd) نباید اینجا بسته شود! اگر الان ببندیم، تلگرام ارور EOF می‌گیرد و ربات را از ویس‌چت بیرون می‌اندازد.
            
            old_proc = LIVE_SYSTEM.get("transcoder_proc")
            if old_proc:
                # 🔴 استفاده از قاتل پروسه اختصاصی برای جلوگیری از یتیم شدن پروسه
                await _safe_terminate_process(old_proc)
                
            ffmpeg_cmd = [
                "ffmpeg", "-hide_banner", "-loglevel", "error",
                "-fflags", "nobuffer", "-flags", "low_delay",
                "-i", "pipe:0",            
                "-f", "mp3",               
                "-c:a", "libmp3lame",      
                "-ar", "48000", "-ac", "2", "-b:a", "128k"
            ]
            
            safe_depth = min(10, max(1, depth))
            if mode == "hacker":
                ffmpeg_cmd.extend(["-af", f"aresample=48000,asetrate=33600,atempo=1.4285,flanger=delay=10:depth={safe_depth}"])
                
            ffmpeg_cmd.append("pipe:1")

            LIVE_SYSTEM["transcoder_proc"] = await asyncio.create_subprocess_exec(
                *ffmpeg_cmd,
                stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL 
            )

            if LIVE_SYSTEM.get("chat_id") and LIVE_SYSTEM.get("mode") == "live":
                async def _resync_telegram():
                    try:
                        if not is_hot_swap:
                            await send_ui_log("Priming dynamic pipeline...", "info")
                        try:
                            await asyncio.wait_for(pipe_ready_event.wait(), timeout=3.0)
                        except asyncio.TimeoutError:
                            pass 
                            
                        new_stream = MediaStream(current_pipe, audio_parameters=AudioQuality.HIGH)
                        current_vol = CHAT_VOLUMES.get(LIVE_SYSTEM["chat_id"], 100)
                        
                        # 🔴 نشستنِ اتمیک استریم جدید در تلگرام
                        await resilient_play(LIVE_SYSTEM["chat_id"], new_stream, current_vol)
                        
                        if is_hot_swap:
                            await send_ui_log("⚡ Hot-Swap Matrix Engine Updated Seamlessly.", "success")
                        else:
                            await send_ui_log("✅ Live Matrix Synced successfully!", "success")
                            
                        # 🔴 پاکسازی پسا-سوئیچ (Post-Swap Teardown):
                        # حالا که استریم تلگرام روی لوله جدید نشست، لوله قبلی را با خیال راحت می‌بندیم و نابود می‌کنیم.
                        if old_fd is not None:
                            try: os.close(old_fd)
                            except: pass
                        if old_pipe and os.path.exists(old_pipe):
                            await asyncio.sleep(2.0)
                            try: os.remove(old_pipe)
                            except: pass
                            
                    except Exception as e:
                        await send_ui_log(f"Resync Error: {type(e).__name__} - {str(e)}", "error")
                
                asyncio.create_task(_resync_telegram())

        async def ws_reader_worker():
            try:
                while LIVE_SYSTEM["is_streaming"] and ws_is_open:
                    payload = await asyncio.wait_for(websocket.receive(), timeout=30.0)
                    
                    if "bytes" in payload:
                        if LIVE_SYSTEM.get("mode") != "live":
                            continue
                            
                        proc = LIVE_SYSTEM.get("transcoder_proc")
                        if proc and proc.stdin and not proc.stdin.is_closing():
                            try:
                                proc.stdin.write(payload["bytes"])
                                await proc.stdin.drain()
                            except Exception:
                                pass 
                                
                    elif "text" in payload:
                        try:
                            data = json.loads(payload["text"])
                            cmd_type = data.get("type")
                            
                            if cmd_type == "config":
                                mode = data.get("mode", "normal")
                                depth = int(data.get("depth", 5))
                                await send_ui_log(f"⚡ HOT-SWAP INJECTED: {mode.upper()} MODE", "ff-log")
                                await spawn_transcoder(mode, depth)
                            
                            elif cmd_type == "fetch_dialogs":
                                await send_ui_log("در حال استخراج لیست چت‌ها از سرورهای تلگرام...", "info")
                                dialogs_data = []
                                try:
                                    async for dialog in app.get_dialogs(limit=400):
                                        if dialog.chat.type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP, enums.ChatType.CHANNEL]:
                                            dialogs_data.append({
                                                "id": dialog.chat.id,
                                                "title": dialog.chat.title or "Unknown",
                                                "type": str(dialog.chat.type.name)
                                            })
                                    await websocket.send_text(json.dumps({"type": "dialogs_list", "data": dialogs_data}))
                                    await send_ui_log(f"✅ همگام‌سازی دیالوگ‌ها کامل شد ({len(dialogs_data)} تارگت اکتیو).", "success")
                                except Exception as e:
                                    await send_ui_log(f"خطا در دریافت لیست چت‌ها: {e}", "error")

                            # --- INSERT INTO ws_reader_worker inside websocket_endpoint ---
                            elif cmd_type == "toggle_welcome":
                                is_active = data.get("state", False)
                                LIVE_SYSTEM["welcome_enabled"] = is_active
                                await send_ui_log(f"🧠 هوش مصنوعی خوش‌آمدگویی {'فعال' if is_active else 'غیرفعال'} شد.", "ff-log")
                                await broadcast_ws({"type": "welcome_state", "state": is_active})
                            # --- END INSERT ---

                            elif cmd_type == "set_target":
                                target_id = int(data.get("chat_id"))
                                title = data.get("title", "Unknown")
                                LIVE_SYSTEM["chat_id"] = target_id
                                await send_ui_log(f"🎯 تارگت جدید تنظیم شد: {title}", "ff-log")

                                # 🔴 Deep Scan for Voice Chat Status (Lazy Evaluation)
                                async def scan_vc_status():
                                    try:
                                        peer = await app.resolve_peer(target_id)
                                        has_vc = False
                                        if isinstance(peer, pyrogram_raw.types.InputPeerChannel):
                                            full = await app.invoke(pyrogram_raw.functions.channels.GetFullChannel(channel=peer))
                                            if getattr(full.full_chat, "call", None): has_vc = True
                                        elif isinstance(peer, pyrogram_raw.types.InputPeerChat):
                                            full = await app.invoke(pyrogram_raw.functions.messages.GetFullChat(chat_id=peer.chat_id))
                                            if getattr(full.full_chat, "call", None): has_vc = True

                                        status = "active" if has_vc else "inactive"
                                        await websocket.send_text(json.dumps({"type": "vc_status_check", "chat_id": target_id, "status": status}))
                                    except Exception:
                                        pass
                                
                                asyncio.create_task(scan_vc_status())

                            elif cmd_type == "toggle_mute":
                                is_muted = data.get("state", False)
                                if LIVE_SYSTEM.get("chat_id"):
                                    if is_muted:
                                        await call.mute(LIVE_SYSTEM["chat_id"])
                                        await send_ui_log("🎙️ Telegram VC MUTED.", "error")
                                    else:
                                        await call.unmute(LIVE_SYSTEM["chat_id"])
                                        await send_ui_log("🔊 Telegram VC UNMUTED.", "success")
                            
                            elif cmd_type == "leave_vc":
                                if LIVE_SYSTEM.get("chat_id"):
                                    try: 
                                        await call.leave_call(LIVE_SYSTEM["chat_id"])
                                    except Exception:
                                        pass
                                    
                                    # 🔴 کِلین‌آپ کامل ماشین وضعیت (State Machine) جهت جلوگیری از باگ ارواح
                                    LIVE_SYSTEM["chat_id"] = None
                                    LIVE_SYSTEM["is_streaming"] = False
                                    LIVE_SYSTEM["standby_active"] = False
                                    LIVE_SYSTEM.update({"media_playing": False, "media_paused": False, "media_file_path": None, "media_is_radio": False, "media_is_video": False})
                                    
                                    await send_ui_log("🛑 ارتباط با سرور تلگرام به طور کامل قطع شد (Node Disconnected).", "error")
                                    await websocket.send_text(json.dumps({"type": "media_status", "status": "idle", "title": "", "is_radio": False}))
                                    await websocket.send_text(json.dumps({"type": "vc_status_check", "chat_id": 0, "status": "inactive"}))
                            
                            elif cmd_type == "switch_mode":
                                LIVE_SYSTEM["mode"] = data.get("mode")
                                if LIVE_SYSTEM["mode"] == "tts":
                                    await send_ui_log("🧠 Context Switch: NEURAL CHAT ENGAGED", "ff-log")
                                    proc = LIVE_SYSTEM.get("transcoder_proc")
                                    if proc:
                                        try: proc.kill()
                                        except: pass
                                    
                                    LIVE_SYSTEM["standby_active"] = False
                                    if "tts_event" in LIVE_SYSTEM:
                                        LIVE_SYSTEM["tts_event"].set()
                                else:
                                    await send_ui_log("🎙 Context Switch: LIVE UPLINK ENGAGED", "success")
                            
                            elif cmd_type == "tts_transmit":
                                text = data.get("text", "")
                                voice = data.get("voice", "fa-IR-FaridNeural")
                                if text and LIVE_SYSTEM.get("chat_id"):
                                    await send_ui_log(f"🧠 Synthesizing Neural Sequence...", "ff-log")
                                    asyncio.create_task(process_tts(text, voice))

                           # --- START OF REPLACEMENT BLOCK 2 ---
                            elif cmd_type == "play_media":
                                query = data.get("query", "")
                                is_video = data.get("is_video", False)
                                if query and LIVE_SYSTEM.get("chat_id"):
                                    asyncio.create_task(handle_ws_play_media(query, is_video, LIVE_SYSTEM["chat_id"]))
                                else:
                                    await send_ui_log("ابتدا یک Directory (گروه) را از پنل چپ انتخاب کنید.", "error")
                                    
                            elif cmd_type == "play_radio":
                                url = data.get("url", "")
                                name = data.get("name", "Radio Station")
                                if url and LIVE_SYSTEM.get("chat_id"):
                                    asyncio.create_task(handle_ws_play_radio(url, name, LIVE_SYSTEM["chat_id"]))
                                else:
                                    await send_ui_log("ابتدا یک Directory (گروه) را از پنل چپ انتخاب کنید.", "error")

                            # --- START OF REPLACEMENT BLOCK (TV & Ping Controller) ---
                            elif cmd_type == "play_tv":
                                url = data.get("url", "")
                                name = data.get("name", "TV Channel")
                                if url and LIVE_SYSTEM.get("chat_id"):
                                    asyncio.create_task(handle_ws_play_tv(url, name, LIVE_SYSTEM["chat_id"]))
                                else:
                                    await send_ui_log("ابتدا یک Directory (گروه) را از پنل چپ انتخاب کنید.", "error")
                                    
                            # --- START OF REPLACEMENT BLOCK (Deep Ping Debugger) ---
                            elif cmd_type == "ping_tv_network":
                                nodes = data.get("nodes", [])
                                await send_ui_log(f"📡 مانیتورینگ: آنالیز {len(nodes)} گره... (دیباگر فعال شد)", "ff-log")
                                
                                async def process_pings():
                                    sem = asyncio.Semaphore(4) 
                                    async def check_node(node):
                                        async with sem:
                                            # 🔴 بررسی هوشمند شبکه
                                            if "youtube.com" in node["url"] or "youtu.be" in node["url"] or node["url"].startswith("ytsearch"):
                                                is_valid = True
                                                probe_msg = "Auto-Cloud Bypass (Self-Healing)"
                                            else:
                                                is_valid, probe_msg = await _deep_probe_stream(node["url"])
                                            
                                            if not is_valid and ws_is_open:
                                                await send_ui_log(f"⚠️ تست گره [{node['name']}] رد شد | علت: {probe_msg}", "error")
                                                
                                            if ws_is_open:
                                                try:
                                                    await websocket.send_text(json.dumps({
                                                        "type": "tv_ping_result", 
                                                        "id": node["id"], 
                                                        "status": "online" if is_valid else "offline"
                                                    }))
                                                except: pass
                                                
                                    await asyncio.gather(*(check_node(n) for n in nodes))
                                
                                asyncio.create_task(process_pings())
                            # --- END OF REPLACEMENT BLOCK ---
                                    
                            elif cmd_type == "media_ctrl":
                                action = data.get("action")
                                if LIVE_SYSTEM.get("chat_id"):
                                    asyncio.create_task(handle_ws_media_ctrl(action, LIVE_SYSTEM["chat_id"]))
                                else:
                                    await send_ui_log("سیستم به هیچ تارگتی متصل نیست.", "error")
                            # --- END OF REPLACEMENT BLOCK 2 ---
                            
                        except Exception as e:
                            await send_ui_log(f"Command Error: {e}", "error")

            except asyncio.TimeoutError:
                pass
            except Exception:
                pass
            finally:
                proc = LIVE_SYSTEM.get("transcoder_proc")
                if proc and proc.stdin:
                    try: proc.stdin.close()
                    except: pass

        async def ffmpeg_stdout_worker():
            try:
                while LIVE_SYSTEM["is_streaming"]:
                    proc = LIVE_SYSTEM.get("transcoder_proc")
                    if not proc or not proc.stdout:
                        await asyncio.sleep(0.01)
                        continue
                        
                    try:
                        chunk = await proc.stdout.read(4096)
                        if not chunk:
                            await asyncio.sleep(0.01)
                            continue
                        
                        try:
                            await asyncio.to_thread(os.write, fifo_fd, chunk)
                            if not pipe_ready_event.is_set():
                                pipe_ready_event.set()
                        except BlockingIOError:
                            pass
                        except OSError:
                            await asyncio.sleep(0.01)
                    except Exception:
                        await asyncio.sleep(0.01)
            except Exception:
                pass

        task_ws = asyncio.create_task(ws_reader_worker())
        task_out = asyncio.create_task(ffmpeg_stdout_worker())
        await asyncio.gather(task_ws, task_out) 

    except WebSocketDisconnect:
        ws_is_open = False
    except Exception as e:
        await send_traceback_to_me(f"WS FATAL ERROR: {str(e)}")
    finally:
        ACTIVE_WEBSOCKETS.discard(websocket)
        LIVE_SYSTEM["is_streaming"] = False
        ws_is_open = False
        
        # 🔴 قتل بی‌رحمانه پروسه FFmpeg هنگام قطع سوکت کاربر (Zombie Guard)
        proc = LIVE_SYSTEM.get("transcoder_proc")
        if proc:
            await _safe_terminate_process(proc)
            LIVE_SYSTEM["transcoder_proc"] = None

        if fifo_fd is not None:
            try: os.close(fifo_fd)
            except: pass
            
        if current_pipe and os.path.exists(current_pipe):
            try: os.remove(current_pipe)
            except: pass

        try: await websocket.close(code=1011)
        except: pass
            
        if LIVE_SYSTEM.get("chat_id"):
            try:
                standby_stream = MediaStream("/tmp/standby.mp3", audio_parameters=AudioQuality.HIGH)
                await call.change_stream(LIVE_SYSTEM["chat_id"], standby_stream)
            except Exception:
                pass

# --- START OF REPLACEMENT BLOCK 3 (Core Kernel Handler with Dual Text/Voice Engine) ---


async def deep_tracer_log(step: str, uid: int, detail: str):
    """دیباگر هسته با سیستم ارسال گارانتی شده"""
    time_str = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
    icons = {"BOOT": "🚀", "DETECT": "📡", "JOIN": "📥", "LEAVE": "📤", "CACHE": "🗄", "TIMER": "⏱", "CHECK": "🔍", "MATRIX": "🧠", "TTS": "🗣", "TEXT": "💬", "WARN": "⚠️", "SUCCESS": "✅", "ABORT": "🛑", "ERROR": "❌"}
    icon = icons.get(step, "▪️")
    msg = f"**{icon} [STEP: {step}]** `{time_str}`\n👤 **User ID:** `{uid}`\n📝 **Trace:** {detail}"
    try: await app.send_message("me", msg)
    except Exception: pass
    print(f"[{step}] UID: {uid} -> {detail}")

@app.on_raw_update(group=2)
async def vc_raw_update_handler(client: Client, update, users, chats):
    """شنود عمیق با موتور پردازش دوگانه (Dual Engine) برای متن و صدا"""
    updates_list = getattr(update, "updates", [update])

    for inner_update in updates_list:
        if not isinstance(inner_update, pyrogram_raw.types.UpdateGroupCallParticipants):
            continue

        # بررسی اینکه حداقل یکی از آپشن‌های خوش‌آمدگویی روشن باشد
        is_voice_welcome = LIVE_SYSTEM.get("welcome_enabled", False)
        is_text_welcome = LIVE_SYSTEM.get("welcome_text_enabled", False)
        if not (is_voice_welcome or is_text_welcome):
            return

        # سیستم Auto-Heal (حفظ شده از نسخه قبل)
        if not LIVE_SYSTEM.get("chat_id"):
            if active_streams_map:
                recovered_chat_id = list(active_streams_map.keys())[0]
                LIVE_SYSTEM.update({"chat_id": recovered_chat_id, "is_streaming": True})
                await deep_tracer_log("BOOT", 0, f"تارگت از روی نقشه حافظه (RAM) بازیابی و Sync شد: {recovered_chat_id}")
            else:
                # 🔴 فیکس اسپم پی‌وی: لاگ مزاحم حذف شد. وقتی سیستم کاملاً بی‌کار است، در سکوت متوقف می‌شود.
                return

        target_chat_id = LIVE_SYSTEM.get("chat_id")
        if not target_chat_id:
            return

        for participant in inner_update.participants:
            if not hasattr(participant, 'peer') or not isinstance(participant.peer, pyrogram_raw.types.PeerUser):
                continue
                
            user_id = participant.peer.user_id
            
            if getattr(participant, 'left', False):
                welcome_matrix.active_participants.discard(user_id)
                await deep_tracer_log("LEAVE", user_id, "خروج کاربر از ویس‌چت تایید و از رم پاک شد.")
                continue
                
            if user_id not in welcome_matrix.active_participants:
                welcome_matrix.active_participants.add(user_id)
                await deep_tracer_log("JOIN", user_id, "سیگنال ورود کاربر دریافت شد. شروع زنجیره شناسایی...")
                
                raw_name = ""
                is_bot = False
                
                user_data = users.get(user_id)
                if user_data:
                    await deep_tracer_log("CACHE", user_id, "کاربر در دیتابیس لحظه‌ای (Raw Users) یافت شد.")
                    is_bot = getattr(user_data, 'bot', False)
                    if not is_bot:
                        raw_name = getattr(user_data, 'first_name', '') or getattr(user_data, 'title', '')
                else:
                    await deep_tracer_log("CACHE", user_id, "پراکسی کش خالی بود! درخواست مستقیم به API تلگرام (Fetch)...")
                    try:
                        fetched_user = await client.get_users(user_id)
                        is_bot = fetched_user.is_bot
                        if not is_bot:
                            raw_name = fetched_user.first_name or ""
                        await deep_tracer_log("CACHE", user_id, f"هویت دریافت شد: {raw_name}")
                    except Exception as fetch_err:
                        await deep_tracer_log("ERROR", user_id, f"خطا در دریافت هویت: {fetch_err}")
                        raw_name = "دوست عزیز" 

                if is_bot:
                    await deep_tracer_log("ABORT", user_id, "تارگت، ربات (Bot) تشخیص داده شد. نادیده گرفته شد.")
                    continue

                # --- START OF REPLACEMENT BLOCK (Asynchronous Split Timing Workflow) ---
                async def delayed_welcome_workflow(uid: int, name: str):
                    try:
                        await deep_tracer_log("TIMER", uid, f"استارت پردازش هوشمند: متن (1s) / ویس (4s) برای {name}...")
                        
                        # 🔴 گام اول: توقف 1 ثانیه‌ای اختصاصی برای حباب متنی
                        await asyncio.sleep(1.0)
                        
                        if uid not in welcome_matrix.active_participants:
                            await deep_tracer_log("ABORT", uid, "کاربر قبل از 1 ثانیه خارج شد.")
                            return

                        is_voice_active = LIVE_SYSTEM.get("welcome_enabled", False)
                        is_text_active = LIVE_SYSTEM.get("welcome_text_enabled", False)

                        if not (is_voice_active or is_text_active):
                            return

                        # تولید دیالوگ یکپارچه در ثانیه 1 (جلوگیری از اعمال دوبار Cooldown)
                        welcome_text = await welcome_matrix.generate_welcome(uid, name)
                        if not welcome_text:
                            await deep_tracer_log("ABORT", uid, "کاربر در محدودیت زمانی 24 ساعته (Cooldown) قرار دارد.")
                            return
                            
                        # اجرای مسیر متن (دقیقاً در ثانیه 1)
                        if is_text_active:
                            await deep_tracer_log("TEXT", uid, "تزریق حباب متنی روی Overlay در ثانیه 1...")
                            try:
                                emojis = ["🌹", "🎉", "✨", "❤️", "🔥", "💎", "🎊", "🥂"]
                                selected_emoji = random.choice(emojis)
                                display_name = name if name else "دوست عزیز"
                                final_msg = f"{selected_emoji} {display_name} عزیز، خوش اومدی"
                                if len(final_msg) > 125:
                                    final_msg = final_msg[:122] + "..."
                                
                                chat_target = LIVE_SYSTEM.get("chat_id")
                                peer = await client.resolve_peer(chat_target)
                                is_channel = isinstance(peer, pyrogram_raw.types.InputPeerChannel)
                                
                                if is_channel:
                                    full_chat = await client.invoke(pyrogram_raw.functions.channels.GetFullChannel(channel=peer))
                                else:
                                    full_chat = await client.invoke(pyrogram_raw.functions.messages.GetFullChat(chat_id=peer.chat_id))
                                    
                                group_call = getattr(full_chat.full_chat, "call", None)
                                
                                if group_call and hasattr(group_call, "id") and hasattr(group_call, "access_hash"):
                                    input_call = pyrogram_raw.types.InputGroupCall(
                                        id=group_call.id,
                                        access_hash=group_call.access_hash
                                    )
                                    await client.invoke(
                                        pyrogram_raw.functions.phone.SendGroupCallMessage(
                                            call=input_call,
                                            message=pyrogram_raw.types.TextWithEntities(text=final_msg, entities=[]),
                                            random_id=random.randint(1000000, 999999999)
                                        )
                                    )
                                    await deep_tracer_log("SUCCESS", uid, "حباب متنی مستقیماً به ویدیوچت تزریق شد.")
                            except Exception as text_err:
                                await deep_tracer_log("WARN", uid, f"سوییچ به Fallback متنی. علت: {type(text_err).__name__}")
                                try:
                                    sent_msg = await client.send_message(chat_id=chat_target, text=final_msg)
                                    async def fallback_destruct(msg_to_delete, delay=5.0):
                                        await asyncio.sleep(delay)
                                        try: await msg_to_delete.delete()
                                        except: pass
                                    asyncio.create_task(fallback_destruct(sent_msg, 5.0))
                                except: pass

                        # 🔴 گام دوم: توقف 3 ثانیه دیگر (مجموعاً 4 ثانیه) اختصاصی برای پخش Voice
                        if is_voice_active:
                            await asyncio.sleep(3.0)
                            
                            # ارزیابی مجدد پایداری حضور کاربر و وضعیت استریم پس از 4 ثانیه
                            if uid not in welcome_matrix.active_participants:
                                await deep_tracer_log("ABORT", uid, "کاربر بین ثانیه 1 تا 4 خارج شد. لغو عملیات صوتی.")
                                return
                                
                            if not LIVE_SYSTEM.get("is_streaming"):
                                await deep_tracer_log("WARN", uid, "استریم قطع شد! لغو پخش ویس.")
                                return
                                
                            await deep_tracer_log("TTS", uid, "ارسال پیام تولید شده به موتور صوتی در ثانیه 4...")
                            LIVE_SYSTEM["standby_active"] = False
                            await process_tts(welcome_text, "fa-IR-FaridNeural")

                    except Exception as err:
                        err_trace = traceback.format_exc()
                        await deep_tracer_log("ERROR", uid, f"کرش بحرانی در موتور خوش‌آمدگویی:\n`{err_trace}`")
# --- END OF REPLACEMENT BLOCK ---

                asyncio.create_task(delayed_welcome_workflow(user_id, raw_name))
# --- END OF REPLACEMENT BLOCK 3 ---
# --- START OF REPLACEMENT BLOCK (Live TV Matrix Database) ---
# پایگاه داده استاتیک شبکه‌ها جهت پردازش فوق‌سریع در لایه پایتون (O(1) Time Complexity)
# --- START OF REPLACEMENT BLOCK 1 (Python TV Nodes: The Ultimate Matrix) ---
# --- START OF REPLACEMENT BLOCK (Global Matrix Database) ---
# 🔴 توجه بسیار مهم: این متغیر باید کاملاً چسبیده به سمت چپ خط باشد (بدون هیچ Space یا Tab)
TV_MATRIX_NODES = {
    # 🌐 NEWS & POLITICS (Auto-Heal YouTube)
    "n_bbc": {"name": "BBC Persian", "url": "https://www.youtube.com/@BBCPersian/live"},
    "n_intl": {"name": "Iran Intl", "url": "https://www.youtube.com/@iranintltv/live"},
    "n_afghan": {"name": "Afghan Intl", "url": "ytsearch1:Afghanistan International Live"},
    "n_voa": {"name": "VOA Farsi", "url": "https://www.youtube.com/@VOAFarsi/live"},
    "n_farda": {"name": "Radio Farda", "url": "https://www.youtube.com/@RadioFarda/live"},
    "n_manoto": {"name": "Manoto TV", "url": "ytsearch1:Manoto Live پخش زنده"},
    "n_pars": {"name": "Pars TV", "url": "ytsearch1:Pars TV Live پخش زنده"},
    "n_kalemeh": {"name": "Kalemeh TV", "url": "ytsearch1:Kalemeh TV Live"},
    "n_simaye": {"name": "Simaye Azadi", "url": "ytsearch1:Simaye Azadi Live پخش زنده"},
    "n_channel1": {"name": "Channel One", "url": "ytsearch1:Kanal Yek TV Live شهرام همایون"},
    "n_irane_farda": {"name": "Irane Farda", "url": "ytsearch1:Irane Farda TV Live پخش زنده"},
    "n_euronews_fa": {"name": "Euronews FA", "url": "ytsearch1:Euronews Farsi Live"},

    # 💎 GEM NETWORK (Self-Healing Spider)
    "g_tv": {"name": "GEM TV", "url": "ytsearch1:GEM TV Live پخش زنده"},
    "g_series": {"name": "GEM Series", "url": "ytsearch1:GEM Series Live پخش زنده"},
    "g_movie": {"name": "GEM Movies", "url": "ytsearch1:GEM Movies Live پخش زنده"},
    "g_bolly": {"name": "GEM Bollywood", "url": "ytsearch1:GEM Bollywood Live پخش زنده"},
    "g_classic": {"name": "GEM Classic", "url": "ytsearch1:GEM Classic Live پخش زنده"},
    "g_kids": {"name": "GEM Kids", "url": "ytsearch1:GEM Kids Live پخش زنده"},
    "g_junior": {"name": "GEM Junior", "url": "ytsearch1:GEM Junior Live پخش زنده"},
    "g_life": {"name": "GEM Life", "url": "ytsearch1:GEM Life Live پخش زنده"},
    "g_food": {"name": "GEM Food", "url": "ytsearch1:GEM Food Live پخش زنده"},
    "g_rubix": {"name": "GEM Rubix", "url": "ytsearch1:GEM Rubix Live پخش زنده"},
    "g_river": {"name": "GEM River", "url": "ytsearch1:GEM River Live پخش زنده"},
    "g_drama": {"name": "GEM Drama", "url": "ytsearch1:GEM Drama Live پخش زنده"},

    # 🟣 PERSIANA NETWORK (Self-Healing Spider)
    "p_one": {"name": "Persiana One", "url": "ytsearch1:Persiana One Live پخش زنده"},
    "p_family": {"name": "Persiana Family", "url": "ytsearch1:Persiana Family Live پخش زنده"},
    "p_cinema": {"name": "Persiana Cinema", "url": "ytsearch1:Persiana Cinema Live پخش زنده"},
    "p_music": {"name": "Persiana Music", "url": "ytsearch1:Persiana Music Live پخش زنده"},
    "p_rap": {"name": "Persiana Rap", "url": "ytsearch1:Persiana Rap Live پخش زنده"},
    "p_comedy": {"name": "Persiana Comedy", "url": "ytsearch1:Persiana Comedy Live پخش زنده"},
    "p_sports": {"name": "Persiana Sports", "url": "ytsearch1:Persiana Sports Live پخش زنده"},
    "p_junior": {"name": "Persiana Junior", "url": "ytsearch1:Persiana Junior Live پخش زنده"},
    "p_nostalgia": {"name": "Persiana Nostalgia", "url": "ytsearch1:Persiana Nostalgia Live پخش زنده"},
    "p_korea": {"name": "Persiana Korea", "url": "ytsearch1:Persiana Korea Live پخش زنده"},

    # 🎵 MUSIC & ENTERTAINMENT (Auto-Heal YouTube)
    "m_pmc": {"name": "PMC Music", "url": "ytsearch1:PMC Music Live پخش زنده"},
    "m_rjtv": {"name": "Radio Javan TV", "url": "ytsearch1:Radio Javan TV Live"},
    "m_tapesh": {"name": "Tapesh TV", "url": "ytsearch1:Tapesh TV Live پخش زنده"},
    "m_avang": {"name": "Avang TV", "url": "ytsearch1:Avang TV Live پخش زنده"},
    "m_navahang": {"name": "Navahang TV", "url": "ytsearch1:Navahang TV Live پخش زنده"},
    "m_caltex": {"name": "Caltex TV", "url": "ytsearch1:Caltex TV Live پخش زنده"},

    # 🟠 GENERAL ENTERTAINMENT & MOVIES
    "e_mbc": {"name": "MBC Persia", "url": "ytsearch1:MBC Persia Live پخش زنده"},
    "e_4u": {"name": "4U TV", "url": "ytsearch1:4U TV Live پخش زنده"},
    "e_itn": {"name": "ITN TV", "url": "ytsearch1:ITN TV Live پخش زنده حمید شب خیز"},
    "e_khatereh": {"name": "Khatereh TV", "url": "ytsearch1:Khatereh TV Live پخش زنده"},
    "e_ava_family": {"name": "Ava Family", "url": "ytsearch1:Ava Family Live پخش زنده"},
    "e_ava_series": {"name": "Ava Series", "url": "ytsearch1:Ava Series Live پخش زنده"},
    "e_omide_iran": {"name": "Omide Iran", "url": "ytsearch1:Omide Iran TV Live پخش زنده"},
    "e_ifilm": {"name": "iFilm Farsi", "url": "ytsearch1:iFilm Farsi Live پخش زنده"},

    # 🟢 IRIB & DOMESTIC (State TV - Auto-Heal)
    "irib_1": {"name": "Shabake 1", "url": "ytsearch1:شبکه یک پخش زنده"},
    "irib_2": {"name": "Shabake 2", "url": "ytsearch1:شبکه دو پخش زنده"},
    "irib_3": {"name": "Shabake 3", "url": "ytsearch1:شبکه سه پخش زنده"},
    "irib_4": {"name": "Shabake 4", "url": "ytsearch1:شبکه چهار پخش زنده"},
    "irib_5": {"name": "Shabake 5", "url": "ytsearch1:شبکه پنج تهران پخش زنده"},
    "irib_khabar": {"name": "Shabake Khabar", "url": "ytsearch1:شبکه خبر پخش زنده"},
    "irib_varzesh": {"name": "Varzesh TV", "url": "ytsearch1:شبکه ورزش پخش زنده"},
    "irib_nasim": {"name": "Shabake Nasim", "url": "ytsearch1:شبکه نسیم پخش زنده"},
    "irib_pooya": {"name": "Shabake Pooya", "url": "ytsearch1:شبکه پویا پخش زنده"},
    "irib_mostanad": {"name": "Mostanad TV", "url": "ytsearch1:شبکه مستند پخش زنده"},
    "irib_namayesh": {"name": "Namayesh TV", "url": "ytsearch1:شبکه نمایش پخش زنده"},
    "irib_salamat": {"name": "Salamat TV", "url": "ytsearch1:شبکه سلامت پخش زنده"},

    # 🕌 RELIGION
    "r_mohabat": {"name": "Mohabat TV", "url": "ytsearch1:Mohabat TV Live پخش زنده"},
    "r_nejat": {"name": "Nejat TV", "url": "ytsearch1:Nejat TV Live پخش زنده"},
    "r_imam": {"name": "Imam Hossein TV", "url": "ytsearch1:Imam Hossein TV Live پخش زنده"},
    "r_ganje": {"name": "Ganje Hozoor", "url": "ytsearch1:گنج حضور پرویز شهبازی پخش زنده"},

    # 🌍 GLOBAL NEWS & US & TR
    "gb1": {"name": "Al Jazeera", "url": "https://www.youtube.com/@aljazeeraenglish/live"},
    "gb2": {"name": "Sky News UK", "url": "https://www.youtube.com/@SkyNews/live"},
    "gb3": {"name": "DW News", "url": "https://www.youtube.com/@dwnews/live"},
    "gb4": {"name": "France 24", "url": "https://www.youtube.com/@France24_en/live"},
    "gb5": {"name": "Euronews", "url": "https://www.youtube.com/@euronews/live"},
    "us1": {"name": "ABC News", "url": "https://www.youtube.com/@ABCNews/live"},
    "us2": {"name": "NBC News", "url": "https://www.youtube.com/@NBCNews/live"},
    "us3": {"name": "CBS News", "url": "https://www.youtube.com/@CBSNews/live"},
    "us5": {"name": "NASA TV", "url": "https://www.youtube.com/@NASA/live"},
    "tr1": {"name": "TRT 1", "url": "https://tv-trt1.medya.trt.com.tr/master.m3u8"},
    "tr2": {"name": "TRT Haber", "url": "https://www.youtube.com/@trthaber/live"},
    "tr5": {"name": "Show TV", "url": "https://www.youtube.com/@ShowTV/live"}
}
# --- END OF REPLACEMENT BLOCK ---
    # --- END OF REPLACEMENT BLOCK 1 ---
# --- START OF REPLACEMENT BLOCK (Anti-Duplicate Command Cache) ---
# 🔴 شاهکار مهندسی: کش فوق‌سریع برای فیلتر کردن آپدیت‌های تکراری تلگرام (جلوگیری از اجرای ۲ بار دستور)
PROCESSED_COMMANDS_CACHE = {}

@app.on_message(is_auth & (filters.text | filters.caption), group=1)
async def command_router(client: Client, message: Message):
    global PROCESSED_COMMANDS_CACHE
    
    # 1. گارد ضد تکرار (Deduplication Guard)
    msg_id = message.id
    now = time.time()
    if msg_id in PROCESSED_COMMANDS_CACHE:
        return # اگر پیام تکراری بود، در نطفه خفه می‌شود
    
    PROCESSED_COMMANDS_CACHE[msg_id] = now
    # پاکسازی خودکار پیام‌های قدیمی‌تر از 10 ثانیه از کش رم برای جلوگیری از نشت حافظه (Memory Leak)
    PROCESSED_COMMANDS_CACHE = {k: v for k, v in PROCESSED_COMMANDS_CACHE.items() if now - v < 10}

    raw_text = message.text or message.caption or ""
    norm_text = normalize_farsi(raw_text).strip().lower()
# --- END OF REPLACEMENT BLOCK ---
    
    # 🔴 پاکسازی نویزهای متنی و نیم‌فاصله‌ها (Zero-width non-joiner) برای دقت ۱۰۰ درصدی
    norm_text = re.sub(r'[\u200c\s]+', ' ', norm_text)
    
    chat_id = message.chat.id
    is_pv = (message.chat.type == enums.ChatType.PRIVATE)
    
    # 🔴 قلب تپنده Smart Routing: اگر ادمین در پی‌وی دستور بدهد، دستور روی گروه هدف اعمال می‌شود
    target_chat_id = LIVE_SYSTEM.get("chat_id") if is_pv else chat_id

    if "پنل" in norm_text or "لایو" in norm_text:
        await send_traceback_to_me(f"👁‍🗨 دستور دریافت شد:\n`{raw_text}`")

    # 🔴 یابنده دستورات بسیار مقاوم (Bulletproof Command Parser)
    cmd_type = None
    query = ""
    is_video = False

    # 1. جستجوی اختصاصی ویدیو
    if norm_text.startswith(("پخش فیلم ", "play video ")):
        cmd_type = "cloud_play"
        query = raw_text.split(" ", 2)[-1].strip()
        is_video = True
        
    # 2. جستجوی اختصاصی آهنگ
    elif norm_text.startswith(("پخش آهنگ ", "play music ")):
        cmd_type = "cloud_play"
        query = raw_text.split(" ", 2)[-1].strip()
        is_video = False

        
    # --- NEW: TV Matrix Smart Parser ---
    elif norm_text in ["لیست تلوزیون", "لیست تلویزیون"]:
        cmd_type = "tv_list"
    elif norm_text.startswith(("پخش تلوزیون ", "پخش تلویزیون ")):
        cmd_type = "tv_play"
        # استخراج آیدی دقیق (مثلاً ir4) با حذف اسپیس‌ها و حروف اضافه
        query = raw_text.split(" ", 2)[-1].strip().lower()
    # ------------------------------------
    elif norm_text in ["پخش پروفایل", "play profile"]: 
            cmd_type = "profile_play"
    
    elif norm_text.startswith(("پروفایل اینستا", "profile ig")): 
            cmd_type = "ig_profile"
            urls = re.findall(r'(https?://(?:www\.)?instagram\.com/[^\s]+)', raw_text)
            query = urls[0] if urls else re.sub(r'(?i)^(پروفایل\s*اینستا|profile\s*ig)[\s\u200c]*', '', raw_text).strip()
            if not query and message.reply_to_message:
                query = message.reply_to_message.text or message.reply_to_message.caption or ""

    elif norm_text.startswith(("دانلود اینستا", "dl ig")): 
            cmd_type = "ig_download"
            urls = re.findall(r'(https?://(?:www\.)?instagram\.com/[^\s]+)', raw_text)
            query = urls[0] if urls else re.sub(r'(?i)^(دانلود\s*اینستا|dl\s*ig)[\s\u200c]*', '', raw_text).strip()
            if not query and message.reply_to_message:
                query = message.reply_to_message.text or message.reply_to_message.caption or ""

    elif norm_text.startswith(("پخش اینستا", "play ig")): 
            cmd_type = "ig_play"
            urls = re.findall(r'(https?://(?:www\.)?instagram\.com/[^\s]+)', raw_text)
            query = urls[0] if urls else re.sub(r'(?i)^(پخش\s*اینستا|play\s*ig)[\s\u200c]*', '', raw_text).strip()
            if not query and message.reply_to_message:
                query = message.reply_to_message.text or message.reply_to_message.caption or ""
        # --- END OF REPLACEMENT BLOCK ---

    elif norm_text.startswith(("پخش ", "play ")):
        cmd_type = "cloud_play"
        query = raw_text.split(" ", 1)[-1].strip()
        is_video = False
        
    # --- START OF REPLACEMENT BLOCK (Command Parser Update) ---
    elif norm_text in ["توقف", "pause", "مکث"]: cmd_type = "pause"
    elif norm_text in ["ادامه", "resume"]: cmd_type = "resume"
    elif norm_text in ["قطع", "پایان", "stop"]: cmd_type = "stop"
    elif norm_text in ["پینگ", "ping"]: cmd_type = "ping"
    elif norm_text in ["پنل روشن", "panel on"]: cmd_type = "panel_on"
    elif norm_text in ["پنل خاموش", "panel off"]: cmd_type = "panel_off"
    elif norm_text in ["live", "لایو"]: cmd_type = "live"
    
    # --- START OF REPLACEMENT BLOCK (Meow Bot Toggles) ---
    elif norm_text == "ادمین منیجر روشن": cmd_type = "admin_manager_on"
    elif norm_text == "ادمین منیجر خاموش": cmd_type = "admin_manager_off"
    elif norm_text.startswith(("معاف از بررسی", "معاف از برسی")): cmd_type = "admin_exempt"
    elif norm_text.startswith("حذف معافیت"): cmd_type = "admin_unexempt"
    elif norm_text in ["وایت لیست", "لیست سفید", "whitelist"]: cmd_type = "show_whitelist"
    # 👇 این سه خط را دقیقاً اینجا اضافه کنید 👇
    elif norm_text in ["اخبار روشن", "خبر روشن"]: cmd_type = "news_on"
    elif norm_text in ["اخبار خاموش", "خبر خاموش"]: cmd_type = "news_off"
    elif norm_text in ["اخبار", "خبر"]: cmd_type = "news_now"
    elif norm_text in ["کامل", "بیشتر", "جزئیات خبر", "متن کامل", "full", "more"]: cmd_type = "news_full"
    # این دو خط را در بین سایر elif های مربوط به شناسایی دستور (مثلا زیر دستور ping یا panel on) اضافه کنید:
    elif norm_text in ["دیتیل", "detail", "جزئیات", "info"]: cmd_type = "media_detail"
    elif norm_text in ["راهنما", "help", "دستورات", "منو"]: cmd_type = "help_menu"
    # 🔴 اضافه شدن دستورات سیستم هوشمند پاکسازی ربات سرگرمی
    elif norm_text == "حذف میو روشن": cmd_type = "meow_cleaner_on"
    elif norm_text == "حذف میو خاموش": cmd_type = "meow_cleaner_off"
    # --- END OF REPLACEMENT BLOCK ---

    # --- START OF REPLACEMENT BLOCK 1 (Command Parser) ---
    elif norm_text in ["خوش آمد ویس روشن", "خوش آمد ویس آقا روشن", "خوش آمد ویس خانوم روشن", "خوش آمد ویس خاموش"]:
        if norm_text == "خوش آمد ویس روشن": cmd_type = "welcome_voice_on"
        elif norm_text == "خوش آمد ویس آقا روشن": cmd_type = "welcome_voice_male_on"
        elif norm_text == "خوش آمد ویس خانوم روشن": cmd_type = "welcome_voice_female_on"
        elif norm_text == "خوش آمد ویس خاموش": cmd_type = "welcome_voice_off"
    elif norm_text == "خوش آمد متن روشن": cmd_type = "welcome_text_on"
    elif norm_text == "خوش آمد متن خاموش": cmd_type = "welcome_text_off"
    # --- END OF REPLACEMENT BLOCK 1 ---
    # --- START OF REPLACEMENT BLOCK (Advanced Command Parser) ---
    elif norm_text in ["پخش پروفایل", "play profile"]: cmd_type = "profile_play"
    elif norm_text in ["پخش", "play"]: cmd_type = "reply_play"
    
    # 🔴 دستورات داینامیک جلو و عقب بردن زمان (Seek)
    elif re.match(r"(\d+)\s*(جلو|عقب)", norm_text):
        match = re.match(r"(\d+)\s*(جلو|عقب)", norm_text)
        cmd_type = "seek_time"
        offset = int(match.group(1))
        query = offset if match.group(2) == "جلو" else -offset

    # 🔴 دستورات باز و بسته کردن لایو دوربین/تصویر
    elif norm_text in ["تصویر بسته", "بستن تصویر", "video off"]: cmd_type = "video_off"
    elif norm_text in ["تصویر باز", "باز کردن تصویر", "video on"]: cmd_type = "video_on"

    elif norm_text.startswith(("ولوم ", "vol ")):
        cmd_type = "volume"
        try: query = int(norm_text.split()[-1])
        except: cmd_type = None
    # --- END OF REPLACEMENT BLOCK ---

    # --- INSERT THESE INTO YOUR command_router PARSER BLOCK ---
    elif norm_text == "پیکربندی": cmd_type = "config_on"
    elif norm_text == "لغو پیکربندی": cmd_type = "config_off"
    elif norm_text == "وضعیت": cmd_type = "sys_status"
    elif norm_text == "آنتی فحش روشن": cmd_type = "antiswear_on"
    elif norm_text == "آنتی فحش خاموش": cmd_type = "antiswear_off"
    elif norm_text == "آنتی اسپم روشن": cmd_type = "antispam_on"
    elif norm_text == "آنتی اسپم خاموش": cmd_type = "antispam_off"
    elif norm_text.startswith("سکوت"): cmd_type = "force_mute"
    elif norm_text.startswith("حذف سکوت"): cmd_type = "force_unmute"
    # --------------------------------------------------------

    # --------------------------------------------------------

    if not cmd_type:
        return 

    # 🔴 آپدیت شاهکار مهندسی: اولویت‌بندی گاردهای مسیر و پیکربندی (جلوگیری از دراپ شدن سایلنت)
    
    # 1. گارد مسیر: بررسی اتصال به گروه (اگر در پی‌وی ربات دستور دادید)
    if is_pv and not target_chat_id and cmd_type not in ["panel_on", "panel_off", "ping"]:
        try: await client.send_message(chat_id, "⚠️ **خطای مسیر:** ربات در حال حاضر به هیچ گروهی متصل نیست!\nابتدا در گروه مورد نظر دستور `پنل روشن` را بفرستید.")
        except: pass
        return

    # 2. گارد پیکربندی: بررسی اجازه فعالیت در گروه
    if cmd_type not in ["config_on", "ping", "panel_on", "panel_off"]:
        if target_chat_id not in ADMIN_MANAGER.setdefault("configured_chats", set()):
            # 🔴 آپدیت: به جای سایلنت ماندن، یک لاگ برای شما در پی‌وی می‌فرستد تا گیج نشوید!
            await send_traceback_to_me(f"🛑 دستور `{norm_text}` رد شد.\nعلت: گروه هدف هنوز در ربات پیکربندی نشده است. لطفاً کلمه `پیکربندی` را بفرستید.")
            return

    if getattr(message.from_user, "is_self", False):
        try: 
            await message.delete()
        except: 
            pass

    try:
        status_msg = await client.send_message(chat_id, "⏳ در حال پردازش سیستم...")
    except Exception as err:
        await send_traceback_to_me(f"🔴 عدم دسترسی ارسال پیام در چت `{chat_id}`:\n{err}")
        return

    # 🔴 اجرای اتمیک و تفکیک‌شده دستورات با اعمال روی Target Chat
    try:
        if cmd_type == "panel_on":
            LIVE_SYSTEM["is_armed"] = True
            await safe_edit_text(status_msg, "✅ سیستم امنیتی غیرفعال و پنل وب استریم **مسلح** شد.\nمنتظر اتصال اپراتور...")
            
        elif cmd_type == "panel_off":
            LIVE_SYSTEM["is_armed"] = False
            LIVE_SYSTEM["is_streaming"] = False
            if LIVE_SYSTEM.get("chat_id"):
                try: await call.leave_call(LIVE_SYSTEM["chat_id"])
                except: pass
                LIVE_SYSTEM["chat_id"] = None
            proc = LIVE_SYSTEM.get("transcoder_proc")
            if proc:
                try: proc.kill(); asyncio.create_task(proc.wait()) 
                except: pass
                LIVE_SYSTEM["transcoder_proc"] = None
            await safe_edit_text(status_msg, "🛑 پنل وب استریم **قفل** شد.\nربات از ویس‌چت خارج شد و پروسه‌ها پاکسازی شدند.")

        # --- INSERT THESE INTO YOUR command_router EXECUTION BLOCK ---
        elif cmd_type == "config_on":
            ADMIN_MANAGER.setdefault("configured_chats", set()).add(target_chat_id)
            await safe_edit_text(status_msg, "✅ **[ سیستم مرکزی ]**\nگروه با موفقیت در هسته ربات پیکربندی شد. از این پس ربات در این گروه فعال است.")

        elif cmd_type == "config_off":
            ADMIN_MANAGER.setdefault("configured_chats", set()).discard(target_chat_id)
            await safe_edit_text(status_msg, "🛑 **[ سیستم مرکزی ]**\nپیکربندی لغو شد. ربات دیگر در این گروه به هیچ دستوری پاسخ نخواهد داد.")

        elif cmd_type == "antiswear_on":
            ADMIN_MANAGER.setdefault("anti_swear", set()).add(target_chat_id)
            await safe_edit_text(status_msg, "🤬 **[ Fosh Guard Engine ]** `ONLINE`\n━━━━━━━━━━━━━━━━━━\nسیستم برخورد با کلمات رکیک فعال شد. مجازات قطعی پس از ۳ اخطار اعمال می‌گردد.")

        elif cmd_type == "antiswear_off":
            ADMIN_MANAGER.setdefault("anti_swear", set()).discard(target_chat_id)
            await safe_edit_text(status_msg, "🛑 **[ Fosh Guard Engine ]** `OFFLINE`\nآنتی فحش غیرفعال شد.")

        elif cmd_type == "antispam_on":
            ADMIN_MANAGER.setdefault("anti_spam", set()).add(target_chat_id)
            await safe_edit_text(status_msg, "⚡️ **[ Anti-Flood Engine ]** `ONLINE`\n━━━━━━━━━━━━━━━━━━\nمحافظت در برابر ارسال پیام‌های رگباری فعال شد.")

        elif cmd_type == "antispam_off":
            ADMIN_MANAGER.setdefault("anti_spam", set()).discard(target_chat_id)
            await safe_edit_text(status_msg, "🛑 **[ Anti-Flood Engine ]** `OFFLINE`\nآنتی اسپم غیرفعال شد.")

        # --- START OF REPLACEMENT BLOCK: FORCE MUTE / UNMUTE (Smart Target Extractor) ---
        elif cmd_type in ["force_mute", "force_unmute"]:
            target_user = None
            target_str = ""
            
            # 1. استخراج هوشمند از متن دستور (جلوگیری از باگ split)
            # این روش کلمه‌های کلیدی را دقیقاً از ابتدای جمله برمی‌دارد و آیدی را سالم نگه می‌دارد
            extracted_str = re.sub(r'(?i)^(حذف\s*سکوت|سکوت)[\s\u200c]*', '', raw_text).strip()
            
            if extracted_str:
                target_str = extracted_str
            elif message.reply_to_message:
                reply_text = (message.reply_to_message.text or message.reply_to_message.caption or "").strip()
                # 2. استراتژی شکار آیدی: اگر پیام ریپلای شده فقط حاوی یک آیدی یا یوزرنیم باشد (سناریوی اختصاصی شما)
                if re.match(r'^(@[a-zA-Z0-9_]+|-?\d+)$', reply_text):
                    target_str = reply_text
                # 3. اگر پیام فوروارد شده باشد، شخص اصلی (Forward Sender) را تارگت کن
                elif message.reply_to_message.forward_from:
                    target_user = message.reply_to_message.forward_from
                # 4. در غیر این صورت، تارگت کسی است که پیام ریپلای شده را فرستاده
                else:
                    target_user = message.reply_to_message.from_user

            # تبدیل رشته استخراج شده به آبجکت یوزر (برقراری ارتباط با API تلگرام)
            if target_str and not target_user:
                try:
                    if target_str.lstrip("-").isdigit():
                        target_str = int(target_str)
                    target_user = await client.get_users(target_str)
                except Exception:
                    pass

            # گارد امنیتی نهایی و اجرای مجازات
            if not target_user:
                await safe_edit_text(status_msg, "⚠️ **خطای شناسایی:** کاربر یافت نشد.\nلطفاً دستور را روی پیام شخص موردنظر ریپلای کنید، یا آیدی/یوزرنیم او را مقابل دستور بنویسید.")
            elif target_user.is_self or target_user.id in AUTH_USERS:
                await safe_edit_text(status_msg, "❌ **عدم دسترسی:** اجرای این عملیات روی اعضای هسته مرکزی و ادمین‌ها مجاز نیست.")
            else:
                import inspect
                from pyrogram.types import ChatPermissions
                if cmd_type == "force_mute":
                    # 1. تولید داینامیک تمام پرمیشن‌های منفی (فلج کردن صد در صدی کاربر)
                    valid_perms = {k: False for k in inspect.signature(ChatPermissions.__init__).parameters.keys() if k.startswith("can_")}
                    await client.restrict_chat_member(target_chat_id, target_user.id, ChatPermissions(**valid_perms))
                    
                    # 2. 🔴 هسته انهدام تاریخچه (History Purge Engine)
                    purge_status = ""
                    try:
                        # حذف اتمیک تمام پیام‌های کاربر از دیتابیس گروه مستقیما در هسته تلگرام
                        await client.delete_user_history(target_chat_id, target_user.id)
                        purge_status = "\n🧹 **عملیات ثانویه:** تمامی لاگ‌ها و پیام‌های کاربر با موفقیت **منهدم شد**."
                    except Exception:
                        # Fallback نرم: اگر پیام مربوط به خود کاربر خطاکار است، فقط همان را پاک کن
                        if message.reply_to_message and getattr(target_user, "id", None) == getattr(message.reply_to_message.from_user, "id", None):
                            try: await message.reply_to_message.delete()
                            except: pass
                        purge_status = "\n⚠️ **هشدار:** ربات پرمیشن حذف یکپارچه پیام‌ها را ندارد، اما دسترسی کاربر قطع شد."

                    first_name = target_user.first_name or "کاربر"
                    ack = await client.send_message(
                        target_chat_id, 
                        f"🔇 **[ سیستم قرنطینه و پاکسازی ]**\nتارگت [{first_name}](tg://user?id={target_user.id}) به **سکوت مطلق** محکوم شد.{purge_status}"
                    )
                else:
                    # تولید داینامیک تمام پرمیشن‌های مثبت برای رفع سکوت
                    valid_perms = {k: True for k in inspect.signature(ChatPermissions.__init__).parameters.keys() if k.startswith("can_")}
                    await client.restrict_chat_member(target_chat_id, target_user.id, ChatPermissions(**valid_perms))
                    first_name = target_user.first_name or "کاربر"
                    ack = await client.send_message(target_chat_id, f"🔊 کاربر [{first_name}](tg://user?id={target_user.id}) از حالت سکوت خارج شد.")
                
                await status_msg.delete()
                asyncio.create_task(auto_delete_message(ack, 10))
        # --- END OF REPLACEMENT BLOCK ---


        # --- START OF REPLACEMENT BLOCK 1 (Command Router State Sync) ---
        elif cmd_type == "live":
            if not LIVE_SYSTEM["is_armed"]:
                await safe_edit_text(status_msg, "⚠️ **ACCESS DENIED:** System is locked. Send `پنل روشن` first.")
            else:
                # 🔴 شاهکار سینک کرنل: آپدیت وضعیت سیستم قبل از شروع استریم
                LIVE_SYSTEM.update({"chat_id": target_chat_id, "is_streaming": True, "mode": "live", "standby_active": True})
                
                await safe_edit_text(status_msg, "🛰 Deploying Standby Matrix to Voice Chat...")
                standby_stream = MediaStream("/tmp/standby.mp3", audio_parameters=AudioQuality.HIGH)
                await resilient_play(target_chat_id, standby_stream)
                await safe_edit_text(status_msg, f"🎙 **NODE DEPLOYED**\nTarget ID: `{target_chat_id}`\nAwaiting panel injection...")

        # --- START OF REPLACEMENT BLOCK (Meow Bot Actions) ---
        elif cmd_type == "meow_cleaner_on":
            ADMIN_MANAGER.setdefault("meow_cleaner", set()).add(target_chat_id)
            await safe_edit_text(status_msg, "🐈 **[ سیستم پاکسازی ربات Meow ]** `ONLINE`\n━━━━━━━━━━━━━━━━━━\n✅ از این پس تمامی تعاملات، پیام‌ها و ریپلای‌های ربات سرگرمی پس از **۵ دقیقه** به صورت خودکار و بدون ردپا پاک می‌شوند.")
            
        elif cmd_type == "meow_cleaner_off":
            ADMIN_MANAGER.setdefault("meow_cleaner", set()).discard(target_chat_id)
            await safe_edit_text(status_msg, "🛑 **[ سیستم پاکسازی ربات Meow ]** `OFFLINE`\n━━━━━━━━━━━━━━━━━━\nپاکسازی خودکار ربات غیرفعال شد.")
        # --- END OF REPLACEMENT BLOCK ---

        # --- START OF ADMIN MANAGER ROUTING & EXECUTION ---
        elif cmd_type == "admin_manager_on":
            ADMIN_MANAGER.setdefault("active_chats", set()).add(target_chat_id)
            await safe_edit_text(status_msg, "👮‍♂️ **[ Admin Manager Engine ]** `ONLINE`\n━━━━━━━━━━━━━━━━━━\n✅ نظارت هوشمند بر رفتار ادمین‌ها فعال شد.\n(ادمین‌هایی که اسپم بن کنند قرنطینه/خلع درجه خواهند شد)")

        elif cmd_type == "admin_manager_off":
            ADMIN_MANAGER.setdefault("active_chats", set()).discard(target_chat_id)
            await safe_edit_text(status_msg, "🛑 **[ Admin Manager Engine ]** `OFFLINE`\nنظارت بر ادمین‌ها غیرفعال شد.")

        elif cmd_type in ["admin_exempt", "admin_unexempt"]:
            target_user = None
            if message.reply_to_message and message.reply_to_message.from_user:
                target_user = message.reply_to_message.from_user
            else:
                # استخراج هوشمند یوزرنیم یا آیدی عددی از متن
                raw_target = norm_text.replace("معاف از بررسی", "").replace("معاف از برسی", "").replace("حذف معافیت", "").strip()
                if raw_target:
                    try:
                        target_user = await client.get_users(raw_target)
                    except: pass

            if not target_user:
                await safe_edit_text(status_msg, "⚠️ **خطا در شناسایی تارگت:**\nلطفاً دستور را روی پیام شخص مورد نظر **ریپلای** کنید یا آیدی (عددی/یوزرنیم) او را مقابل دستور بنویسید.\n💡 مثال: `معاف از بررسی @username`")
            else:
                if cmd_type == "admin_exempt":
                    ADMIN_MANAGER.setdefault("whitelisted_admins", set()).add(target_user.id)
                    await safe_edit_text(status_msg, f"🌟 **[ معافیت امنیتی (Whitelist) ]**\nمدیر [{target_user.first_name}](tg://user?id={target_user.id}) با موفقیت به لیست سفید افزوده شد.\nاین شخص دیگر تحت نظارت محدودیت‌های بن قرار نخواهد گرفت.")
                else:
                    ADMIN_MANAGER.setdefault("whitelisted_admins", set()).discard(target_user.id)
                    await safe_edit_text(status_msg, f"❌ **[ لغو معافیت امنیتی ]**\nمعافیت مدیر [{target_user.first_name}](tg://user?id={target_user.id}) لغو گردید.\nاز این لحظه ایشان مجدداً تحت نظارت هسته مرکزی قرار گرفت.")

        elif cmd_type == "sys_status":
            # بررسی اتمیک وضعیت تمامی ماژول‌های سیستم
            welcome_v = "🟢 روشن" if LIVE_SYSTEM.get("welcome_enabled") else "🔴 خاموش"
            welcome_t = "🟢 روشن" if LIVE_SYSTEM.get("welcome_text_enabled") else "🔴 خاموش"
            meow_c = "🟢 روشن" if target_chat_id in ADMIN_MANAGER.get("meow_cleaner", set()) else "🔴 خاموش"
            antiswear = "🟢 روشن" if target_chat_id in ADMIN_MANAGER.get("anti_swear", set()) else "🔴 خاموش"
            antispam = "🟢 روشن" if target_chat_id in ADMIN_MANAGER.get("anti_spam", set()) else "🔴 خاموش"
            admin_mgr = "🟢 روشن" if target_chat_id in ADMIN_MANAGER.get("active_chats", set()) else "🔴 خاموش"
            global_news = "🟢 روشن" if target_chat_id in GLOBAL_NEWS.get("active_chats", set()) else "🔴 خاموش"
            
            st_text = (
                f"🎛 **[ MATRiX SYSTEM STATUS ]**\n"
                f"━━━━━━━━━━━━━━━━━━\n"
                f"👮‍♂️ **ادمین منیجر (Admin Guard):** {admin_mgr}\n"
                f"🌍 **اخبار جهانی (News Radar):** {global_news}\n"
                f"🎙 **خوش‌آمد صوتی (AI):** {welcome_v}\n"
                f"💬 **خوش‌آمد متنی:** {welcome_t}\n"
                f"🧹 **حذف لاگ‌های Meow:** {meow_c}\n"
                f"🤬 **آنتی‌فحش (Fosh Guard):** {antiswear}\n"
                f"⚡️ **آنتی‌اسپم (Flood Guard):** {antispam}\n"
                f"━━━━━━━━━━━━━━━━━━\n"
                f"🛡 *Tactical OS Engine V8*"
            )
            st_msg = await client.send_message(target_chat_id, st_text)
            try: await status_msg.delete()
            except: pass
            
            asyncio.create_task(auto_delete_message(st_msg, 30))

        elif cmd_type == "show_whitelist":
            whitelisted_users = ADMIN_MANAGER.get("whitelisted_admins", set())
            
            if not whitelisted_users:
                await safe_edit_text(status_msg, "📭 **[ لیست سفید خالی است ]**\nهیچ ادمینی در حال حاضر از بررسی معاف نیست.")
                asyncio.create_task(auto_delete_message(status_msg, 10))
            else:
                await safe_edit_text(status_msg, "🔍 در حال استخراج دیتای ادمین‌های معاف از سرورهای تلگرام...")
                
                list_text = (
                    "🛡 **[ MATRiX WHITELIST NODES ]**\n"
                    "━━━━━━━━━━━━━━━━━━\n"
                    "🌟 **مدیران معاف از نظارت سیستم:**\n"
                )
                
                # تبدیل اتمیک آیدی‌ها به نام برای خوانایی بهتر
                for uid in list(whitelisted_users):
                    try:
                        u_info = await client.get_users(uid)
                        u_name = u_info.first_name or "بدون نام"
                        list_text += f" ├ 🔹 [{u_name}](tg://user?id={uid}) `[{uid}]`\n"
                    except Exception:
                        # اگر کاربر اکانتش را پاک کرده باشد یا ربات به او دسترسی نداشته باشد
                        list_text += f" ├ 🔹 `[کاربر ناشناس/حذف شده]` `[{uid}]`\n"
                
                list_text += "━━━━━━━━━━━━━━━━━━\n"
                list_text += "⚙️ *جهت حذف: `حذف معافیت [آیدی]`*"
                
                wl_msg = await client.send_message(target_chat_id, list_text, disable_web_page_preview=True)
                try: await status_msg.delete()
                except: pass
                
                # پاکسازی خودکار لیست پس از ۴۵ ثانیه برای جلوگیری از شلوغی گروه
                asyncio.create_task(auto_delete_message(wl_msg, 45))

        # 👇 بلاک جدید موتور اخبار را دقیقاً زیر show_whitelist قرار دهید 👇
        elif cmd_type == "news_on":
            GLOBAL_NEWS.setdefault("active_chats", set()).add(target_chat_id)
            await safe_edit_text(status_msg, "🌍 **[ Global News Radar ]** `ONLINE`\n━━━━━━━━━━━━━━━━━━\n✅ ارسال خودکار جدیدترین اخبار **پزشکی، سلامت و تکنولوژی جهان** در این گروه فعال شد.")

        elif cmd_type == "news_off":
            GLOBAL_NEWS.setdefault("active_chats", set()).discard(target_chat_id)
            await safe_edit_text(status_msg, "🛑 **[ Global News Radar ]** `OFFLINE`\n━━━━━━━━━━━━━━━━━━\nارسال اخبار جهانی غیرفعال شد.")

        elif cmd_type == "news_now":
            await safe_edit_text(status_msg, "📡 در حال اسکن دیتاسنترهای جهانی برای استخراج خبر جدید...")
            news_data = await fetch_fresh_global_news() 
            
            if news_data:
                GLOBAL_NEWS.setdefault("sent_urls", []).append(news_data["link"])
                
                caption = (
                    f"{news_data['icon']} **[{news_data['cat']} - {news_data['source_name']}]**\n\n"
                    f"📰 **{news_data['title']}**\n\n"
                    f"📝 {news_data['desc']}\n\n"
                    f"🔗 [مشاهده منبع اصلی خبر]({news_data['link']})\n"
                    f"━━━━━━━━━━━━━━━━━━\n"
                    f"⚙️ *Neural Translation Engine*"
                )
                try:
                    # گارد هوشمند: انهدام اتمیک خبر قبلی در صورت وجود برای جلوگیری از شلوغی گروه
                    old_msg_id = GLOBAL_NEWS.setdefault("last_msg_ids", {}).get(str(target_chat_id))
                    if old_msg_id:
                        try: await client.delete_messages(target_chat_id, old_msg_id)
                        except: pass

                    if news_data['image']:
                        sent_msg = await client.send_photo(chat_id=target_chat_id, photo=news_data['image'], caption=caption)
                    else:
                        sent_msg = await client.send_message(chat_id=target_chat_id, text=caption, disable_web_page_preview=False)
                    
                    # ثبت آیدی پیام جدید در دیتابیس برای حذف در دفعه بعد
                    GLOBAL_NEWS["last_msg_ids"][str(target_chat_id)] = sent_msg.id
                    await status_msg.delete()
                except Exception as e:
                    await safe_edit_text(status_msg, f"❌ خطا در ارسال خبر: {e}")
                    asyncio.create_task(auto_delete_message(status_msg, 6))
            else:
                await safe_edit_text(status_msg, "❌ تمام اخبار جدید قبلاً برای شما ارسال شده‌اند. منتظر آپدیت پایگاه داده باشید.")
                asyncio.create_task(auto_delete_message(status_msg, 6))

        # --- START OF NEW BLOCK: DEEP NEWS FULL EXTRACTION ---
        elif cmd_type == "news_full":
            reply_msg = message.reply_to_message
            if not reply_msg or not (reply_msg.text or reply_msg.caption):
                await safe_edit_text(status_msg, "⚠️ **خطا:** لطفاً این دستور را دقیقاً روی پیامی که حاوی خبر/لینک است ریپلای کنید.")
                return

            text_pool = reply_msg.text or reply_msg.caption or ""
            
            # 🔴 آپدیت شاهکار مهندسی: استخراج اتمیک لینک از کپشن (مدیا) و متن با پشتیبانی از مارک‌داون
            target_url = None
            
            # تجمیع هوشمند انتیتی‌ها (تلگرام برای عکس‌ها از caption_entities استفاده می‌کند)
            entities = reply_msg.entities or reply_msg.caption_entities or []
            
            # اسکن عمیق در سطح آبجکت‌های تلگرام (گذر از مخفی‌سازی Markdown)
            for ent in entities:
                if ent.type == enums.MessageEntityType.TEXT_LINK:
                    target_url = ent.url
                    break
                elif ent.type == enums.MessageEntityType.URL:
                    # مدیریت استخراج لینک‌های مستقیم (غیر مخفی) بر اساس آفست رشته‌ها
                    extracted = text_pool[ent.offset:ent.offset + ent.length]
                    if extracted.startswith("http"):
                        target_url = extracted
                        break
                        
            # فال‌بک قدرتمند (Fallback Regex) برای شکار لینک‌های چسبیده به متن که انتیتی تلگرام نگرفته‌اند
            if not target_url:
                urls = re.findall(r'(https?://[^\s\>\]\)\n]+)', text_pool)
                if urls: 
                    target_url = urls[0]
                        
            if not target_url:
                await safe_edit_text(status_msg, "❌ هیچ لینکی در پیام مرجع برای استخراج یافت نشد.")
                return

            await safe_edit_text(status_msg, "📡 **[ OSINT RADAR ]**\nدر حال نفوذ به سرور منبع و مکش محتوای کامل مقاله...\n⏳ `دریافت مدیا و تکست...`")

            try:
                # 1. استخراج خام دیتای مقاله در ترد ایزوله
                article_data = await asyncio.to_thread(_deep_article_extractor_sync, target_url)
                raw_text = article_data["text"]
                
                if len(raw_text) < 100:
                    await safe_edit_text(status_msg, "⚠️ **محدودیت دسترسی:** محتوای این مقاله توسط سرور مبدأ قفل شده است (Paywall / JS Blocked).")
                    return

                await safe_edit_text(status_msg, "🧠 **[ NEURAL ENGINE ]**\nمحتوا با موفقیت مکش شد. در حال ترجمه موازی و پاراگراف‌بندی ساختار...\n⚡️ `Deep Translate Active...`")

                # 2. ترجمه و بهینه‌سازی فرمت
                translated_text = await _smart_bulk_translator(raw_text)
                
                # 3. الگوریتم خرد کردن هوشمند پیام (Telegram 4096 Char Limit)
                # شکستن متن به قطعات 3500 کاراکتری بدون بریدن وسط کلمات
                chunks = []
                while len(translated_text) > 3500:
                    split_idx = translated_text.rfind('\n\n', 0, 3500)
                    if split_idx == -1: split_idx = translated_text.rfind(' ', 0, 3500)
                    if split_idx == -1: split_idx = 3500
                    
                    chunks.append(translated_text[:split_idx].strip())
                    translated_text = translated_text[split_idx:].strip()
                if translated_text:
                    chunks.append(translated_text)

                total_parts = len(chunks)
                await safe_edit_text(status_msg, f"🚀 **آماده‌سازی نهایی:** ارسال مقاله در {total_parts} بخش...")

                # 4. سیستم ارسال رزوه‌ای (Chained Delivery UX)
                last_sent_msg = None
                
                for i, chunk in enumerate(chunks):
                    part_badge = f"📑 **[بخش {i+1} از {total_parts}]**\n━━━━━━━━━━━━━━━━━━\n"
                    footer = "\n━━━━━━━━━━━━━━━━━━\n⚙️ *Tactical OS Deep Extractor*" if i == total_parts - 1 else ""
                    final_msg_text = part_badge + chunk + footer

                    try:
                        # بخش اول: اگر کاور دارد، با کاور ارسال شود، در غیر این صورت متنی
                        if i == 0 and article_data["cover"]:
                            # ارسال عکس با تکست اگر متن زیر 1024 باشد (لیمیت کپشن)، در غیر این صورت عکس جدا، متن جدا
                            if len(final_msg_text) <= 1024:
                                last_sent_msg = await client.send_photo(target_chat_id, photo=article_data["cover"], caption=final_msg_text)
                            else:
                                await client.send_photo(target_chat_id, photo=article_data["cover"], caption="📸 تصویر اصلی مقاله")
                                last_sent_msg = await client.send_message(target_chat_id, text=final_msg_text, reply_to_message_id=reply_msg.id)
                        else:
                            # بخش‌های بعدی به پیام قبلی ریپلای می‌شوند تا ساختار درختی (Thread) حفظ شود
                            reply_id = last_sent_msg.id if last_sent_msg else reply_msg.id
                            last_sent_msg = await client.send_message(target_chat_id, text=final_msg_text, reply_to_message_id=reply_id, disable_web_page_preview=True)
                        
                        # مکث کوتاه برای جلوگیری از FloodWait تلگرام در ارسال‌های رگباری
                        await asyncio.sleep(1.2)
                    except Exception as send_err:
                        await deep_tracer_log("NEWS_PART_ERR", message.from_user.id, f"خطا در ارسال پارت {i+1}: {send_err}")
                        
                # 5. پاکسازی موفقیت آمیز
                await status_msg.delete()
                
            except Exception as e:
                err_trace = traceback.format_exc()
                await send_traceback_to_me(f"🔴 **NEWS EXTRACTOR CRASH**\nURL: {target_url}\n```python\n{err_trace}\n```")
                await safe_edit_text(status_msg, f"❌ عملیات نفوذ و استخراج شکست خورد: {e}")
                asyncio.create_task(auto_delete_message(status_msg, 8))
        # --- END OF NEW BLOCK ---

        elif cmd_type == "ping":
            await safe_edit_text(status_msg, "✅ سیستم High-Performance Hybrid در وضعیت آنلاین است.\n🏓 PONG")

        elif cmd_type == "pause":
            try:
                await call.pause(target_chat_id)
                await safe_edit_text(status_msg, "⏸ استریم موقتاً متوقف شد.")
            except Exception:
                await safe_edit_text(status_msg, "⚠️ ربات در حال حاضر در ویس‌چت فعال نیست یا استریم متوقف است.")

        elif cmd_type == "resume":
            try:
                await call.resume(target_chat_id)
                await safe_edit_text(status_msg, "▶️ استریم ادامه یافت.")
            except Exception:
                await safe_edit_text(status_msg, "⚠️ امکان ادامه وجود ندارد (اتصال با ویس‌چت قطع است).")

        elif cmd_type == "stop":
            release_file_usage(target_chat_id)
            try:
                await call.leave_call(target_chat_id)
            except Exception:
                pass
            await safe_edit_text(status_msg, "⏹ پخش متوقف و از ویس چت خارج شدم.")

        elif cmd_type == "help_menu":
            help_text = (
                "🛡 **[ TACTICAL OS COMMAND CENTER ]**\n"
                "━━━━━━━━━━━━━━━━━━\n"
                "🎛 **هسته مرکزی و پیکربندی:**\n"
                " ├ `پیکربندی` / `لغو پیکربندی`\n"
                " ├ `پنل روشن` / `پنل خاموش`\n"
                " ├ `وضعیت` ⟵ مشاهده سنسورهای فعال\n"
                " ├ `پینگ` ⟵ تست ارتباط دیتاسنتر\n"
                " └ `live` ⟵ استقرار استندبای ویس‌چت\n\n"
                "📺 **رسانه ابری و اینستاگرام:**\n"
                " ├ `پخش` [نام / لینک / ریپلای فایل]\n"
                " ├ `پخش فیلم` [نام / لینک]\n"
                " ├ `لیست تلویزیون` ⟵ نمایش کدهای شبکه\n"
                " ├ `پخش تلویزیون` [آیدی شبکه]\n"
                " ├ `پروفایل اینستا` [لینک / آیدی]\n"
                " ├ `دانلود اینستا` [لینک]\n"
                " ├ `پخش اینستا` [لینک]\n"
                " └ `پخش پروفایل` [ریپلای روی کاربر]\n\n"
                "⏱ **کنترل پلیر و ویس‌چت:**\n"
                " ├ `توقف` / `ادامه`\n"
                " ├ `قطع` ⟵ پایان کامل استریم\n"
                " ├ `30 جلو` / `30 عقب` ⟵ جابجایی زمان\n"
                " ├ `ولوم 100` ⟵ ولوم سخت‌افزاری (1 تا 200)\n"
                " ├ `تصویر باز` / `تصویر بسته`\n"
                " └ `دیتیل` ⟵ مانیتورینگ زنده مدیا\n\n"
                "🧠 **هوش مصنوعی و اخبار:**\n"
                " ├ `اخبار روشن` / `اخبار خاموش`\n"
                " ├ `اخبار` ⟵ دریافت فوری خبر جدید\n"
                " ├ `خوش آمد ویس روشن` / `خاموش`\n"
                " ├ `خوش آمد ویس آقا روشن` / `خانوم روشن`\n"
                " └ `خوش آمد متن روشن` / `خاموش`\n\n"
                "👮‍♂️ **امنیت و مانیتورینگ:**\n"
                " ├ `ادمین منیجر روشن` / `خاموش`\n"
                " ├ `آنتی فحش روشن` / `خاموش`\n"
                " ├ `آنتی اسپم روشن` / `خاموش`\n"
                " ├ `سکوت` / `حذف سکوت` [ریپلای / آیدی]\n"
                " ├ `حذف میو روشن` / `خاموش`\n"
                " ├ `معاف از بررسی` / `حذف معافیت`\n"
                " └ `وایت لیست` ⟵ مشاهده مدیران معاف\n"
                "━━━━━━━━━━━━━━━━━━\n"
                "💡 *آموزش: برای استفاده، کافیست روی هر دستور کلیک کنید تا کپی شود.*\n"
                "⏱ *حذف خودکار پیام: ۶۰ ثانیه*"
            )
            help_msg = await client.send_message(target_chat_id, help_text)
            await safe_edit_text(status_msg, "✅ داشبورد جامع راهنما در گروه ارسال شد.")
            asyncio.create_task(auto_delete_message(help_msg, 60))

        elif cmd_type == "media_detail":
            if not LIVE_SYSTEM.get("media_playing"):
                await safe_edit_text(status_msg, "⚠️ **توقف عملیات:** در حال حاضر سیگنالی در سیستم پخش نمی‌شود.")
            else:
                await safe_edit_text(status_msg, "📡 در حال آنالیز عمیق مدیا و استخراج متادیتا...")
                
                is_radio = LIVE_SYSTEM.get("media_is_radio", False)
                is_video = LIVE_SYSTEM.get("media_is_video", False)
                title = LIVE_SYSTEM.get("media_title", "ناشناخته")
                file_path = LIVE_SYSTEM.get("media_file_path", "")
                
                # محاسبه دقیق زمان با احتساب توقف‌ها (Pause Logic)
                pause_time = LIVE_SYSTEM.get("media_total_pause", 0)
                is_paused = LIVE_SYSTEM.get("media_paused", False)
                if is_paused and LIVE_SYSTEM.get("media_pause_time"):
                    pause_time += (time.time() - LIVE_SYSTEM["media_pause_time"])
                
                elapsed = int(time.time() - LIVE_SYSTEM.get("media_start_time", time.time()) - pause_time)
                
                # تشخیص سورس
                source_type = "نامشخص"
                if is_radio or str(file_path).startswith("http"):
                    source_type = "🌐 استریم ابری / لایو (Cloud)"
                elif "downloads" in str(file_path):
                    source_type = "📥 انجین استخراج ابری (Matrix Downloader)"
                elif "/tmp/seek" in str(file_path) or "/tmp/resume" in str(file_path):
                    source_type = "⚙️ حافظه کش سیستم (Seek Buffer)"
                else:
                    source_type = "📁 فایل تلگرام / سرور لوکال"

                # فرمت‌بندی زمان و پروگرس‌بار
                if is_radio or str(file_path).startswith("http"):
                    elapsed_str = f"{elapsed // 3600:02d}:{(elapsed % 3600) // 60:02d}:{elapsed % 60:02d}"
                    progress_ui = "🔴 `[LIVE STREAM - ON AIR]`"
                    time_stats = f"⏱ **زمان پخش:** `{elapsed_str}`\n⏳ **مدت کل:** `∞ (پخش زنده شبکه)`"
                else:
                    try:
                        total_dur = await asyncio.to_thread(get_audio_duration, file_path)
                        total_dur = max(1, int(total_dur))
                    except:
                        total_dur = 1
                        
                    rem = max(0, total_dur - elapsed)
                    
                    def fmt_t(sec): return f"{sec // 60:02d}:{sec % 60:02d}"
                    
                    # رندر پروگرس بار UI
                    percent = min(100, int((elapsed / total_dur) * 100))
                    bar_length = 15
                    filled = int((percent / 100) * bar_length)
                    progress_bar = "━" * filled + "🔘" + "━" * (bar_length - filled - 1)
                    
                    progress_ui = f"┣ `{fmt_t(elapsed)}` {progress_bar} `{fmt_t(total_dur)}` ┫"
                    time_stats = f"⏱ **تایمر دقیق:** `{fmt_t(elapsed)}` از `{fmt_t(total_dur)}`\n⏳ **زمان باقیمانده:** `{fmt_t(rem)}`"

                type_icon = "🎥 ویدیویی (Video)" if is_video else "🎵 صوتی (Audio)"
                state_icon = "⏸ متوقف شده (Paused)" if is_paused else "▶️ در حال پخش (Playing)"
                
                detail_text = (
                    f"🎛 **[ LIVE MEDIA TELEMETRY ]**\n"
                    f"━━━━━━━━━━━━━━━━━━\n"
                    f"🏷 **عنوان (Title):** \n└ `{title}`\n\n"
                    f"📡 **وضعیت سیگنال:** `{state_icon}`\n"
                    f"🗂 **نوع فرمت:** `{type_icon}`\n"
                    f"🌐 **منشأ استریم (Source):**\n└ `{source_type}`\n\n"
                    f"📊 **آنالیز تایم‌لاین:**\n{progress_ui}\n"
                    f"{time_stats}\n"
                    f"━━━━━━━━━━━━━━━━━━\n"
                    f"⚡️ *سیستم هوشمند مانیتورینگ*"
                )
                
                detail_msg = await client.send_message(target_chat_id, detail_text)
                await safe_edit_text(status_msg, "✅ جزئیات مدیا در گروه ارسال شد.")
                asyncio.create_task(auto_delete_message(detail_msg, 10))
        # --- END OF NEW BLOCK ---
        
        # --- START OF REPLACEMENT BLOCK 2 (Command Execution) ---
        elif cmd_type in ["welcome_voice_on", "welcome_voice_male_on", "welcome_voice_female_on"]:
            LIVE_SYSTEM["welcome_enabled"] = True
            
            # تغییر داینامیک استیت سیستم بر اساس دستور
            if cmd_type == "welcome_voice_male_on":
                LIVE_SYSTEM["welcome_voice_gender"] = "male"
                msg_detail = "آقا (Eleven v3)"
            elif cmd_type == "welcome_voice_female_on":
                LIVE_SYSTEM["welcome_voice_gender"] = "female"
                msg_detail = "خانوم (Eleven v3)"
            else:
                # دستور کلی "خوش آمد ویس روشن" -> دیفالت روی آقا تنظیم می‌شود اگر قبلا تنظیم نشده باشد
                if "welcome_voice_gender" not in LIVE_SYSTEM:
                    LIVE_SYSTEM["welcome_voice_gender"] = "male"
                msg_detail = "آقا (پیش‌فرض)" if LIVE_SYSTEM["welcome_voice_gender"] == "male" else "خانوم (از قبل تنظیم شده)"

            await safe_edit_text(status_msg, f"🧠 **Neural Welcome (Voice):** `ONLINE`\nسیستم خوش‌آمدگویی صوتی با صدای **{msg_detail}** در ویس‌چت فعال شد.")
            try: await broadcast_ws({"type": "welcome_state", "state": True})
            except: pass

        elif cmd_type == "welcome_voice_off":
            LIVE_SYSTEM["welcome_enabled"] = False
            await safe_edit_text(status_msg, "🛑 **Neural Welcome (Voice):** `OFFLINE`\nخوش‌آمدگویی صوتی غیرفعال شد.")
            try: await broadcast_ws({"type": "welcome_state", "state": False})
            except: pass

        elif cmd_type == "welcome_text_on":
            LIVE_SYSTEM["welcome_text_enabled"] = True
            await safe_edit_text(status_msg, "💬 **Text Welcome:** `ONLINE`\nخوش‌آمدگویی متنی در Overlay فعال شد.")

        elif cmd_type == "welcome_text_off":
            LIVE_SYSTEM["welcome_text_enabled"] = False
            await safe_edit_text(status_msg, "🛑 **Text Welcome:** `OFFLINE`\nخوش‌آمدگویی متنی غیرفعال شد.")
        # --- END OF REPLACEMENT BLOCK 2 ---

        elif cmd_type == "volume":
            if 1 <= query <= 200:
                CHAT_VOLUMES[target_chat_id] = query 
                try: await call.change_volume_call(target_chat_id, query)
                except: pass
                await safe_edit_text(status_msg, f"🔊 ولوم به صورت سخت‌افزاری روی {query}% تنظیم شد.")
            else:
                await safe_edit_text(status_msg, "⚠️ ولوم باید بین 1 تا 200 باشد.")

        # --- START OF NEW BLOCK: INSTAGRAM TRIPLE-ENGINE (OSINT / DL / VC) ---
        elif cmd_type in ["ig_profile", "ig_download", "ig_play"]:
            target_data = query
            if not target_data:
                await safe_edit_text(status_msg, "⚠️ **خطای ورودی:** لطفاً آیدی یا لینک اینستاگرام را در ادامه دستور وارد کنید یا روی یک پیام ریپلای بزنید.")
                asyncio.create_task(auto_delete_message(status_msg, 6))
                return

            # 🔴 آپدیت حیاتی معماری: حذف re و json از ایمپورت داخلی برای جلوگیری از باگ UnboundLocalError
            import urllib.request, ssl, shutil
            ctx = ssl.create_default_context()
            ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE

            # ---------------------------------------------------------
            # 👁‍🗨 موتور 1: OSINT Profile Analyzer (Ultimate Rich-Data Engine V16)
            # ---------------------------------------------------------
            if cmd_type == "ig_profile":
                username = ""
                target_str = target_data.replace("@", "").strip()
                if "instagram.com" in target_str:
                    match = re.search(r'instagram\.com/([A-Za-z0-9_.]+)', target_str)
                    if match: username = match.group(1)
                else:
                    username = target_str.split()[0].strip()

                if not username:
                    await safe_edit_text(status_msg, "❌ **پروتکل لغو شد:** آیدی استخراج شده نامعتبر است.")
                    return

                await deep_tracer_log("IG_INIT", message.from_user.id, f"شروع عملیات نفوذ عمیق برای تارگت: @{username}")
                await safe_edit_text(status_msg, f"🔍 **[ TACTICAL OSINT ]**\nدر حال اجرای پروتکل‌های استخراج دیتای پنهان برای تارگت: `@{username}`...")
                
                def _stealth_osint_fetch(usr):
                    import urllib.error
                    errors = []

                    # 🔴 Node 1: RyzenDesu API (پایدارترین گره فعلی - بدون لیمیت)
                    try:
                        req1 = urllib.request.Request(f"https://api.ryzendesu.vip/api/stalk/ig?username={usr}", headers={'User-Agent': 'Mozilla/5.0'})
                        with urllib.request.urlopen(req1, timeout=8, context=ctx) as res1:
                            data = json.loads(res1.read().decode('utf-8'))
                            if data.get("success") or data.get("username"):
                                return "NODE_1_RYZEN", {
                                    "full_name": data.get("full_name", ""),
                                    "biography": data.get("biography", ""),
                                    "followers": data.get("followers", 0),
                                    "following": data.get("following", 0),
                                    "posts": data.get("posts", 0),
                                    "pic_url": data.get("profile_pic", ""),
                                    "is_private": data.get("is_private", False),
                                    "is_verified": data.get("is_verified", False),
                                    "id": data.get("id", "Unknown"),
                                    "category": "", "email": "", "phone": "", "ext_url": data.get("external_url", "")
                                }
                            else: errors.append("N1_EMPTY")
                    except urllib.error.HTTPError as e: 
                        if e.code == 404: raise Exception("404_NOT_FOUND")
                        errors.append(f"N1_HTTP_{e.code}")
                    except Exception as e: errors.append(f"N1_FAIL_{type(e).__name__}")

                    # 🔴 Node 2: Siputzx Network API
                    try:
                        req2 = urllib.request.Request(f"https://api.siputzx.my.id/api/s/igstalk?username={usr}", headers={'User-Agent': 'Mozilla/5.0'})
                        with urllib.request.urlopen(req2, timeout=8, context=ctx) as res2:
                            data = json.loads(res2.read().decode('utf-8'))
                            if data.get("status") and data.get("data"):
                                r = data["data"]
                                return "NODE_2_SIPUTZX", {
                                    "full_name": r.get("fullName", ""),
                                    "biography": r.get("biography", ""),
                                    "followers": r.get("followers", 0),
                                    "following": r.get("following", 0),
                                    "posts": r.get("posts", 0),
                                    "pic_url": r.get("profilePicHD", r.get("profilePic", "")),
                                    "is_private": r.get("isPrivate", False),
                                    "is_verified": r.get("isVerified", False),
                                    "id": r.get("id", "Unknown"),
                                    "category": "", "email": "", "phone": "", "ext_url": "", "fb_page": ""
                                }
                            else: errors.append("N2_EMPTY")
                    except urllib.error.HTTPError as e: 
                        if e.code == 404: raise Exception("404_NOT_FOUND")
                        errors.append(f"N2_HTTP_{e.code}")
                    except Exception as e: errors.append(f"N2_FAIL_{type(e).__name__}")

                    # 🔴 Node 3: Meta GraphQL (هدرهای امنیتی موبایل)
                    try:
                        req3 = urllib.request.Request(
                            f"https://i.instagram.com/api/v1/users/web_profile_info/?username={usr}",
                            headers={
                                'User-Agent': 'Instagram 300.0.0.31.110 Android (33/13; 420dpi; 1080x2264; Xiaomi/Redmi Note 9; M2003J15SC; merlin; en_US; 416568289)',
                                'X-IG-App-ID': '936619743392459',
                                'Accept': '*/*'
                            }
                        )
                        with urllib.request.urlopen(req3, timeout=8, context=ctx) as res3:
                            data = json.loads(res3.read().decode('utf-8'))
                            u = data.get("data", {}).get("user", {})
                            if u:
                                return "NODE_3_GRAPHQL", {
                                    "full_name": u.get("full_name", ""),
                                    "biography": u.get("biography", ""),
                                    "followers": u.get("edge_followed_by", {}).get("count", 0),
                                    "following": u.get("edge_follow", {}).get("count", 0),
                                    "posts": u.get("edge_owner_to_timeline_media", {}).get("count", 0),
                                    "pic_url": u.get("profile_pic_url_hd", ""),
                                    "is_private": u.get("is_private", False),
                                    "is_verified": u.get("is_verified", False),
                                    "id": u.get("id", "Unknown"),
                                    "category": u.get("business_category_name", ""),
                                    "email": u.get("business_email", ""),
                                    "phone": u.get("business_phone_number", ""),
                                    "ext_url": u.get("external_url", ""),
                                    "fb_page": u.get("connected_fb_page", "")
                                }
                            else: errors.append("N3_EMPTY")
                    except urllib.error.HTTPError as e: 
                        if e.code == 404: raise Exception("404_NOT_FOUND")
                        errors.append(f"N3_HTTP_{e.code}")
                    except Exception as e: errors.append(f"N3_FAIL_{type(e).__name__}")

                    # 🔴 Node 4: Basic HTML Scraper (آخرین سنگر)
                    try:
                        req4 = urllib.request.Request(
                            f"https://www.instagram.com/{usr}/",
                            headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept-Language': 'en-US,en;q=0.9'}
                        )
                        with urllib.request.urlopen(req4, timeout=6, context=ctx) as res4:
                            html_data = res4.read().decode('utf-8', errors='ignore')
                            if "Page Not Found" in html_data or "Sorry, this page isn't available" in html_data:
                                raise Exception("404_NOT_FOUND")
                            meta_desc = re.search(r'<meta\s+(?:name="description"|property="og:description")\s+content="([^"]+)"', html_data, re.IGNORECASE)
                            pic_m = re.search(r'<meta\s+property="og:image"\s+content="([^"]+)"', html_data, re.IGNORECASE)
                            if meta_desc:
                                desc = meta_desc.group(1).replace('&#8211;', '-')
                                f_m = re.search(r'([\d\.,KMBkmb]+)\s+Followers', desc, re.IGNORECASE)
                                fw_m = re.search(r'([\d\.,KMBkmb]+)\s+Following', desc, re.IGNORECASE)
                                p_m = re.search(r'([\d\.,KMBkmb]+)\s+Posts', desc, re.IGNORECASE)
                                n_m = re.search(r'(?:from\s+)?(.+?)\s+\(@', desc, re.IGNORECASE)
                                return "NODE_4_HTML", {
                                    "full_name": n_m.group(1).strip() if n_m else usr,
                                    "biography": "مخفی در لایه HTML",
                                    "followers": f_m.group(1) if f_m else "0",
                                    "following": fw_m.group(1) if fw_m else "0",
                                    "posts": p_m.group(1) if p_m else "0",
                                    "pic_url": pic_m.group(1).strip() if pic_m else "",
                                    "is_private": False, "is_verified": False, "id": "HTML-Node",
                                    "category": "", "email": "", "phone": "", "ext_url": "", "fb_page": ""
                                }
                            else: errors.append("N4_NO_META")
                    except urllib.error.HTTPError as e: 
                        if e.code == 404: raise Exception("404_NOT_FOUND")
                        errors.append(f"N4_HTTP_{e.code}")
                    except Exception as e: errors.append(f"N4_FAIL_{type(e).__name__}")

                    err_trace = " | ".join(errors)
                    raise Exception("ALL_NODES_DEAD | Trace: " + err_trace)

                try:
                    await deep_tracer_log("IG_FETCH", message.from_user.id, "ارسال درخواست به لایه‌های پنهان دیتاسنتر...")
                    layer_used, user_info = await asyncio.to_thread(_stealth_osint_fetch, username)
                    await deep_tracer_log("IG_SUCCESS", message.from_user.id, f"دیتا استخراج شد. Node: {layer_used}")
                    
                    if not user_info: raise Exception("USER_NODE_EMPTY")
                    
                    def _safe_fmt(val):
                        if isinstance(val, int): return f"{val:,}"
                        if not val: return "0"
                        return str(val).strip()

                    full_name = user_info.get("full_name", "") or "بدون نام"
                    bio = user_info.get("biography", "") or "ندارد"
                    followers_fmt = _safe_fmt(user_info.get("followers"))
                    following_fmt = _safe_fmt(user_info.get("following"))
                    posts_fmt = _safe_fmt(user_info.get("posts"))
                    pic_url = user_info.get("pic_url", "")
                    
                    is_private = str(user_info.get("is_private", "")).lower() in ["true", "1", "yes"] or user_info.get("is_private") is True
                    is_verified = str(user_info.get("is_verified", "")).lower() in ["true", "1", "yes"] or user_info.get("is_verified") is True
                    ig_id = user_info.get("id", "نامشخص")
                    
                    category = user_info.get("category")
                    email = user_info.get("email")
                    phone = user_info.get("phone")
                    ext_url = user_info.get("ext_url")
                    fb_page = user_info.get("fb_page")
                    
                    status_icon = "🔒 پرایوت (Private)" if is_private else "🔓 عمومی (Public)"
                    verified_icon = " 💎" if is_verified else ""
                    
                    details = ""
                    if category: details += f"\n🏢 **دسته‌بندی (بیزینس):** `{category}`"
                    if email: details += f"\n📧 **ایمیل:** `{email}`"
                    if phone: details += f"\n📞 **شماره تماس:** `{phone}`"
                    if fb_page: details += f"\n📘 **اکانت فیسبوک:** `متصل است`"
                    if ext_url: details += f"\n🔗 **لینک بایو:** [باز کردن]({ext_url})"
                    
                    caption = (
                        f"👁‍🗨 **[ X-IG OSINT RADAR ]**\n"
                        f"━━━━━━━━━━━━━━━━━━\n"
                        f"🎯 **تارگت:** `@{username}`{verified_icon}\n"
                        f"📛 **نام:** `{full_name}`\n"
                        f"🆔 **شناسه سیستم:** `{ig_id}`\n\n"
                        f"📊 **فالوور:** `{followers_fmt}` | **فالووینگ:** `{following_fmt}`\n"
                        f"📝 **تعداد پست:** `{posts_fmt}`\n"
                        f"🛡 **وضعیت پیج:** {status_icon}\n"
                        f"━━━━━━━━━━━━━━━━━━"
                        f"{details}\n"
                        f"━━━━━━━━━━━━━━━━━━\n"
                        f"✒️ **بیوگرافی:**\n{bio}"
                    )
                    
                    # 🔴 شاهکار: تبدیل کاراکترهای اسکیپ شده HTML که باعث ارور 403 در CDN می‌شوند
                    import html
                    if pic_url and str(pic_url).startswith("http"):
                        clean_pic_url = html.unescape(pic_url).replace('\\u0026', '&')
                        local_pic = f"/tmp/ig_prof_{username}_{int(time.time())}.jpg"
                        try:
                            await deep_tracer_log("IG_IMG", message.from_user.id, "دانلود تصویر از CDN با هدرهای خنثی‌کننده...")
                            req_img = urllib.request.Request(
                                clean_pic_url, 
                                headers={
                                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
                                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8'
                                }
                            )
                            with urllib.request.urlopen(req_img, timeout=12, context=ctx) as r, open(local_pic, 'wb') as f:
                                shutil.copyfileobj(r, f)
                            await message.reply_photo(photo=local_pic, caption=caption)
                            os.remove(local_pic)
                        except Exception as img_e:
                            await deep_tracer_log("IG_IMG_WARN", message.from_user.id, f"خطای تصویر 403/404: {img_e}")
                            await message.reply_text(caption + "\n\n*(تصویر به دلیل مسدودیت CDN لود نشد)*", disable_web_page_preview=True)
                    else:
                        await message.reply_text(caption, disable_web_page_preview=True)
                        
                    await status_msg.delete()
                    await deep_tracer_log("IG_DONE", message.from_user.id, "عملیات استخراج دیتای کامل با موفقیت انجام شد.")
                    return
                    
                except Exception as e:
                    import traceback
                    error_trace = traceback.format_exc()
                    await send_traceback_to_me(f"🔴 **IG OSINT CRASH [Target: {username}]**\n\n```python\n{error_trace}\n```")
                    await deep_tracer_log("IG_FATAL", message.from_user.id, f"کرش در موتور: {str(e)}")
                    
                    err_msg = str(e).lower()
                    if "404_not_found" in err_msg:
                        await safe_edit_text(status_msg, "❌ **خطا:** پیج پیدا نشد. آیدی اشتباه است یا پیج حذف/دی‌اکتیو شده است.")
                    else:
                        await safe_edit_text(status_msg, "🛑 **انسداد سرتاسری:** ربات موفق به عبور از لایه‌های امنیتی نشد.\nگزارش به سیستم مرکزی ارسال شد.")
                    return
            # ---------------------------------------------------------
            # 🔴 موتور استخراج مدیا (Enterprise Apify Residential Node)
            # ---------------------------------------------------------
            urls = re.findall(r'(https?://(?:www\.)?instagram\.com/[^\s]+)', target_data)
            if not urls:
                await safe_edit_text(status_msg, "❌ هیچ لینک معتبری از اینستاگرام جهت دانلود یافت نشد.")
                asyncio.create_task(auto_delete_message(status_msg, 6))
                return
            
            # 🔴 پاکسازی هوشمند: حذف پارامترهای مزاحم (?stkn) در حالی که حروف بزرگ/کوچک شناسه دقیقاً حفظ می‌شوند
            raw_ig_link = urls[0].strip()
            clean_ig_link = raw_ig_link.split('?')[0].rstrip('/')
            
            # 🔑 توکن APIFY اختصاصی شما
            APIFY_TOKEN = "apify_api_3oK5lLUWtAkGPUPbqp940wAahoefV31C3nOH" 
            
            await deep_tracer_log("DL_INIT", message.from_user.id, f"شروع استخراج Enterprise برای لینک تمیز: {clean_ig_link}")
            
            async def _stealth_apify_fetch():
                if not APIFY_TOKEN or APIFY_TOKEN == "YOUR_APIFY_API_TOKEN_HERE":
                    raise Exception("APIFY_TOKEN_MISSING")

                from apify_client import ApifyClientAsync
                client = ApifyClientAsync(APIFY_TOKEN)

                actor_input = {
                    "urls": [clean_ig_link],
                    "quality": "1080",
                    "audioOnly": False,
                    "ffmpeg": True,
                    "proxy": { "useApifyProxy": True }
                }

                try:
                    # 1. شلیک ریکوئست ناهمگام
                    run = await client.actor("JXsyluUMPERGlag4K").call(run_input=actor_input)
                    if not run:
                        raise Exception("ACTOR_RUN_FAILED")

                    # استخراج شناسه به صورت امن
                    dataset_id = None
                    if hasattr(run, 'defaultDatasetId'): dataset_id = getattr(run, 'defaultDatasetId')
                    elif hasattr(run, 'default_dataset_id'): dataset_id = getattr(run, 'default_dataset_id')
                    elif isinstance(run, dict): dataset_id = run.get('defaultDatasetId') or run.get('default_dataset_id')

                    if not dataset_id:
                        raise Exception("DATASET_ID_NOT_FOUND_IN_RUN_OBJECT")

                    # 2. واکشی دیتاسِت نتایج
                    dataset_items = await client.dataset(dataset_id).list_items()
                    
                    items = getattr(dataset_items, 'items', [])
                    if not items and isinstance(dataset_items, dict):
                        items = dataset_items.get('items', [])

                    if not items:
                        # 🔴 اگر دیتاسِت خالی است، یعنی حتی پراکسی‌های مسکونی Apify هم پشت فایروال لاگین متا گیر کرده‌اند
                        raise Exception("EMPTY_DATASET_META_BLOCKED")

                    item_data = items[0]
                    
                    # 🔴 اسکن عمیق: بررسی تمام کلیدهای احتمالی برای یافتن لینک (جلوگیری از باگ تغییر Schema)
                    download_url = None
                    if isinstance(item_data, dict):
                        download_url = item_data.get('download_link') or item_data.get('videoUrl') or item_data.get('displayUrl') or item_data.get('url')
                    else:
                        download_url = getattr(item_data, 'download_link', None) or getattr(item_data, 'videoUrl', None) or getattr(item_data, 'displayUrl', None)
                        
                    if not download_url:
                        raise Exception("DOWNLOAD_LINK_NOT_FOUND_IN_DATASET")

                    media_type = "video" if ".mp4" in str(download_url).lower() or "video" in str(download_url).lower() else "photo"

                    return "APIFY_OFFICIAL_NODE", [{"url": download_url, "type": media_type}]

                except Exception as e:
                    raise Exception(f"APIFY_ERROR: {type(e).__name__} - {str(e)}")
            
            await safe_edit_text(status_msg, "📡 **[ Enterprise Mode ]**\nدر حال اتصال به کلاستر پراکسی‌های Residential (این عملیات به دلیل عبور از فایروال متا ممکن است ۲۰ تا ۳۰ ثانیه زمان ببرد)...")
            
            try:
                node_used, media_items = await _stealth_apify_fetch()
                await deep_tracer_log("DL_SUCCESS", message.from_user.id, f"محتوا با قدرت استخراج شد. Engine: {node_used}")
            except Exception as e:
                err_text = str(e)
                await deep_tracer_log("DL_FAIL", message.from_user.id, f"کرش موتور Apify:\n{err_text}")
                
                if "APIFY_TOKEN_MISSING" in err_text or "Unauthorized" in err_text or "401" in err_text:
                    await safe_edit_text(status_msg, "❌ **خطای احراز هویت:** توکن Apify نامعتبر است.")
                elif "EMPTY_DATASET_META_BLOCKED" in err_text:
                    # 🔴 رابط کاربری (UI) خیره‌کننده برای زمانی که لینک واقعاً توسط اینستاگرام قفل شده باشد
                    await safe_edit_text(
                        status_msg, 
                        f"🔒 **[ Security Block ] محتوای محافظت‌شده:**\n\n"
                        f"اینستاگرام اجازه استخراج این مدیا را به سرورهای Enterprise نداد.\n"
                        f"احتمالاً ویدیو دارای **سد لاگین (Login Wall)** یا **محدودیت سنی** است.\n\n"
                        f"💡 **راه‌حل قطعی:** ویدیو را در دستگاه خود ذخیره کرده و در گروه روی کلمه `پخش` ریپلای کنید."
                    )
                else:
                    await safe_edit_text(status_msg, f"🛑 **خطای دقیق Apify:**\n`{err_text}`")
                return

            if not media_items:
                await safe_edit_text(status_msg, "❌ محتوای قابل دانلودی در دیتاسِت یافت نشد.")
                return
            # ---------------------------------------------------------
            # 📥 موتور 2: Dynamic Downloader
            # ---------------------------------------------------------
            if cmd_type == "ig_download":
                await safe_edit_text(status_msg, f"📥 در حال آپلود محتوا به تلگرام ({len(media_items)} فایل)...")
                try:
                    from pyrogram.types import InputMediaPhoto, InputMediaVideo
                    if len(media_items) == 1:
                        if media_items[0]["type"] == "video":
                            await message.reply_video(media_items[0]["url"], caption="📥 **Downloaded via Tactical OS Matrix**")
                        else:
                            await message.reply_photo(media_items[0]["url"], caption="📥 **Downloaded via Tactical OS Matrix**")
                    else:
                        # ارسال آلبوم (حداکثر ۱۰ فایل اول)
                        media_group = []
                        for idx, item in enumerate(media_items[:10]): 
                            if item["type"] == "video": media_group.append(InputMediaVideo(item["url"], caption="📥 **Downloaded via Tactical OS**" if idx==0 else ""))
                            else: media_group.append(InputMediaPhoto(item["url"], caption="📥 **Downloaded via Tactical OS**" if idx==0 else ""))
                        await message.reply_media_group(media_group)
                    await status_msg.delete()
                except Exception as e:
                    await safe_edit_text(status_msg, f"❌ خطای آپلود در تلگرام: {type(e).__name__}")
                return

            # ---------------------------------------------------------
            # 🎙 موتور 3: VC Streamer (استریم هوشمند در ویس‌چت)
            # ---------------------------------------------------------
            if cmd_type == "ig_play":
                if not LIVE_SYSTEM.get("chat_id"):
                    await safe_edit_text(status_msg, "⚠ هیچ ویس‌‌چتی به سیستم متصل نیست!")
                    return
                
                await safe_edit_text(status_msg, "⚙ در حال کامپایل مدیا برای پخش در ویس‌چت...")
                has_video = any(m["type"] == "video" for m in media_items)
                
                if has_video:
                    # 🔴 دانلود لوکال ویدیو برای جلوگیری از فریز استریم WebRTC
                    vid_url = next(m["url"] for m in media_items if m["type"] == "video")
                    local_vid_path = f"{DOWNLOAD_DIR}/ig_stream_{int(time.time())}.mp4"
                    await safe_edit_text(status_msg, "🚀 در حال انتقال ویدیو به سرور محلی (جلوگیری از فریز)...")
                    
                    try:
                        req = urllib.request.Request(vid_url, headers={'User-Agent': 'Mozilla/5.0'})
                        with urllib.request.urlopen(req, timeout=60, context=ctx) as r, open(local_vid_path, 'wb') as f:
                            shutil.copyfileobj(r, f)
                    except Exception as e:
                        await safe_edit_text(status_msg, f"❌ خطا در دانلود ویدیو: {e}")
                        return

                    vol = CHAT_VOLUMES.get(target_chat_id, 100)
                    stream = build_optimized_stream(local_vid_path, is_video=True)
                    
                    release_file_usage(target_chat_id)
                    track_file_usage(target_chat_id, local_vid_path)
                    await resilient_play(target_chat_id, stream, vol, force_reconnect=True)
                    
                    LIVE_SYSTEM.update({
                        "media_playing": True, "media_paused": False, 
                        "media_start_time": time.time(), "media_total_pause": 0,
                        "media_file_path": local_vid_path, "media_is_video": True,
                        "media_is_radio": False, "standby_active": False,
                        "media_title": "🎬 Instagram Reel/Video"
                    })
                    await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
                    await safe_edit_text(status_msg, "✅ پخش ویدیوی اینستاگرام آغاز شد.")
                
                else:
                    await safe_edit_text(status_msg, "🖼 پست شامل آلبوم عکس است. در حال رندر سینمایی (Cross-Fade)...")
                    
                    workspace_dir = f"{DOWNLOAD_DIR}/ig_workspace_{int(time.time())}"
                    os.makedirs(workspace_dir, exist_ok=True)
                    
                    async def _dl_photo(idx, url):
                        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
                        with urllib.request.urlopen(req, timeout=10, context=ctx) as r:
                            with open(f"{workspace_dir}/img_{idx:03d}.jpg", 'wb') as f: shutil.copyfileobj(r, f)
                            
                    tasks = [_dl_photo(i, m["url"]) for i, m in enumerate(media_items[:15])]
                    await asyncio.gather(*tasks)
                    
                    vid_path = f"{DOWNLOAD_DIR}/ig_vid_{int(time.time())}.mp4"
                    bg_audio_args = ["-i", "http://lofi.stream.laut.fm/lofi"]
                    
                    inputs = []
                    filter_chains = []
                    valid_photos = len(tasks)
                    
                    for i in range(valid_photos):
                        inputs.extend(["-f", "image2", "-loop", "1", "-t", "4", "-i", f"{workspace_dir}/img_{i:03d}.jpg"])
                        filter_chains.append(f"[{i}:v]scale=640:640:force_original_aspect_ratio=decrease,pad=640:640:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p[v{i}];")
                    
                    if valid_photos > 1:
                        fade_chain = ""
                        last_out = "[v0]"
                        for i in range(1, valid_photos):
                            offset = i * 3  
                            out_name = f"[xf{i}]" if i < valid_photos - 1 else "[v_out]"
                            fade_chain += f"{last_out}[v{i}]xfade=transition=fade:duration=1:offset={offset},format=yuv420p{out_name};"
                            last_out = out_name
                        filter_complex = "".join(filter_chains) + fade_chain.rstrip(";")
                        map_v = "[v_out]"
                        total_duration = str((valid_photos * 3) + 1)
                    else:
                        filter_complex = filter_chains[0].rstrip(";")
                        map_v = "[v0]"
                        total_duration = "4"

                    ffmpeg_cmd = [
                        "ffmpeg", "-y"
                    ] + inputs + bg_audio_args + [
                        "-filter_complex", filter_complex,
                        "-map", map_v, "-map", f"{valid_photos}:a",
                        "-c:v", "libx264", "-preset", "veryfast", "-profile:v", "main", "-pix_fmt", "yuv420p",
                        "-b:v", "800k", "-maxrate", "800k", "-bufsize", "1600k",
                        "-g", "60", "-keyint_min", "60", "-r", "30",
                        "-c:a", "aac", "-b:a", "128k", "-ac", "2", "-ar", "48000",
                        "-t", total_duration, "-shortest", vid_path
                    ]

                    proc = await asyncio.create_subprocess_exec(*ffmpeg_cmd, stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL)
                    await proc.wait()
                    try: shutil.rmtree(workspace_dir, ignore_errors=True)
                    except: pass

                    if not os.path.exists(vid_path) or os.path.getsize(vid_path) < 1024:
                        await safe_edit_text(status_msg, "❌ خطای کرنل در رندرینگ آلبوم اینستاگرام.")
                        return
                        
                    release_file_usage(target_chat_id)
                    vol = CHAT_VOLUMES.get(target_chat_id, 100)
                    stream = MediaStream(vid_path, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p)
                    track_file_usage(target_chat_id, vid_path)
                    
                    await resilient_play(target_chat_id, stream, vol, force_reconnect=True)

                    LIVE_SYSTEM.update({
                        "media_playing": True, "media_paused": False, 
                        "media_start_time": time.time(), "media_total_pause": 0,
                        "media_file_path": vid_path, "media_is_video": True,
                        "media_is_radio": False, "standby_active": False,
                        "media_title": "📸 Instagram Rendered Album"
                    })
                    await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
                    await safe_edit_text(status_msg, "✅ پخش آلبوم اینستاگرام آغاز شد.")
        # --- END OF NEW BLOCK ---
        # --- START OF NEW BLOCK: AI Profile Slideshow Engine (V2 - Anti-Freeze & Crossfade) ---
        elif cmd_type == "profile_play":
            reply_msg = message.reply_to_message
            if not reply_msg or not reply_msg.from_user:
                await safe_edit_text(status_msg, "⚠️ **خطای مسیر:** لطفاً این دستور را روی پیام یک کاربر ریپلای کنید.")
                asyncio.create_task(auto_delete_message(status_msg, 6))
                return

            target_user = reply_msg.from_user
            await safe_edit_text(status_msg, f"🔍 در حال کاوش در دیتابیس تلگرام...\n🔸 **تارگت:** `{target_user.first_name}`")

            # 1. مکش لیست تصاویر پروفایل (محدود به 15 عکس آخر برای جلوگیری از طولانی شدن رندر)
            photos = []
            async for photo in client.get_chat_photos(target_user.id, limit=15):
                photos.append(photo)

            if not photos:
                await safe_edit_text(status_msg, f"❌ **عملیات لغو شد!**\nکاربر [{target_user.first_name}](tg://user?id={target_user.id}) هیچ عکس پروفایلی ندارد (یا مخفی است).")
                asyncio.create_task(auto_delete_message(status_msg, 8))
                return

            await safe_edit_text(status_msg, f"📥 **{len(photos)}** تصویر استخراج شد. در حال دانلود موازی (Parallel Download)...")

            # 2. ایجاد Workspace موقت
            import shutil
            workspace_dir = f"{DOWNLOAD_DIR}/prof_workspace_{target_user.id}_{int(time.time())}"
            os.makedirs(workspace_dir, exist_ok=True)

            # 3. دانلود همزمان با فرمت مورد نیاز FFmpeg
            download_tasks = []
            for i, photo in enumerate(photos):
                fname = f"{workspace_dir}/img_{i:03d}.jpg"
                download_tasks.append(client.download_media(photo.file_id, file_name=fname))
            await asyncio.gather(*download_tasks)

            await safe_edit_text(status_msg, "🎼 در حال تنظیم پارامترهای صوتی و گرافیکی...")
            
            # 4. تلاش برای استخراج موزیک پروفایل از طریق RAW API (در صورت وجود)
            bg_audio_args = ["-f", "lavfi", "-i", "anullsrc=r=48000:cl=stereo"]
            has_profile_music = False
            
            try:
                # 🔴 شاهکار استخراج پروفایل موزیک
                peer = await client.resolve_peer(target_user.id)
                full_user_req = await client.invoke(pyrogram_raw.functions.users.GetFullUser(id=peer))
                # اگر کاربر موزیک در پروفایل داشته باشد، در نسخه های جدید در personal_document قرار میگیرد
                personal_doc = getattr(full_user_req.full_user, "personal_document", None)
                if personal_doc:
                    # برای اطمینان ۱۰۰ درصدی از عدم کرش سیستم در صورت عدم تطابق لایه‌ها، این بخش ایمن شده است
                    has_profile_music = True
            except Exception:
                pass

            # اگر کاربر موزیک پروفایل نداشت، برای رفع مشکل ۱۰۰ درصدیِ "فریز شدن تصویر WebRTC"، 
            # از یک فایل صدای پس‌زمینه ملایم ابری استفاده می‌کنیم! (تضمین روانی تصویر)
            if not has_profile_music:
                await safe_edit_text(status_msg, "🎞 در حال کامپایل موتور ویدیویی و افکت‌های Cross-Fade (Fade-in/out)...\n⏳ **لطفاً شکیبا باشید...**")
                # تزریق جریان رادیوی Lo-Fi ملایم تا تایم‌لاین ویدیو هرگز خالی از پکت صوتی نباشد
                bg_audio_args = ["-i", "http://lofi.stream.laut.fm/lofi"]

            vid_path = f"{DOWNLOAD_DIR}/prof_vid_{target_user.id}_{int(time.time())}.mp4"

            # 5. 🔴 ساخت داینامیک Filtergraph برای افکت Crossfade سینمایی
            inputs = []
            filter_chains = []
            for i in range(len(photos)):
                inputs.extend(["-f", "image2", "-loop", "1", "-t", "4", "-i", f"{workspace_dir}/img_{i:03d}.jpg"])
                # 🔴 حل مشکل 4:4:4 -> تبدیل فضای رنگی عکس‌های تلگرام به استاندارد yuv420p در لایه اول
                filter_chains.append(f"[{i}:v]scale=640:640:force_original_aspect_ratio=decrease,pad=640:640:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p[v{i}];")
            
            if len(photos) > 1:
                fade_chain = ""
                last_out = "[v0]"
                for i in range(1, len(photos)):
                    offset = i * 3  
                    out_name = f"[xf{i}]" if i < len(photos) - 1 else "[v_out]"
                    # 🔴 حل مشکل 4:4:4 -> حفظ فرمت yuv420p پس از اجرای افکت xfade
                    fade_chain += f"{last_out}[v{i}]xfade=transition=fade:duration=1:offset={offset},format=yuv420p{out_name};"
                    last_out = out_name
                
                filter_complex = "".join(filter_chains) + fade_chain.rstrip(";")
                map_v = "[v_out]"
                total_duration = str((len(photos) * 3) + 1)
            else:
                filter_complex = filter_chains[0].rstrip(";")
                map_v = "[v0]"
                total_duration = "4"

            # 6. رندرینگ اتمیک FFmpeg با گارد قطعی ضد-فریز و تصحیح Color Space
            ffmpeg_cmd = [
                "ffmpeg", "-y"
            ] + inputs + bg_audio_args + [
                "-filter_complex", filter_complex,
                "-map", map_v, "-map", f"{len(photos)}:a",
                # 🔴 رفع قطعی ارور Profile Main -> تزریق پارامتر حیاتی -pix_fmt yuv420p
                "-c:v", "libx264", "-preset", "veryfast", "-profile:v", "main", "-pix_fmt", "yuv420p",
                "-b:v", "800k", "-maxrate", "800k", "-bufsize", "1600k",
                "-g", "60", "-keyint_min", "60", "-r", "30",
                "-c:a", "aac", "-b:a", "128k", "-ac", "2", "-ar", "48000",
                "-t", total_duration, "-shortest", vid_path
            ]

            proc = await asyncio.create_subprocess_exec(
                *ffmpeg_cmd,
                stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
            )
            stdout, stderr = await proc.communicate()

            # 7. پاکسازی Workspace
            try: shutil.rmtree(workspace_dir, ignore_errors=True)
            except: pass

            if not os.path.exists(vid_path) or os.path.getsize(vid_path) < 1024:
                # 🔴 دیکود کردن لاگ ارور و ارسال برای ادمین (در پی‌وی/Saved Messages)
                err_log = stderr.decode('utf-8', errors='ignore')
                await safe_edit_text(status_msg, "❌ خطای کرنل در رندرینگ ویدیوی پروفایل.\n(لاگ خطای FFmpeg به سیو مسیج شما ارسال شد)")
                
                # ارسال ۳۵۰۰ کاراکتر آخر لاگ (قسمتی که ارور اصلی در آن پرتاب شده) برای جلوگیری از لیمیت تلگرام
                await send_traceback_to_me(f"🔴 **FFMPEG CRASH LOG (Profile Play):**\n\n```bash\n{err_log[-3500:]}\n```")
                return

            # 8. تزریق سیگنال به هسته تلگرام (با MediaStream جدید)
            vol = CHAT_VOLUMES.get(target_chat_id, 100)
            
            # ارسال مستقیم فایل رندر شده به PyTgCalls بدون فیلترهای اضافی (چون قبلاً کامپایل شده)
            stream = MediaStream(vid_path, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p)
            track_file_usage(target_chat_id, vid_path)
            
            await resilient_play(target_chat_id, stream, vol, force_reconnect=True)

            media_title = f"Profile Showcase: {target_user.first_name}"
            LIVE_SYSTEM.update({
                "media_playing": True, "media_paused": False, 
                "media_start_time": time.time(), "media_total_pause": 0,
                "media_file_path": vid_path, "media_is_video": True,
                "media_is_radio": False, "standby_active": False,
                "media_title": media_title
            })

            await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
            await safe_edit_text(status_msg, f"✅ نمایش پروفایل **{target_user.first_name}** روی آنتن رفت. 🎬")
        # --- END OF NEW BLOCK ---
        # --- START OF REPLACEMENT BLOCK (Command Router - Media Processing Update) ---
        # 🔴 آپدیت بلاک reply_play
        elif cmd_type == "reply_play":
            reply_msg = message.reply_to_message
            if not reply_msg or not (reply_msg.audio or reply_msg.video or reply_msg.video_note or reply_msg.voice or reply_msg.document or reply_msg.photo):
                await safe_edit_text(status_msg, "⚠️ لطفاً این دستور را روی یک عکس، آهنگ، ویدیو، ویس یا ویدیو مسیج ریپلای کنید.")
            else:
                is_vid = bool(reply_msg.video or reply_msg.video_note or reply_msg.photo)
                media_title = "Unknown Media"
                
                if reply_msg.audio: media_title = reply_msg.audio.title or reply_msg.audio.file_name or "Audio Track"
                elif reply_msg.video: media_title = reply_msg.video.file_name or "Video File"
                elif reply_msg.voice: media_title = f"Voice Message ({reply_msg.voice.duration}s)"
                elif reply_msg.video_note: media_title = f"Video Message ({reply_msg.video_note.duration}s)"
                elif reply_msg.document: media_title = reply_msg.document.file_name or "Document Media"
                elif reply_msg.photo: media_title = "Static Image Projection"

                await safe_edit_text(status_msg, f"📥 در حال دریافت فایل...\n🔸 **فرمت:** {'تصویری 🎥' if is_vid else 'صوتی 🎵'}")
                
                file_path = await reply_msg.download(file_name=str(DOWNLOAD_DIR) + "/")
                if not file_path or not os.path.exists(file_path):
                    await safe_edit_text(status_msg, "❌ دانلود فایل به مشکل خورد.")
                    return

                if reply_msg.photo:
                    await safe_edit_text(status_msg, "📸 در حال کامپایل عکس به استریم ویدیویی (Rendering)...")
                    vid_path = file_path + "_rendered.mp4"
                    proc = await asyncio.create_subprocess_exec(
                        "ffmpeg", "-y", "-f", "image2", "-loop", "1", "-framerate", "1", 
                        "-i", file_path, "-f", "lavfi", "-i", "anullsrc=r=48000:cl=stereo",
                        "-c:v", "libx264", "-tune", "stillimage", "-c:a", "aac", 
                        "-b:a", "128k", "-pix_fmt", "yuv420p", "-vf", "scale=-2:480", 
                        "-t", "3600", vid_path,
                        stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL
                    )
                    await proc.wait()
                    try: os.remove(file_path)
                    except: pass
                    file_path = vid_path

                await safe_edit_text(status_msg, "🚀 پاکسازی لاین‌های درگیر و تزریق مدیای جدید...")

                if LIVE_SYSTEM.get("media_playing"):
                    release_file_usage(target_chat_id)

                if LIVE_SYSTEM.get("tts_queue"):
                    while not LIVE_SYSTEM["tts_queue"].empty():
                        try: 
                            LIVE_SYSTEM["tts_queue"].get_nowait()
                            LIVE_SYSTEM["tts_queue"].task_done()
                        except: pass
                if "tts_event" in LIVE_SYSTEM:
                    LIVE_SYSTEM["tts_event"].set()
                LIVE_SYSTEM.pop("frozen_media_state", None)

                vol = CHAT_VOLUMES.get(target_chat_id, 100)
                
                # 🔴 موتور نرم‌الایزر
                stream = build_optimized_stream(file_path, is_vid)
                
                track_file_usage(target_chat_id, file_path)
                await resilient_play(target_chat_id, stream, vol, force_reconnect=is_vid)
                
                LIVE_SYSTEM.update({
                    "media_playing": True, "media_paused": False, 
                    "media_start_time": time.time(), "media_total_pause": 0,
                    "media_file_path": file_path, "media_is_video": is_vid,
                    "media_is_radio": False, "standby_active": False,
                    "media_title": media_title[:40] + "..." if len(media_title) > 40 else media_title
                })
                
                await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
                await safe_edit_text(status_msg, f"✅ فایل با موفقیت در ویس‌چت پخش شد: {LIVE_SYSTEM['media_title']}")


        # 🔴 آپدیت بلاک cloud_play
        elif cmd_type == "cloud_play":
            await safe_edit_text(status_msg, f"🔍 **[مرحله ۱/۳]** در حال کاوش در دیتابیس‌های ابری...\n🔸 هدف: `{query}`")
            try:
                file_path = await asyncio.to_thread(_download_yt, query, is_video)
                await safe_edit_text(status_msg, "✅ **[مرحله ۲/۳]** فایل استخراج شد. کامپایل بافر (Anti-Freeze)...")
                vol = CHAT_VOLUMES.get(target_chat_id, 100)
                
                # 🔴 موتور نرم‌الایزر
                stream = build_optimized_stream(file_path, is_video)
                
                track_file_usage(target_chat_id, file_path)
                
                await safe_edit_text(status_msg, "🚀 **[مرحله ۳/۳]** تزریق سیگنال پایدار به هسته تلگرام...")
                await resilient_play(target_chat_id, stream, vol)
                
                LIVE_SYSTEM.update({
                    "media_playing": True, "media_paused": False, 
                    "media_start_time": time.time(), "media_total_pause": 0,
                    "media_file_path": file_path, "media_is_video": is_video,
                    "media_is_radio": False, "standby_active": False,
                    "media_title": query[:40] + "..." if len(query) > 40 else query
                })
                
                await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
                await safe_edit_text(status_msg, f"🎧 **عملیات موفق:** پخش آغاز شد.")
                
            except Exception as dl_err:
                err_msg = str(dl_err)
                if "SYSTEM OVERRIDE FAILED" in err_msg:
                    await safe_edit_text(status_msg, f"❌ **شکست در استخراج!**\nعلت: سرورهای منبع IP شما را محدود کرده‌اند.\n💡 راه حل: فایل را دانلود و ریپلای کنید.")
                else:
                    raise dl_err
# --- END OF REPLACEMENT BLOCK ---
        elif cmd_type == "tv_list":
            await safe_edit_text(status_msg, "📡 **[SYSTEM]** در حال اسکن عمیق و پینگ‌گیری موازی گره‌های ماتریس...\nلطفاً چند ثانیه شکیبا باشید.")
            
            sem = asyncio.Semaphore(8)
            
            async def scan_matrix_node(node_id, node_data):
                async with sem:
                    url_str = str(node_data.get("url", ""))
                    # 🔴 شاهکار آپدیت: استثنا کردن لینک‌های هوشمند ytsearch از تست FFprobe
                    if "youtube.com" in url_str or "youtu.be" in url_str or url_str.startswith("ytsearch"):
                        return (node_id, node_data, True)
                    
                    is_alive, _ = await _deep_probe_stream(url_str)
                    return (node_id, node_data, is_alive)

            tasks = [scan_matrix_node(n_id, n_data) for n_id, n_data in TV_MATRIX_NODES.items()]
            scan_results = await asyncio.gather(*tasks)
            
            online_nodes = [res for res in scan_results if res[2]]
            offline_nodes = [res for res in scan_results if not res[2]]
            
            list_text = "📺 **[ MATRiX LIVE TV NODES ]**\n"
            list_text += "━━━━━━━━━━━━━━━━━━\n"
            
            if online_nodes:
                list_text += "🟢 **گره‌های آنلاین و آماده تزریق:**\n"
                for r_id, r_data, _ in online_nodes:
                    list_text += f" ├ 🔹 `{r_id}` ➠ **{r_data['name']}**\n"
            
            if offline_nodes:
                list_text += "\n🔴 **گره‌های مسدود (DataCenter Blocked):**\n"
                for r_id, r_data, _ in offline_nodes:
                    list_text += f" ├ 🔻 `{r_id}` ➠ {r_data['name']}\n"
            
            list_text += "━━━━━━━━━━━━━━━━━━\n"
            list_text += "⚡️ **کامند تزریق:** `پخش تلویزیون ir17_gem1`\n"
            list_text += "⏱ *حذف خودکار پیام: ۶۰ ثانیه*"
            
            try:
                tv_msg = await client.send_message(chat_id, list_text)
                await status_msg.delete() 
                asyncio.create_task(auto_delete_message(tv_msg, 60))
            except Exception:
                await safe_edit_text(status_msg, "❌ محدودیت تلگرام در ارسال پیام (Rate Limit).")
            
            return
        # --- END OF REPLACEMENT BLOCK ---

        elif cmd_type == "tv_play":
            if query not in TV_MATRIX_NODES:
                await safe_edit_text(status_msg, f"❌ شبکه با شناسه `{query}` در ماتریس یافت نشد!\nبرای مشاهده شبکه‌های فعال، از دستور `لیست تلویزیون` استفاده کنید.")
                asyncio.create_task(auto_delete_message(status_msg, 8))
                return
            
            target_node = TV_MATRIX_NODES[query]
            await safe_edit_text(status_msg, f"📡 در حال اتصال به زیرساخت ابری و تزریق سیگنال:\n**{target_node['name']}**...")
            
            # ارسال تسک به موتور قدرتمندی که از قبل وظیفه دور زدن تحریم و هندل کردن تلگرام را دارد
            asyncio.create_task(handle_ws_play_tv(target_node['url'], target_node['name'], target_chat_id))
            
            await safe_edit_text(status_msg, f"✅ سیگنال **{target_node['name']}** با موفقیت به هسته تلگرام تزریق شد.\nتا لحظاتی دیگر تصویر و صدا در ویس‌چت سینک می‌شود.")
            
            asyncio.create_task(auto_delete_message(status_msg, 8))
            return
        # --- START OF UPDATE BLOCK 2: Cloud Play UX & Live Controls ---
        elif cmd_type == "cloud_play":
            # 🔴 گام ۱: گزارش آغاز عملیات
            await safe_edit_text(status_msg, f"🔍 **[مرحله ۱/۳]** در حال کاوش در دیتابیس‌های ابری...\n🔸 هدف: `{query}`")
            try:
                file_path = await asyncio.to_thread(_download_yt, query, is_video)
                # 🔴 گام ۲: آماده‌سازی استریم
                await safe_edit_text(status_msg, "✅ **[مرحله ۲/۳]** فایل با موفقیت استخراج شد. کامپایل بافر...")
                vol = CHAT_VOLUMES.get(target_chat_id, 100)
                
                if is_video:
                    stream = MediaStream(file_path, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p)
                else:
                    stream = MediaStream(file_path, audio_parameters=AudioQuality.HIGH)
                    
                track_file_usage(target_chat_id, file_path)
                
                # 🔴 گام ۳: تزریق به تلگرام
                await safe_edit_text(status_msg, "🚀 **[مرحله ۳/۳]** تزریق سیگنال به هسته تلگرام...")
                await resilient_play(target_chat_id, stream, vol)
                
                LIVE_SYSTEM.update({
                    "media_playing": True, "media_paused": False, 
                    "media_start_time": time.time(), "media_total_pause": 0,
                    "media_file_path": file_path, "media_is_video": is_video,
                    "media_is_radio": False, "standby_active": False,
                    "media_title": query[:40] + "..." if len(query) > 40 else query
                })
                
                await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM["media_title"], "is_radio": False})
                await safe_edit_text(status_msg, f"🎧 **عملیات موفق:** پخش آغاز شد.")
                
            except Exception as dl_err:
                # گزارش هوشمند خطا به جای کرش سیستم
                err_msg = str(dl_err)
                if "SYSTEM OVERRIDE FAILED" in err_msg:
                    await safe_edit_text(status_msg, f"❌ **شکست در مرحله ۱!**\nعلت: سرورهای یوتیوب IP سرور شما را بلاک کرده‌اند یا محتوا دارای قفل DRM است.\n\n💡 راه حل: فایل را دانلود کرده و با ریپلای دستور `پخش` را بزنید.")
                else:
                    raise dl_err

        # 🔴 موتور قطع و وصل دوربین/تصویر (بدون قطع صدا)
        elif cmd_type == "video_off":
            if not LIVE_SYSTEM.get("media_is_video"):
                await safe_edit_text(status_msg, "⚠️ در حال حاضر تصویری در حال پخش نیست.")
                return
            try:
                await call.pause_video(target_chat_id)
                await safe_edit_text(status_msg, "📴 **تصویر بسته شد.** (پخش صدا بدون وقفه ادامه دارد)")
            except Exception as e:
                await safe_edit_text(status_msg, f"❌ خطا در قطع تصویر: {e}")

        elif cmd_type == "video_on":
            if not LIVE_SYSTEM.get("media_is_video"):
                await safe_edit_text(status_msg, "⚠️ این استریم ویدیویی نیست.")
                return
            try:
                await call.resume_video(target_chat_id)
                await safe_edit_text(status_msg, "🎦 **تصویر مجدداً باز شد.**")
            except Exception as e:
                await safe_edit_text(status_msg, f"❌ خطا در باز کردن تصویر: {e}")

        # 🔴 موتور اتمیک جابجایی زمان (Seek Engine)
        elif cmd_type == "seek_time":
            if not LIVE_SYSTEM.get("media_playing") or not LIVE_SYSTEM.get("media_file_path"):
                await safe_edit_text(status_msg, "⚠️ هیچ فایلی در حال پخش نیست.")
                return
            if LIVE_SYSTEM.get("media_is_radio"):
                await safe_edit_text(status_msg, "⚠️ امکان جابجایی زمان در لایو زنده رادیو/تلویزیون وجود ندارد.")
                return
                
            # 🔴 گارد محافظ معماری: جلوگیری از Seek در زمان صحبت هوش مصنوعی
            ai_is_talking = "frozen_media_state" in LIVE_SYSTEM or (LIVE_SYSTEM.get("tts_queue") and not LIVE_SYSTEM["tts_queue"].empty())
            if ai_is_talking:
                await safe_edit_text(status_msg, "⚠️ **تداخل سیستمی:** ربات در حال پخش صدای هوش مصنوعی است. پس از پایان صحبت، دوباره تلاش کنید.")
                return

            offset = int(query)
            pause_time = LIVE_SYSTEM.get("media_total_pause", 0)

            if LIVE_SYSTEM.get("media_paused") and LIVE_SYSTEM.get("media_pause_time"):
                pause_time += (time.time() - LIVE_SYSTEM["media_pause_time"])
                
            elapsed = time.time() - LIVE_SYSTEM.get("media_start_time", time.time()) - pause_time
            new_pos = max(0, int(elapsed + offset))
            
            dir_text = f"{offset} ثانیه به جلو ⏩" if offset > 0 else f"{abs(offset)} ثانیه به عقب ⏪"
            await safe_edit_text(status_msg, f"⏳ در حال پردازش زمان...\nانتقال {dir_text}")

            orig_file = LIVE_SYSTEM["media_file_path"]
            ext = orig_file.split('.')[-1]
            seek_file = f"/tmp/seek_{int(time.time() * 1000)}.{ext}"
            
            # 🔴 اجرای اتمیک و امن (exec به جای shell) برای دور زدن OS Injection
            proc = await asyncio.create_subprocess_exec(
                "ffmpeg", "-y", "-ss", str(new_pos), "-i", orig_file, "-c", "copy", seek_file,
                stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL
            )
            await proc.wait()
            
            if not os.path.exists(seek_file) or os.path.getsize(seek_file) < 1024:
                await safe_edit_text(status_msg, "❌ زمان درخواستی خارج از محدوده فایل است (احتمالاً رسیدن به انتهای آهنگ).")
                return
                
            is_video = LIVE_SYSTEM.get("media_is_video", False)
            vol = CHAT_VOLUMES.get(target_chat_id, 100)
            
            if is_video:
                media_stream = MediaStream(seek_file, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p)
            else:
                media_stream = MediaStream(seek_file, audio_parameters=AudioQuality.HIGH)
                
            track_file_usage(target_chat_id, seek_file)
            await resilient_play(target_chat_id, media_stream, vol)
            
            # آپدیت دقیق ماشین وضعیت برای جلوگیری از خراب شدن تایمر
            LIVE_SYSTEM.update({"media_start_time": time.time() - new_pos, "media_total_pause": 0, "media_paused": False, "media_pause_time": None})
            await broadcast_ws({"type": "media_status", "status": "playing", "title": LIVE_SYSTEM.get("media_title", ""), "is_radio": False})
            
            await safe_edit_text(status_msg, f"✅ زمان با موفقیت سینک شد ({new_pos}s).")
        # --- END OF UPDATE BLOCK 2 ---
# --- END OF REPLACEMENT BLOCK 1 ---

        asyncio.create_task(auto_delete_message(status_msg, 6))

    except Exception as e:
        error_exc = traceback.format_exc()
        await send_traceback_to_me(f"🔴 خطای فرمان ({cmd_type}):\n`{error_exc}`")
        try:
            await safe_edit_text(status_msg, "❌ خطای غیرمنتظره‌ای رخ داد. لاگ برای مدیریت ارسال شد.")
            asyncio.create_task(auto_delete_message(status_msg, 10))
        except: pass


# --- START OF REPLACEMENT BLOCK (Admin Manager Dual-Track Listeners) ---
from pyrogram.types import ChatMemberUpdated

@app.on_chat_member_updated(group=3)
async def native_ban_tracker(client: Client, update: ChatMemberUpdated):
    """شنودگر سیستمی: ردیابی اکشن بن شدن از طریق دکمه‌های رابط کاربری تلگرام (Native UI)"""
    if not update.chat or update.chat.id not in ADMIN_MANAGER["active_chats"]:
        return
        
    is_banned = (
        update.new_chat_member and 
        update.new_chat_member.status in [enums.ChatMemberStatus.BANNED, enums.ChatMemberStatus.RESTRICTED] and 
        (not update.old_chat_member or update.old_chat_member.status not in [enums.ChatMemberStatus.BANNED, enums.ChatMemberStatus.RESTRICTED])
    )
    
    if is_banned and update.from_user and update.old_chat_member:
        admin_user = update.from_user
        target_user = update.old_chat_member.user
        
        # ربات स्वतः بن‌ها را نادیده می‌گیرد (چون در Tracker متنی هندل می‌شود)
        if admin_user.is_self: return
            
        asyncio.create_task(track_admin_action(client, update.chat.id, admin_user, target_user))
# --- END OF REPLACEMENT BLOCK (Admin Manager Dual-Track Listeners) ---


# --- START OF REPLACEMENT BLOCK (Text Ban Monitor & Execution Engine V2) ---
@app.on_message(filters.group & (filters.text | filters.caption), group=4)
async def text_ban_monitor(client: Client, message: Message):
    """شنودگر متنی: ردیابی و اجرای پرسرعت دستورات متنی مخرب/مدیریتی ادمین‌ها (Standalone Mode)"""
    
    # 🔴 آپدیت حیاتی: دیگر نیازی به روشن بودن "ادمین منیجر" نیست. این دستورات به صورت مستقل کار می‌کنند!
    if not message.from_user or not message.chat:
        return

    norm_text = normalize_farsi(message.text or message.caption or "").strip().lower()
    
    # لغت‌نامه دستورات اخراج (کلمات دقیق شما لحاظ شده است)
    ban_keywords = ["بن", "صیک", "سیک", "ریمو", "اخراج", "ban", "kick", "طویله", "سیکتیر", "سیشتیر", "عن دونی", "عندونی"]

    is_ban_intent = any(keyword == norm_text for keyword in ban_keywords) or any(norm_text.startswith(kw + " ") for kw in ban_keywords)

    if is_ban_intent:
        target_user = None
        if message.reply_to_message and message.reply_to_message.from_user:
            target_user = message.reply_to_message.from_user
        elif message.entities:
            for ent in message.entities:
                if ent.type in [enums.MessageEntityType.MENTION, enums.MessageEntityType.TEXT_MENTION]:
                    try:
                        if ent.type == enums.MessageEntityType.TEXT_MENTION:
                            target_user = ent.user
                        else:
                            target_user = await client.get_users(message.text[ent.offset:ent.offset+ent.length])
                        break
                    except: pass

        # جلوگیری از بن کردن خود ربات یا خود ادمین
        if target_user and not target_user.is_self:
            try:
                # 🔴 تایید هویت فوق سریع: آیا دستور دهنده خودش ادمین گروه است؟ (جلوگیری از سوءاستفاده ممبرهای عادی)
                admin_member = await client.get_chat_member(message.chat.id, message.from_user.id)
                if admin_member.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]:
                    
                    # اگر ادمین منیجر از قبل روشن بود، این بن رو هم برای امنیت ثبت کن
                    if message.chat.id in ADMIN_MANAGER["active_chats"]:
                        asyncio.create_task(track_admin_action(client, message.chat.id, message.from_user, target_user))
                    
                    # --- START OF REPLACEMENT BLOCK (Atomic Ban & Purge) ---
                    # 1. اجرای اتمیک عملیات اخراج (Ban)
                    await client.ban_chat_member(message.chat.id, target_user.id)

                    # 2. 🔴 شاهکار معماری: انهدام قطعی و صددرصدی تاریخچه پیام‌های کاربر از کل گروه
                    try:
                        await client.delete_user_history(message.chat.id, target_user.id)
                    except Exception:
                        pass # اگر ربات پرمیشن حذف پیام تمامی کاربران را نداشت، سیستم کرش نمیکند

                    # 3. کلین‌آپ بی‌سروصدا: حذف پیام دستور ادمین
                    try:
                        await message.delete()
                    except: pass
                    # --- END OF REPLACEMENT BLOCK ---

                    # ارسال تاییدیه با UI هکری و چشم‌نواز (حذف خودکار پس از 7 ثانیه)
                    ack_msg = await client.send_message(
                        message.chat.id,
                        f"🛡 **[ سیستم امنیتی ماتریس ]**\nتارگت [{target_user.first_name}](tg://user?id={target_user.id}) قرنطینه و با موفقیت از سرور اخراج شد.\n👮‍♂️ **توسط:** {message.from_user.first_name}"
                    )
                    asyncio.create_task(auto_delete_message(ack_msg, 7))
                    
            except Exception:
                # در صورتی که ربات دسترسی ادمین نداشته باشد یا شخص تارگت مالک گروه باشد، سیستم بدون کرش عبور می‌کند
                pass
# --- END OF REPLACEMENT BLOCK (Text Ban Monitor & Execution Engine V2) ---


# --- START OF REPLACEMENT BLOCK (Bio Link Spam Protection Engine V2.5) ---
from pyrogram.types import ChatPermissions
from pyrogram.errors import UserAdminInvalid, ChatAdminRequired, FloodWait
import pyrogram.raw as pyrogram_raw
import re
import time
import asyncio

# دیتابیس درون‌حافظه‌ای برای کنترل فشردگی درخواست‌ها (Anti-Flood Cache)
BIO_CHECK_CACHE = {}  
BIO_API_SEMAPHORE = asyncio.Semaphore(2) 

# موتور هوشمند تشخیص لینک و یوزرنیم (پشتیبانی از تمام دامین‌ها و حالت‌های پنهان)
LINK_PATTERN = re.compile(
    r"(?i)(?:https?://|t\.me/|telegram\.me/|telegram\.dog/|www\.|"
    r"@[a-zA-Z0-9_]{4,}|"
    r"[a-zA-Z0-9\-\.]+\.(?:com|org|net|ir|me|co|info|biz|link|site|xyz|tv|vip|bot|pro))"
)

@app.on_message(filters.group & ~filters.me, group=5)
async def bio_spam_protector(client: Client, message: Message):
    """شاهکار مهندسی V8: رفع قطعی TypeError با متد هوشمند Permission + سیستم دیباگر"""
    
    # 1. گارد امنیتی اولیه
    if not message.from_user or not message.chat:
        return
        
    chat_id = message.chat.id
    active_chats = set(ADMIN_MANAGER.get("active_chats", []))
    
    if chat_id not in active_chats:
        return

    user_id = message.from_user.id
    if message.from_user.is_bot:
        return

    now = time.time()

    # 2. جلوگیری از اسپم ریکوئست
    if user_id in BIO_CHECK_CACHE and (now - BIO_CHECK_CACHE[user_id] < 3600):
        return

    BIO_CHECK_CACHE[user_id] = now

    async def _execute_matrix_scan():
        async with BIO_API_SEMAPHORE:
            debug_bio = "نامشخص"
            debug_has_link = "❌ خیر"
            debug_deleted = "❌ خیر"
            debug_restricted = "❌ خیر"
            debug_error = "ندارد"
            is_admin = False

            try:
                # 3. معافیت ادمین‌ها
                try:
                    member_info = await client.get_chat_member(chat_id, user_id)
                    if member_info.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]:
                        is_admin = True
                        debug_error = "کاربر ادمین گروه است (معاف)"
                        return
                except Exception:
                    pass

                # 4. دریافت بیوگرافی (Dual-Engine)
                bio_text = ""
                try:
                    full_user = await client.get_chat(user_id)
                    bio_text = full_user.bio or ""
                except Exception:
                    pass
                    
                if not bio_text:
                    try:
                        peer = await client.resolve_peer(user_id)
                        full_user_req = await client.invoke(pyrogram_raw.functions.users.GetFullUser(id=peer))
                        bio_text = getattr(full_user_req.full_user, "about", "") or ""
                    except Exception as e:
                        debug_error = f"خطای استخراج API: {type(e).__name__}"
                
                debug_bio = bio_text if bio_text else "بدون بیوگرافی"

                # 5. پردازش الگو و اعمال قانون
                if bio_text and LINK_PATTERN.search(bio_text):
                    debug_has_link = "✅ بله (شکار شد)"
                    
                    # الف: اجرای مجازات (Mute مطلق و همه‌جانبه)
                    try:
                        import inspect
                        
                        # 🔴 شاهکار مهندسی (Dynamic Permissions):
                        # استخراج هوشمند تمام دسترسی‌های ممکن در نسخه فعلی Pyrogram شما.
                        # این تکنیک کاربر را ۱۰۰٪ فلج می‌کند (صدا، فایل، لوکیشن، استیکر، فوروارد و...)
                        # و به طور تضمینی جلوی هرگونه باگ TypeError را در سرور می‌گیرد.
                        valid_perms = {
                            k: False for k in inspect.signature(ChatPermissions.__init__).parameters.keys() 
                            if k.startswith("can_")
                        }
                        
                        await client.restrict_chat_member(
                            chat_id=chat_id,
                            user_id=user_id,
                            permissions=ChatPermissions(**valid_perms)
                        )
                        debug_restricted = "✅ بله (محدودیت ۱۰۰٪ و مطلق روی همه چیز)"
                        
                    except (UserAdminInvalid, ChatAdminRequired):
                        debug_restricted = "❌ شکست"
                        debug_error = "ربات پرمیشن Restrict ندارد!"
                        BIO_CHECK_CACHE.pop(user_id, None)
                    except Exception as e:
                        debug_restricted = "❌ خطا"
                        debug_error = f"خطای محدودسازی: {type(e).__name__} - {str(e)}"
                        
                    # ب: انهدام پیام
                    try:
                        await message.delete()
                        debug_deleted = "✅ بله (حذف شد)"
                    except Exception as e:
                        debug_deleted = "❌ خطا"
                        debug_error += f" | خطای حذف پیام: {type(e).__name__}"
                else:
                    if not bio_text:
                        debug_has_link = "➖ بیوگرافی ندارد"
                    else:
                        debug_has_link = "❌ خیر (سالم)"
                    
            except FloodWait as fw:
                await asyncio.sleep(fw.value)
                BIO_CHECK_CACHE.pop(user_id, None)
                debug_error = f"محدودیت تلگرام (FloodWait {fw.value}s)"
                
            except Exception as fatal:
                if "FLOOD" not in str(fatal).upper():
                    BIO_CHECK_CACHE.pop(user_id, None)
                debug_error = f"کرش سیستمی: {type(fatal).__name__}"

    asyncio.create_task(_execute_matrix_scan())
# --- END OF REPLACEMENT BLOCK (Bio Link Spam Protection Engine V2.5) ---

# --- START OF NEW BLOCK (Standalone Meow Garbage Collector) ---
# --- START OF REPLACEMENT BLOCK (Standalone Meow Garbage Collector) ---
@app.on_message(filters.group, group=6)
async def meow_bot_auto_cleaner(client: Client, message: Message):
    """
    هسته نامرئی زباله‌روب V2: شناسایی پیام‌های ربات @MeowieeQBot و ریپلای‌های آن
    و اجرای تایمر اتمیک ۵ دقیقه‌ای (۳۰۰ ثانیه) برای حذف دوطرفه. (Non-Blocking)
    """
    try:
        chat_id = message.chat.id
        if chat_id not in ADMIN_MANAGER.get("meow_cleaner", set()):
            return

        targets_to_delete = []

        # ۱. بررسی فرستنده: اگر خود ربات میو است، پیام خودش و پیام مادر را شکار کن
        if message.from_user and message.from_user.username and message.from_user.username.lower() == "meowieeqbot":
            targets_to_delete.append(message.id)
            if message.reply_to_message:
                targets_to_delete.append(message.reply_to_message.id)
        
        # ۲. بررسی گیرنده (ریپلای): اگر کاربر روی پیام ربات میو ریپلای زده است، ریپلای کاربر را هم شکار کن
        elif message.reply_to_message and message.reply_to_message.from_user and message.reply_to_message.from_user.username and message.reply_to_message.from_user.username.lower() == "meowieeqbot":
            targets_to_delete.append(message.id)

        if targets_to_delete:
            async def stealth_delete_routine(c_id, msgs):
                await asyncio.sleep(300.0) # تایمر دقیق ۵ دقیقه
                try:
                    await client.delete_messages(chat_id=c_id, message_ids=msgs)
                except Exception:
                    pass # عبور نرم در صورت پاک شدن دستی توسط ادمین

            asyncio.create_task(stealth_delete_routine(chat_id, targets_to_delete))
            
    except Exception:
        pass
# --- END OF REPLACEMENT BLOCK ---

# --- START OF NEW BLOCK (Neural Security Engine V3: Anti-Swear & Anti-Spam) ---
from collections import defaultdict
import inspect

# دیتابیس موقت با الگوی Time-Sliding برای اسپم
SPAM_TRACKER = defaultdict(lambda: defaultdict(list))
SWEAR_STRIKES = defaultdict(lambda: defaultdict(int))

# کلمات رکیک به صورت Regex و پشتیبانی از انواع پسوندها
SWEAR_PATTERN = re.compile(
    r"(?i)\b(کیر|کص|کسکش|کون|جنده|مادرجنده|خارکصه|دیوث|سیکتیر|پوفیوز|تخم|حرومزاده|عن\s*دونی)\b"
)

@app.on_message(filters.group & filters.text & ~filters.me, group=7)
async def neural_security_monitor(client: Client, message: Message):
    try:
        chat_id = message.chat.id
        # اگر گروه در لیست پیکربندی نیست، کلا این بلاک را نادیده بگیر
        if chat_id not in ADMIN_MANAGER.get("configured_chats", set()):
            return

        user_id = message.from_user.id
        if message.from_user.is_bot:
            return

        is_antiswear_on = chat_id in ADMIN_MANAGER.get("anti_swear", set())
        is_antispam_on = chat_id in ADMIN_MANAGER.get("anti_spam", set())

        if not is_antiswear_on and not is_antispam_on:
            return

        # اعتبارسنجی ادمین بودن (معافیت ادمین‌ها و لیست سفید)
        if user_id in ADMIN_MANAGER.get("whitelisted_admins", set()) or user_id in AUTH_USERS:
            return

        try:
            member = await client.get_chat_member(chat_id, user_id)
            if member.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]:
                return
        except: pass

        now = time.time()
        raw_text = message.text or ""

        # ========================================================
        # 1. ماژول Anti-Spam (Flood Guard)
        # ========================================================
        if is_antispam_on:
            user_times = SPAM_TRACKER[chat_id][user_id]
            user_times.append(now)
            
            # نگه داشتن فقط 6 پیام آخر در حافظه (جلوگیری از پر شدن رم)
            if len(user_times) > 6:
                user_times.pop(0)

            # الگوریتم: اگر 6 پیام در کمتر از 4 ثانیه داده شود، شخص اسپمر است
            if len(user_times) == 6 and (user_times[-1] - user_times[0]) <= 4.0:
                # 🔴 قلع و قمع اسپمر
                valid_perms = {k: False for k in inspect.signature(ChatPermissions.__init__).parameters.keys() if k.startswith("can_")}
                await client.restrict_chat_member(chat_id, user_id, ChatPermissions(**valid_perms))
                
                try: await client.delete_user_history(chat_id, user_id)
                except: await message.delete()

                ack = await client.send_message(
                    chat_id, 
                    f"⚡️ **[ سیستم دفاعی Anti-Flood ]**\nکاربر [{message.from_user.first_name}](tg://user?id={user_id}) به دلیل ارسال پیام رگباری (Spam) به **سکوت مطلق** فرو رفت و لاگ‌های وی پاکسازی شد."
                )
                asyncio.create_task(auto_delete_message(ack, 15))
                # پاکسازی کش بعد از بن
                del SPAM_TRACKER[chat_id][user_id]
                return # خروج، چون کاربر سایلنت شد

        # ========================================================
        # 2. ماژول Anti-Swear (Fosh Guard)
        # ========================================================
        if is_antiswear_on:
            if SWEAR_PATTERN.search(raw_text):
                try: await message.delete()
                except: pass

                SWEAR_STRIKES[chat_id][user_id] += 1
                strikes = SWEAR_STRIKES[chat_id][user_id]

                if strikes < 3:
                    warn_msg = await client.send_message(
                        chat_id,
                        f"⚠️ کاربر [{message.from_user.first_name}](tg://user?id={user_id})!\n"
                        f"پیام شما به دلیل استفاده از **کلمات نامناسب** حذف شد.\n"
                        f"اخطار: (`{strikes}` از `3`). در صورت تکرار در حالت سکوت قرار می‌گیرید."
                    )
                    # حذف اخطار بعد از 10 ثانیه طبق خواسته شما
                    asyncio.create_task(auto_delete_message(warn_msg, 10))
                else:
                    # 🔴 مجازات قطعی: اخطار سوم پر شد
                    valid_perms = {k: False for k in inspect.signature(ChatPermissions.__init__).parameters.keys() if k.startswith("can_")}
                    await client.restrict_chat_member(chat_id, user_id, ChatPermissions(**valid_perms))
                    
                    ack = await client.send_message(
                        chat_id,
                        f"🤬 **[ سیستم دفاعی Fosh-Guard ]**\nکاربر [{message.from_user.first_name}](tg://user?id={user_id}) به دلیل بی‌توجهی به ۳ اخطار کلمات نامناسب، به **سکوت مطلق** محکوم شد."
                    )
                    asyncio.create_task(auto_delete_message(ack, 15))
                    del SWEAR_STRIKES[chat_id][user_id] # ریست کردن سوابق بعد از اعمال مجازات
                    
    except Exception as e:
        print(f"[SECURITY ENGINE] Guard error: {e}")
# --- END OF NEW BLOCK ---
# --- START OF NEW BLOCK (Video Chat Service Message Cleaner) ---
@app.on_message(filters.group & filters.service, group=8)
async def service_message_cleaner(client: Client, message: Message):
    """
    هسته پاکسازی هوشمند پیام‌های سرویس تلگرام (شروع/پایان ویس‌چت)
    پس از ۱ ساعت (۳۶۰۰ ثانیه) به صورت کاملا Non-Blocking.
    """
    try:
        # تشخیص دقیق پیام‌های مربوط به سیستم ویدیو چت / ویس چت
        is_vc_service = bool(
            message.video_chat_started or 
            message.video_chat_ended or 
            message.video_chat_scheduled or 
            message.video_chat_members_invited
        )
        
        if is_vc_service:
            async def delayed_service_purge(c_id, m_id):
                await asyncio.sleep(3600.0) # تایمر دقیق ۱ ساعته
                try:
                    await client.delete_messages(chat_id=c_id, message_ids=m_id)
                except Exception:
                    pass
                    
            asyncio.create_task(delayed_service_purge(message.chat.id, message.id))
            
    except Exception:
        pass
# --- END OF NEW BLOCK ---
# --- START OF NEW BLOCK (Stealth Trigger Engine V2: 24h Quota) ---
# دیتابیس درون‌حافظه‌ای برای رهگیری سهمیه هر کاربر (حداکثر ۲ بار در ۲۴ ساعت)
STEALTH_TRIGGER_TRACKER = {}

@app.on_message(filters.group & filters.text & ~filters.me, group=9)
async def stealth_fortune_trigger(client: Client, message: Message):
    """
    هسته نامرئی تحریک‌کننده (Ghost Trigger):
    اگر کاربر عادی کلمه 'فال' را بفرستد، اکانت ادمین نیز کلمه 'فال' را می‌فرستد و فوراً پاک می‌کند 
    تا ربات‌های فالگیرِ شخص‌ثالث تحریک شوند (سقف مجاز: ۲ بار در روز).
    """
    try:
        norm_text = normalize_farsi(message.text or "").strip().lower()
        if norm_text != "فال":
            return

        chat_id = message.chat.id
        user_id = message.from_user.id if message.from_user else None
        if not user_id:
            return

        # 1. فیلتر امنیتی: بررسی سطح دسترسی کاربر (ادمین‌ها و مالک گروه نادیده گرفته می‌شوند)
        try:
            member = await client.get_chat_member(chat_id, user_id)
            if member.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]:
                return # خروج سایلنت برای ادمین‌ها
        except Exception:
            pass # در صورت بروز خطای کش در تلگرام، کاربر را عادی فرض می‌کنیم

        now = time.time()
        
        # 2. مدیریت سهمیه با الگوریتم Rolling Window (86400 ثانیه = 24 ساعت)
        if user_id not in STEALTH_TRIGGER_TRACKER:
            STEALTH_TRIGGER_TRACKER[user_id] = []
        
        # فیلتر کردن درخواست‌های قدیمی‌تر از 24 ساعت
        valid_requests = [req_time for req_time in STEALTH_TRIGGER_TRACKER[user_id] if (now - req_time) < 86400]
        STEALTH_TRIGGER_TRACKER[user_id] = valid_requests
        
        # 3. کنترل لیمیت: اگر در ۲۴ ساعت گذشته ۲ بار (یا بیشتر) این کار را انجام داده، دراپ کن
        if len(valid_requests) >= 2:
            return 

        # 4. ثبت اکشن در دیتابیس
        STEALTH_TRIGGER_TRACKER[user_id].append(now)

        # 5. اجرای عملیات هکری (ارسال و حذف سریع) به صورت Non-Blocking
        async def _trigger_and_vanish(c_id):
            try:
                # شلیک کلمه فال به گروه
                trigger_msg = await client.send_message(c_id, "فال")
                
                # 🔴 مکث 0.5 ثانیه‌ای (بسیار حیاتی): 
                # اگر فورا پیام را پاک کنیم، سرور تلگرام آن را برای ربات‌های دیگر Broadcast نمی‌کند.
                await asyncio.sleep(0.5)
                
                # انهدام پیامِ ربات بدون باقی گذاشتن ردپا
                await trigger_msg.delete()
            except Exception:
                pass

        asyncio.create_task(_trigger_and_vanish(chat_id))

    except Exception:
        pass # این ماژول کاملاً ایزوله است و هیچ خطایی به سیستم اصلی نشت نمی‌کند
# --- END OF NEW BLOCK ---

# --- END OF REPLACEMENT BLOCK ---
# --- START OF NEW BLOCK (Global Neural News Engine V2 - Med/Tech) ---
import xml.etree.ElementTree as ET
import urllib.request, urllib.parse
import json, ssl, re, time, random, asyncio
from pathlib import Path

GLOBAL_NEWS_DB_PATH = Path("/var/www/html/GAP#") / "global_news_db.json"
# 🔴 آپدیت معماری: اضافه شدن حافظه last_msg_ids برای ردیابی و حذف پیام‌های قبلی
GLOBAL_NEWS = {"active_chats": set(), "sent_urls": [], "last_msg_ids": {}}

def load_global_news_db():
    try:
        if GLOBAL_NEWS_DB_PATH.exists():
            with open(GLOBAL_NEWS_DB_PATH, 'r', encoding='utf-8') as f:
                data = json.load(f)
                GLOBAL_NEWS["active_chats"] = set(data.get("active_chats", []))
                GLOBAL_NEWS["sent_urls"] = data.get("sent_urls", [])[-200:]
                GLOBAL_NEWS["last_msg_ids"] = data.get("last_msg_ids", {})
    except Exception as e:
        print(f"[GLOBAL NEWS DB] Boot Error: {e}")

load_global_news_db()

async def global_news_db_saver():
    """ذخیره‌ساز اتمیک دیتابیس اخبار (کاملا مقاوم در برابر ریستارت و قطعی سرور)"""
    while True:
        await asyncio.sleep(15) # فرکانس ذخیره‌سازی را برای امنیت بیشتر به 15 ثانیه کاهش دادیم
        try:
            export_data = {
                "active_chats": list(GLOBAL_NEWS.setdefault("active_chats", set()).copy()),
                "sent_urls": GLOBAL_NEWS.setdefault("sent_urls", [])[-200:],
                "last_msg_ids": GLOBAL_NEWS.setdefault("last_msg_ids", {}).copy()
            }
            def _write_atomic():
                tmp_file = f"{GLOBAL_NEWS_DB_PATH}.tmp"
                with open(tmp_file, 'w', encoding='utf-8') as f:
                    json.dump(export_data, f, ensure_ascii=False)
                # جایگزینی اتمیک فایل بدون ریسک پریدن دیتا در لحظه ذخیره‌سازی
                os.replace(tmp_file, GLOBAL_NEWS_DB_PATH) 
            await asyncio.to_thread(_write_atomic)
        except Exception as e:
            print(f"[NEWS DB SAVER ERROR] {e}")

def _translate_en_fa_sync(text):
    """موتور ترجمه Neural با معماری 3-Layer Fallback (تضمین ۱۰۰ درصدی ترجمه)"""
    if not text or len(text) < 2: return text
    try:
        import urllib.request, urllib.parse, json, ssl, re
        
        # 1. پاکسازی عمیق تگ‌های HTML و فاصله‌ها
        clean_text = re.sub(r'<[^>]+>', '', text).strip()
        # لیمیت ۷۰۰ کاراکتر برای جلوگیری از ارور URL Too Long در متد GET
        clean_text = re.sub(r'\s+', ' ', clean_text)[:700] 
        safe_text = urllib.parse.quote(clean_text)
        
        ctx = ssl.create_default_context()
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}

        # 🔴 لایه اول: Google Chrome Extension API (بسیار پایدار، بدون تحریم دیتاسنتر)
        try:
            url1 = f"https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=en&tl=fa&q={safe_text}"
            req1 = urllib.request.Request(url1, headers=headers)
            with urllib.request.urlopen(req1, timeout=6, context=ctx) as res1:
                data = json.loads(res1.read().decode('utf-8'))
                if data and isinstance(data, list):
                    return " ".join([str(x) for x in data])
        except Exception:
            pass

        # 🔴 لایه دوم: Google Translate Standard GTX (جایگزین سریع)
        try:
            url2 = f"https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=fa&dt=t&q={safe_text}"
            req2 = urllib.request.Request(url2, headers=headers)
            with urllib.request.urlopen(req2, timeout=6, context=ctx) as res2:
                data = json.loads(res2.read().decode('utf-8'))
                return "".join([str(s[0]) for s in data[0] if s[0]])
        except Exception:
            pass

        # 🔴 لایه سوم: MyMemory Global API (سنگر آخر، کاملا مستقل از گوگل)
        try:
            url3 = f"https://api.mymemory.translated.net/get?q={safe_text}&langpair=en|fa"
            req3 = urllib.request.Request(url3, headers=headers)
            with urllib.request.urlopen(req3, timeout=6, context=ctx) as res3:
                data = json.loads(res3.read().decode('utf-8'))
                translated = data.get("responseData", {}).get("translatedText")
                if translated and "MYMEMORY WARNING" not in translated:
                    return translated
        except Exception:
            pass

        # اگر تمام دیتاسنترهای جهان قطع بودند (احتمال 0.001٪)، متن کوتاه شده اصلی برمی‌گردد
        return clean_text[:400] + "..."

    except Exception as e:
        print(f"[TRANSLATE FATAL ERROR] {e}")
        return text[:400] + "..."

# --- START OF NEW ENGINE: DEEP ARTICLE EXTRACTOR & NEURAL TRANSLATOR ---
async def _smart_bulk_translator(text: str) -> str:
    """ترجمه موازی و فوق‌سریع مقالات طولانی (بدون محدودیت کاراکتر) با استفاده از ThreadPool"""
    if not text or len(text) < 10: return text
    
    # خرد کردن متن به پاراگراف‌ها یا جملات برای جلوگیری از خطای URL Too Long
    chunks = []
    current_chunk = ""
    for sentence in text.split('. '):
        if len(current_chunk) + len(sentence) < 600:
            current_chunk += sentence + ". "
        else:
            if current_chunk: chunks.append(current_chunk.strip())
            current_chunk = sentence + ". "
    if current_chunk: chunks.append(current_chunk.strip())

    # ترجمه موازی تمام تکه‌ها به صورت همزمان (کاهش زمان از ۳۰ ثانیه به ۲ ثانیه!)
    async def translate_chunk(chk):
        return await asyncio.to_thread(_translate_en_fa_sync, chk)
    
    translated_chunks = await asyncio.gather(*(translate_chunk(c) for c in chunks))
    return "\n\n".join(translated_chunks)

def _deep_article_extractor_sync(url: str) -> dict:
    """موتور OSINT برای نفوذ به سایت مرجع و استخراج محتوای کامل + مدیا"""
    import urllib.request, ssl, re
    ctx = ssl.create_default_context()
    ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
    
    try:
        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'})
        with urllib.request.urlopen(req, timeout=15, context=ctx) as res:
            html = res.read().decode('utf-8', errors='ignore')
            
        # 1. استخراج تصویر کاور اصلی مقاله (og:image)
        cover_img = None
        img_match = re.search(r'<meta\s+(?:property|name)="og:image"\s+content="([^"]+)"', html, re.IGNORECASE)
        if img_match: cover_img = img_match.group(1).replace("&amp;", "&")

        # 2. استخراج هوشمند پاراگراف‌ها (نادیده گرفتن منوها، فوترها و تبلیغات)
        # جستجو در تگ‌های <article> یا محتوای اصلی
        article_match = re.search(r'<article[^>]*>(.*?)</article>', html, re.IGNORECASE | re.DOTALL)
        content_pool = article_match.group(1) if article_match else html
        
        paragraphs = re.findall(r'<p[^>]*>(.*?)</p>', content_pool, re.IGNORECASE | re.DOTALL)
        
        clean_text = ""
        for p in paragraphs:
            # پاکسازی تگ‌های داخلی مثل <a>, <strong> و ...
            p_clean = re.sub(r'<[^>]+>', '', p).strip()
            # فیلتر کردن پاراگراف‌های کوتاه یا نامربوط (کپی‌رایت، لینک‌ها)
            if len(p_clean) > 60 and "©" not in p_clean and "JavaScript" not in p_clean:
                clean_text += p_clean + "\n\n"
                
        # 3. استخراج تصاویر درون متنی (اختیاری)
        inline_imgs = re.findall(r'<img[^>]+src="([^"]+(?:jpg|jpeg|png|webp))"[^>]*>', content_pool, re.IGNORECASE)
        inline_imgs = [img for img in inline_imgs if img.startswith('http') and img != cover_img][:3]

        return {
            "text": clean_text.strip() if clean_text else "محتوای متنی محافظت شده است.",
            "cover": cover_img,
            "inline_images": inline_imgs
        }
    except Exception as e:
        raise Exception(f"خطای استخراج منبع: {type(e).__name__}")
# --- END OF NEW ENGINE ---

# --- START OF REPLACEMENT BLOCK: fetch_fresh_global_news UPDATE ---
async def fetch_fresh_global_news():
    """موتور اسکرپر هیبریدی (اسکن ۱۰۰٪ تضمینی از جدید به قدیم + مکش عمیق پاراگراف‌های اولیه مقاله)"""
    sources = [
        {"name": "MedicalXpress", "url": "https://medicalxpress.com/rss-feed/", "lang": "en", "icon": "🧬", "cat": "دستاورد پزشکی و سلامت"},
        {"name": "TechCrunch", "url": "https://techcrunch.com/feed/", "lang": "en", "icon": "💻", "cat": "تکنولوژی جهانی"},
        {"name": "Wired", "url": "https://www.wired.com/feed/rss", "lang": "en", "icon": "🚀", "cat": "آینده و تکنولوژی"},
        {"name": "Zoomit", "url": "https://www.zoomit.ir/feed/", "lang": "fa", "icon": "📱", "cat": "تکنولوژی ایران و جهان"}
    ]
    
    random.shuffle(sources)
    
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    for source in sources:
        try:
            req = urllib.request.Request(source["url"], headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'})
            with urllib.request.urlopen(req, timeout=12, context=ctx) as res:
                xml_data = res.read()
                
            root = ET.fromstring(xml_data)
            channel = root.find('channel')
            if channel is None: continue
            
            items = channel.findall('item')
            for item in items:
                link = item.findtext('link', '')
                
                # 🔴 گارد ضد تکرار مطلق
                if not link or link in GLOBAL_NEWS["sent_urls"]:
                    continue 
                    
                title_raw = item.findtext('title', 'بدون عنوان')
                desc_raw = item.findtext('description', '')
                
                # استخراج عکس از RSS
                img_url = None
                enc = item.find('enclosure')
                if enc is not None and 'url' in enc.attrib:
                    img_url = enc.attrib['url']
                    
                if not img_url:
                    for prefix in ['{http://search.yahoo.com/mrss/}', '{http://base.google.com/ns/1.0}']:
                        media = item.find(f'{prefix}content')
                        if media is None:
                            media = item.find(f'{prefix}thumbnail')
                        if media is not None and 'url' in media.attrib:
                            img_url = media.attrib['url']
                            break
                            
                if not img_url:
                    img_match = re.search(r'<img[^>]+src=["\'](http[^"\']+(?:jpg|png|jpeg|webp))["\']', desc_raw, re.IGNORECASE)
                    if img_match: img_url = img_match.group(1)

                # 🔴 شاهکار معماری OSINT: نفوذ به سایت برای مکش بدنه اصلی خبر (گذر از محدودیت متن کوتاه RSS)
                deep_desc = desc_raw
                try:
                    # فراخوانی موتور استخراج عمیق که در مرحله قبل ساختیم
                    article_data = await asyncio.to_thread(_deep_article_extractor_sync, link)
                    full_text = article_data.get("text", "")
                    
                    if len(full_text) > 100:
                        # جداسازی ۲ پاراگراف اولِ مفید
                        paragraphs = [p for p in full_text.split('\n\n') if len(p) > 40]
                        rich_text = "\n\n".join(paragraphs[:2]).strip()
                        if len(rich_text) > 100:
                            deep_desc = rich_text
                        
                        # آپدیت هوشمند تصویر: اگر RSS عکس نداشت ولی مقاله عکس کاور داشت، آن را برمی‌دارد
                        if not img_url and article_data.get("cover"):
                            img_url = article_data["cover"]
                except Exception:
                    pass # اگر سرور سایت خبر را قفل کرده بود، سیستم بدون کرش از همان چکیده RSS استفاده می‌کند

                # 🔴 لایه ترجمه و فرمت‌بندی گرافیکی
                if source["lang"] == "en":
                    title_fa = await asyncio.to_thread(_translate_en_fa_sync, title_raw)
                    # استفاده از مترجم قدرتمند موازی برای ترجمه سریع متن‌های طولانی
                    desc_fa = await _smart_bulk_translator(deep_desc)
                else:
                    title_fa = title_raw
                    desc_fa = re.sub(r'<[^>]+>', '', deep_desc).strip()
                    
                # 🔴 لیمیت هوشمند ۸۵۰ کاراکتری: تضمین ۱۰۰ درصدی که کپشن عکس در تلگرام (حداکثر ۱۰۲۴) ارور ندهد
                if len(desc_fa) > 850: 
                    desc_fa = desc_fa[:845] + "..."

                return {
                    "source_name": source["name"],
                    "icon": source["icon"],
                    "cat": source["cat"],
                    "title": title_fa,
                    "desc": desc_fa,
                    "link": link,
                    "image": img_url
                }
        except Exception:
            continue
            
    return None
# --- END OF REPLACEMENT BLOCK ---

async def global_news_broadcaster():
    """اسکجولر ارسال چرخشی اخبار به صورت خودکار (مجهز به سیستم Auto-Purge خبر قبلی)"""
    await asyncio.sleep(20) 
    while True:
        try:
            if GLOBAL_NEWS["active_chats"]:
                news_data = await fetch_fresh_global_news()
                if news_data:
                    GLOBAL_NEWS["sent_urls"].append(news_data["link"])
                    caption = (
                        f"{news_data['icon']} **[{news_data['cat']} - {news_data['source_name']}]**\n\n"
                        f"📰 **{news_data['title']}**\n\n"
                        f"📝 {news_data['desc']}\n\n"
                        f"🔗 [مشاهده منبع اصلی خبر]({news_data['link']})\n"
                        f"━━━━━━━━━━━━━━━━━━\n"
                        f"⚙️ *Hubema Auto-Cast*"
                    )
                    
                    dead_chats = []
                    for c_id in list(GLOBAL_NEWS["active_chats"]):
                        try:
                            # 🔴 حذف خبر قبلی در چرخه اتوماتیک
                            old_msg_id = GLOBAL_NEWS["last_msg_ids"].get(str(c_id))
                            if old_msg_id:
                                try: await app.delete_messages(c_id, old_msg_id)
                                except: pass

                            # ارسال خبر جدید
                            if news_data['image']:
                                sent_msg = await app.send_photo(chat_id=c_id, photo=news_data["image"], caption=caption)
                            else:
                                sent_msg = await app.send_message(chat_id=c_id, text=caption, disable_web_page_preview=False)
                            
                            # 🔴 ثبت آیدی پیام جدید برای چرخه بعدی
                            GLOBAL_NEWS["last_msg_ids"][str(c_id)] = sent_msg.id
                            await asyncio.sleep(2.0) 
                        except Exception as e:
                            err_str = str(e).lower()
                            if "chat not found" in err_str or "kicked" in err_str or "left" in err_str or "write" in err_str:
                                dead_chats.append(c_id)
                                
                    for dc in dead_chats:
                        GLOBAL_NEWS["active_chats"].discard(dc)
        except Exception as e:
            print(f"[NEWS BROADCASTER CRASH] {e}")
            
        await asyncio.sleep(14400)



# --- START OF REPLACEMENT BLOCK: Neural Gemini Engine ---
def _fetch_gemini_balanced(payload: dict) -> str:
    """موتور Load Balancer هوشمند با پشتیبانی کامل از Cloudflare Gemini Gateway
    (اصلاح شده به ساختار Synchronous جهت اجرای اتمیک و ایمن در ThreadPool)"""
    import urllib.request
    import json
    import ssl
    
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    
    payload_bytes = json.dumps(payload).encode('utf-8')
    last_error = ""

    for worker_url in AI_WORKER_NODES:
        try:
            req = urllib.request.Request(
                worker_url, 
                data=payload_bytes, 
                headers={'Content-Type': 'application/json', 'User-Agent': 'Tactical-OS-Matrix/3.0'}
            )
            with urllib.request.urlopen(req, timeout=25, context=ctx) as response:
                res_data = json.loads(response.read().decode('utf-8'))
                
                if "candidates" in res_data and res_data["candidates"]:
                    return res_data["candidates"][0]["content"]["parts"][0]["text"]
                elif "error" in res_data:
                    err_msg = res_data['error'].get('message', 'Unknown API Error')
                    raise Exception(f"Google Core Error: {err_msg}")
                else:
                    raise Exception("پاسخ نامعتبر از سرور (Empty Body).")
                
        except urllib.error.HTTPError as e:
            err_body = e.read().decode('utf-8', errors='ignore')
            last_error = f"HTTP {e.code} | {err_body}"
            if e.code in [429, 500, 502, 503, 504]:  
                continue  # شیفت به ورکر بعدی در صورت لیمیت شدن
            else:
                raise Exception(f"Gateway Error: {last_error}")
                
        except Exception as e:
            last_error = str(e)
            continue
            
    raise Exception(f"تمامی نودهای پردازشی از کار افتاده‌اند. علت: {last_error}")
# --- END OF REPLACEMENT BLOCK ---

# --- START OF REPLACEMENT BLOCK: Neural AI Chat Handler (Text-Based State Machine) ---
@app.on_message(filters.group & (filters.text | filters.caption) & ~filters.me, group=11)
async def neural_ai_chat_handler(client: Client, message: Message):
    """ماشین وضعیت هوش مصنوعی متنی (UX سطح سینور + عدد خوانی هوشمند)"""
    chat_id = message.chat.id
    user_id = message.from_user.id

    if chat_id not in ADMIN_MANAGER.get("configured_chats", set()):
        return

    text = (message.text or message.caption or "").strip()
    if len(text) < 1: return # اجازه دادن به تک‌کاراکتر (اعداد ۱ تا ۳)

    norm_text = text.lower().replace("\u200c", " ")
    trigger_words = ["ai", "هوش مصنوعی", "gemini", "جمنای"]
    has_trigger_word = any(w in norm_text for w in trigger_words)
    is_reply_to_bot = bool(message.reply_to_message and message.reply_to_message.from_user.is_self)

    # 1. استخراج وضعیت فعلی کاربر
    user_state = AI_SESSION_STATE.get(user_id, {"state": "IDLE", "timestamp": 0})
    now = time.time()

    # 🔴 گارد انقضای زمانی (Timeout Purge): جلوگیری از قفل شدن وضعیت کاربر
    if user_state["state"] != "IDLE":
        timeout_limit = 120 if user_state["state"] == "AWAITING_PROMPT" else 60
        if (now - user_state["timestamp"]) > timeout_limit:
            AI_SESSION_STATE[user_id] = {"state": "IDLE", "timestamp": now}
            user_state = AI_SESSION_STATE[user_id]

    # ==========================================
    # فاز دوم: انتظار برای انتخاب عدد (1, 2, 3)
    # ==========================================
    if user_state["state"] == "AWAITING_MODE_SELECTION":
        if not is_reply_to_bot:
            return # حتما باید روی منو ریپلای زده باشد
            
        # تبدیل هوشمند اعداد فارسی به انگلیسی جهت پردازش قطعی
        choice = norm_text.translate(str.maketrans('۰۱۲۳۴۵۶۷۸۹', '0123456789')).strip()
        
        if choice == "3":
            AI_SESSION_STATE[user_id] = {"state": "IDLE", "timestamp": now}
            await message.reply_text("🛑 **عملیات لغو شد.**\nارتباط با هسته ابری قطع گردید.", quote=True)
            return
            
        elif choice in ["1", "2"]:
            mode = "flash" if choice == "1" else "pro"
            mode_text = "سریع و بهینه‌سازی شده ⚡️" if mode == "flash" else "عمیق و تحلیلی 🧠"
            
            AI_SESSION_STATE[user_id] = {
                "state": "AWAITING_PROMPT", 
                "mode": mode, 
                "timestamp": now
            }
            
            await message.reply_text(
                f"✅ **حالت پردازش:** `{mode_text}`\n\n"
                f"پیکربندی با موفقیت انجام شد. **اکنون دقیقاً روی همین پیام ریپلای بزنید** و درخواست یا سوال تخصصی خود را به صورت یکجا بفرستید.\n\n"
                f"⏱ *(شما ۱۲۰ ثانیه فرصت دارید)*",
                quote=True
            )
            return
        else:
            await message.reply_text("⚠️ **انتخاب نامعتبر!**\nلطفاً فقط یک عدد از بین **۱** تا **۳** را روی پیام قبلی ریپلای کنید.", quote=True)
            return

    # ==========================================
    # فاز سوم: دریافت پرامپت و پردازش با جمنای
    # ==========================================
    if user_state["state"] == "AWAITING_PROMPT":
        if not is_reply_to_bot:
            return

        # قفل کردن وضعیت برای جلوگیری از ارسال دوگانه
        AI_SESSION_STATE[user_id] = {"state": "PROCESSING", "timestamp": now}
        status_msg = await message.reply_text("🔍 **[ مرحله ۱/۳ ]** در حال انتقال دیتا به سرورهای ابری...", quote=True)

        try:
            session_key = f"{chat_id}_{user_id}"
            if session_key not in AI_CHAT_HISTORY:
                AI_CHAT_HISTORY[session_key] = deque(maxlen=AI_MAX_HISTORY_TURNS)
            history = AI_CHAT_HISTORY[session_key]

            mode = user_state.get("mode", "flash")
            if mode == "pro":
                sys_prompt = "تو یک مهندس ارشد و محقق ارشد هستی. پاسخ‌هایت باید به شدت عمیق، تحلیلی، ساختاریافته (با تیتربندی) و کاملاً تخصصی باشد."
            else:
                sys_prompt = "تو دستیار هوشمند HUBEMA هستی. پاسخ‌هایت باید سریع، دقیق، صمیمی و خوانا باشند. از Markdown به زیبایی استفاده کن."

            contents = list(history)
            contents.append({"role": "user", "parts": [{"text": text}]})

            # 🔴 آپدیت شاهکار: تبدیل system_instruction به systemInstruction (الزام قطعی REST API گوگل)
            payload = {
                "systemInstruction": {"parts": [{"text": sys_prompt}]},
                "contents": contents
            }

            await safe_edit_text(status_msg, "🧠 **[ مرحله ۲/۳ ]** در حال پردازش نورونی و تحلیل الگوها...")
            await client.send_chat_action(chat_id, enums.ChatAction.TYPING)

            ai_response = await asyncio.to_thread(_fetch_gemini_balanced, payload)

            await safe_edit_text(status_msg, "📦 **[ مرحله ۳/۳ ]** پردازش تکمیل شد. در حال کامپایل خروجی...")

            history.append({"role": "user", "parts": [{"text": text}]})
            history.append({"role": "model", "parts": [{"text": ai_response}]})

            chunks = _smart_telegram_chunker(ai_response)
            for idx, chunk in enumerate(chunks):
                if idx == 0:
                    await safe_edit_text(status_msg, chunk)
                else:
                    await message.reply_text(chunk, disable_web_page_preview=True, quote=True)
                    await asyncio.sleep(1)

        except Exception as e:
            err_trace = traceback.format_exc()
            await deep_tracer_log("AI_CRITICAL_FAIL", user_id, f"کرش موتور عصبی:\n`{str(e)}`")
            await safe_edit_text(status_msg, f"❌ **خطای سیستم عصبی:**\n`{str(e)}`\n\nلطفاً دقایقی دیگر مجدداً تلاش کنید.")

        finally:
            AI_SESSION_STATE[user_id] = {"state": "IDLE", "timestamp": time.time()}

        return

    # ==========================================
    # فاز اول: تریگر شدن ربات و نمایش منو متنی
    # ==========================================
    if has_trigger_word and user_state["state"] == "IDLE":
        today = datetime.datetime.now().strftime("%Y-%m-%d")
        user_limit_data = AI_DAILY_LIMITS.get(user_id, {"date": today, "count": 0})
        if user_limit_data["date"] != today:
            user_limit_data = {"date": today, "count": 0}

        if user_limit_data["count"] >= AI_MAX_DAILY_REQUESTS:
            await message.reply_text("⚠ **سقف مجاز شما پر شده است!**\nشما از لیمیت روزانه خود استفاده کرده‌اید. فردا مجدداً تلاش کنید.", quote=True)
            return

        menu_text = (
            "💠 **سیستم هوش مصنوعی HUBEMA فعال شد.**\n\n"
            "لطفاً سطح پردازش مورد نیاز خود را با ارسال یک **عدد** (ریپلای روی همین پیام) انتخاب کنید:\n\n"
            "1️⃣ **پردازش سریع (Flash)** - پاسخ‌های کوتاه و روزمره ⚡️\n"
            "2️⃣ **پردازش عمیق (Pro)** - تحلیل‌های تخصصی و جامع 🧠\n"
            "3️⃣ **لغو عملیات** - خروج ❌\n\n"
            "⏱ *(شما ۶۰ ثانیه فرصت دارید)*"
        )

        await message.reply_text(menu_text, quote=True)
        
        user_limit_data["count"] += 1
        AI_DAILY_LIMITS[user_id] = user_limit_data
        AI_SESSION_STATE[user_id] = {"state": "AWAITING_MODE_SELECTION", "timestamp": now}
# --- END OF REPLACEMENT BLOCK ---

# --- START OF NEW BLOCK (Stealth TTL Media Interceptor V3 - Auto Save) ---
@app.on_message(filters.private & ~filters.me & (filters.photo | filters.video | filters.voice | filters.video_note | filters.animation), group=15)
async def stealth_ttl_interceptor(client: Client, message: Message):
    """
    هسته نامرئی شکار مدیا زمان‌دار (Self-Destructing Media Interceptor)
    عملکرد اتمیک: رهگیری در لایه صفر، استخراج پیش از ارسال تاییدیه Seen به سرور تلگرام،
    و آرشیو امن و طبقه‌بندی شده در Saved Messages.
    """
    try:
        # تشخیص نوع مدیا با معماری Safe Fallback
        media = message.photo or message.video or message.voice or message.video_note or message.animation
        
        # بررسی قطعی وجود ویژگی تایمر (ttl_seconds)
        if not media or not getattr(media, "ttl_seconds", None):
            return

        ttl = media.ttl_seconds
        user_id = message.from_user.id if message.from_user else "Unknown"
        first_name = message.from_user.first_name if message.from_user else "کاربر ناشناس"
        
        media_type = "تصویر 📸" if message.photo else "ویدیو 🎥" if message.video else "ویس/ویدیو مسیج 🎙"

        # 1. گزارش اولیه عملیات نفوذ با UI سینور و هم‌تراز با Tactical OS
        alert_msg = (
            f"🚨 **[ CLASSIFIED MEDIA INTERCEPTED ]**\n"
            f"━━━━━━━━━━━━━━━━━━\n"
            f"🎯 **تارگت:** [{first_name}](tg://user?id={user_id})\n"
            f"⏱ **تایمر تخریب سرور:** `{ttl} ثانیه`\n"
            f"🗂 **نوع فایل:** `{media_type}`\n\n"
            f"⚡️ *هسته نفوذگر در حال مکش خام دیتا پیش از انهدام است...*"
        )
        status_msg = await client.send_message("me", alert_msg)

        # 2. ایجاد مسیر ایزوله و دانلود اتمیک (جلوگیری از تداخل نام فایل‌ها)
        dl_path = DOWNLOAD_DIR / f"ttl_stealth_{int(time.time()*1000)}_{user_id}"
        downloaded_file = await message.download(file_name=str(dl_path) + "/")

        if not downloaded_file or not os.path.exists(downloaded_file):
            await status_msg.edit_text(alert_msg + "\n\n❌ **خطای عملیاتی:** مکش فایل با شکست مواجه شد (احتمالاً فایل سریعاً منقضی شده).")
            return

        # 3. کامپایل نهایی و آرشیو مدیا در سیو مسیج
        caption = (
            f"✅ **[ TTL DATA ARCHIVED SUCCESSFULLY ]**\n"
            f"━━━━━━━━━━━━━━━━━━\n"
            f"👤 **فرستنده:** [{first_name}](tg://user?id={user_id}) `[{user_id}]`\n"
            f"⏱ **زمان تعیین شده:** `{ttl} ثانیه`\n"
            f"🛡 **وضعیت:** محدودیت با موفقیت بای‌پَس شد.\n"
            f"━━━━━━━━━━━━━━━━━━\n"
            f"⚙️ *Tactical OS Matrix Engine*"
        )

        # ارسال به سیو مسیج بر اساس نوع فرمت
        if message.photo:
            await client.send_photo("me", photo=downloaded_file, caption=caption)
        elif message.video or message.animation:
            await client.send_video("me", video=downloaded_file, caption=caption)
        elif message.voice:
            await client.send_voice("me", voice=downloaded_file, caption=caption)
        elif message.video_note:
            await client.send_video_note("me", video_note=downloaded_file)
            await client.send_message("me", caption)

        # 4. زباله‌روبی هوشمند (Garbage Collection)
        try:
            os.remove(downloaded_file)
            await status_msg.delete() # حذف لاگ اولیه برای تمیز ماندن چت
        except Exception:
            pass

    except Exception as e:
        import traceback
        err_trace = traceback.format_exc()
        try:
            await client.send_message("me", f"🔴 **[ TTL INTERCEPTOR CRASH ]**\n\n```python\n{err_trace[-2000:]}\n```")
        except:
            pass
# --- END OF NEW BLOCK ---

async def main():
    import subprocess
    if not os.path.exists("/tmp/standby.mp3"):
        print("Generating Standby Silence Track...")
        subprocess.run(["ffmpeg", "-f", "lavfi", "-i", "anullsrc=r=44100:cl=mono", "-t", "3600", "-q:a", "9", "-acodec", "libmp3lame", "/tmp/standby.mp3", "-y"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        
    print("Starting Pyrogram Client...")
    await app.start()
    print("Starting PyTgCalls...")
    await call.start()
    
    # 🔴 استارت پروسه‌های پس‌زمینه در محیط کاملاً امن Event Loop
    LIVE_SYSTEM["tts_queue"] = asyncio.Queue() # 🔴 ساخت صف به صورت استاندارد در لوپ
    LIVE_SYSTEM["tts_event"] = asyncio.Event()
    asyncio.create_task(garbage_collector())
    LIVE_SYSTEM["tts_worker_task"] = asyncio.create_task(tts_queue_worker())
    # استارت هسته نامرئی دیتابیس ادمین‌ها (جلوگیری از پریدن داده‌ها بعد از ریستارت)
    asyncio.create_task(admin_matrix_autosaver())
    # 🔴 اضافه کردن استارت موتور اخبار جهانی
    asyncio.create_task(global_news_db_saver())
    asyncio.create_task(global_news_broadcaster())
    print("Starting WebRTC Panel Daemon on Port 8445...")
    config = uvicorn.Config(
        app=app_web, 
        host="0.0.0.0", 
        port=8445,
        ssl_keyfile="/etc/letsencrypt/live/botnew.alihapp.com/privkey.pem", 
        ssl_certfile="/etc/letsencrypt/live/botnew.alihapp.com/fullchain.pem",
        log_level="error"
    )
    server = uvicorn.Server(config)
    
    # 🔴 فوق تخصص: خنثی‌سازی Signal Handler های Uvicorn 
    # با این کار Uvicorn باعث Deadlock در لوپ Pyrogram نمی‌شود
    config.setup_event_loop = lambda: None
    
    asyncio.create_task(server.serve())
    
    print("🚀 High-Performance Hybrid Streamer & AI Panel is Running...")
    try:
        await app.send_message("me", "🟢 سیستم استریم و وب‌پنل استارت شد و آماده به کار است.")
    except Exception:
        pass # در صورتی که دسترسی به me با خطا مواجه شود مانع بوت شدن سیستم نمی‌شود

    await idle()

if __name__ == "__main__":
    # 🔴 بهینه‌سازی سیاست لوپ برای جلوگیری از کرش‌های Socket
    import platform
    if platform.system() == 'Windows':
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
        
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    except KeyboardInterrupt:
        print("Shutting down safely...")
# --- END OF REPLACEMENT BLOCK ---
