import sqlite3
import asyncio
import random
import os
import glob
import time
import re
import shutil
import datetime
import hashlib
import json
import urllib.request
from io import BytesIO
from pyrogram import Client, filters, idle, enums, StopPropagation
from pyrogram.types import (
InlineKeyboardMarkup,
InlineKeyboardButton,
Message,
ChatMemberUpdated,
ChatJoinRequest,
CallbackQuery,
ReplyKeyboardMarkup,
ReplyKeyboardRemove,
BotCommand,
InputMediaDocument
)
from pyrogram.enums import ChatMemberStatus, ParseMode
from pyrogram.errors import (
FloodWait, SessionPasswordNeeded,
PhoneCodeInvalid, UserAlreadyParticipant,
AuthKeyUnregistered, UserNotParticipant,
PeerIdInvalid, ChatAdminRequired, InputUserDeactivated, UserIsBlocked,
UsernameInvalid, ChannelPrivate, MessageNotModified, InviteHashInvalid, InviteHashExpired,
WebpageMediaEmpty
)
# --- ๐ CONFIGURATION ๐ ---
API_ID = 23231578
API_HASH = "6016ef2dc043865f26667d89719b2c7e"
BOT_TOKEN = "8544598569:AAEvluFc1ARb3-lmxPCYfXZVbPVasekMrig".strip()
# --- ๐ ADMIN IDs ---
OWNER_ID = 7204275439
SUDO_ID = 6742282042
ADMINS = [OWNER_ID, SUDO_ID]
# --- FOLDERS & SETUP ---
if not os.path.exists("sessions"):
os.makedirs("sessions")
if not os.path.exists("sessions/private"):
os.makedirs("sessions/private")
# --- JSON BACKUP SETUP ---
JSON_FILE = "channels_backup.json"
# ๐ฅ FIX: Safe loader jo corrupted file ko reset hone se bachayega
def safe_load_json_data():
if not os.path.exists(JSON_FILE):
return {}
try:
with open(JSON_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
if isinstance(data, dict):
return data
except Exception:
# Crash ya corruption hone par backup banayega, wipe nahi hone dega
try: shutil.copy(JSON_FILE, JSON_FILE + ".bak")
except: pass
return {}
# ๐ฅ FIX: Atomic Write - Restart ke time aadhi file likhne se rokega!
def save_json_file(data):
try:
tmp_file = JSON_FILE + ".tmp"
with open(tmp_file, "w", encoding="utf-8") as f:
f.write("{\n")
items = list(data.items())
for i, (k, v) in enumerate(items):
inner_json = json.dumps(v, ensure_ascii=False)
f.write(f' "{k}": {inner_json}')
if i < len(items) - 1:
f.write(",\n")
else:
f.write("\n")
f.write("}\n")
# Replace ekdum instant hota hai, isse file corrupt nahi hoti agar server band ho jaye
os.replace(tmp_file, JSON_FILE)
except Exception:
pass
def sync_all_to_json_fast(channels_list):
try:
data = safe_load_json_data()
changed = False
for k, v in list(data.items()):
if isinstance(v, str):
data[k] = {"title": v, "members": "Unknown"}
changed = True
for chat_id, title in channels_list:
cid_str = str(chat_id)
if cid_str not in data:
data[cid_str] = {"title": title, "members": "Unknown"}
changed = True
if changed or not os.path.exists(JSON_FILE):
save_json_file(data)
except Exception:
pass
def add_to_json(chat_id, chat_title, member_count="Unknown"):
try:
data = safe_load_json_data()
# Auto-migrate old string format
for k, v in list(data.items()):
if isinstance(v, str):
data[k] = {"title": v, "members": "Unknown"}
data[str(chat_id)] = {
"title": chat_title,
"members": member_count
}
save_json_file(data)
except Exception:
pass
def remove_from_json(chat_id):
# ๐ฅ FIX: User Request - Kabhi bhi delete nahi hona chahiye JSON se
pass
# --- LISTS FOR BATCHING ---
USERBOTS_BATCHES = {1: [], 2: [], 3: [], 4:[], 5:[]}
ALL_USERBOTS =[]
ALL_PRIVATE_USERBOTS =[]
PRIVATE_BOTS_MAP = {}
WATCHED_CACHE =[]
# ๐ฅ FIX ADDED: workers=200 add kiya gaya hai taaki command reply instantly aaye VPS par.
app = Client("auto_reaction_manager", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN, workers=200)
# --- DATABASE ---
DB_NAME = "reaction_ultra.db"
def init_db():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('CREATE TABLE IF NOT EXISTS users (user_id INTEGER PRIMARY KEY)')
c.execute('CREATE TABLE IF NOT EXISTS watched_channels (id INTEGER PRIMARY KEY AUTOINCREMENT, chat_id INTEGER UNIQUE, chat_title TEXT, owner_id INTEGER)')
try: c.execute('ALTER TABLE watched_channels ADD COLUMN owner_id INTEGER')
except: pass
try: c.execute('ALTER TABLE watched_channels ADD COLUMN is_paid_promo INTEGER DEFAULT 0')
except: pass
c.execute('CREATE TABLE IF NOT EXISTS broadcast_logs (user_id INTEGER, message_id INTEGER, PRIMARY KEY(user_id, message_id))')
c.execute('CREATE TABLE IF NOT EXISTS private_users (user_id INTEGER PRIMARY KEY, custom_username TEXT, custom_password TEXT)')
c.execute('CREATE TABLE IF NOT EXISTS private_sessions (user_id INTEGER, phone TEXT, session_file TEXT)')
c.execute('CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT)')
c.execute('CREATE TABLE IF NOT EXISTS user_reaction_preferences (user_id INTEGER PRIMARY KEY, emojis TEXT)')
c.execute('CREATE TABLE IF NOT EXISTS historical_channels (chat_id INTEGER PRIMARY KEY)')
c.execute('CREATE TABLE IF NOT EXISTS custom_texts (key TEXT PRIMARY KEY, value TEXT)')
conn.commit()
# Sync old channels directly to JSON on startup
c.execute('SELECT chat_id, chat_title FROM watched_channels')
all_channels = c.fetchall()
sync_all_to_json_fast(all_channels)
conn.close()
refresh_cache()
# ==========================================
# ๐ NEW DAILY STATS DATABASE & FUNCTIONS
# ==========================================
def init_daily_db():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS daily_stats (date TEXT PRIMARY KEY, autodms INTEGER DEFAULT 0, starts INTEGER DEFAULT 0, channels_added INTEGER DEFAULT 0, msgs_processed INTEGER DEFAULT 0)''')
c.execute('SELECT value FROM settings WHERE key = "stats_anchor_time"')
if not c.fetchone():
c.execute('INSERT INTO settings (key, value) VALUES (?, ?)', ("stats_anchor_time", str(int(time.time()))))
conn.commit()
conn.close()
def increment_daily_stat(column, count=1):
today = datetime.datetime.now().strftime("%Y-%m-%d")
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('INSERT OR IGNORE INTO daily_stats (date, autodms, starts, channels_added, msgs_processed) VALUES (?, 0, 0, 0, 0)', (today,))
c.execute(f'UPDATE daily_stats SET {column} = {column} + ? WHERE date = ?', (count, today))
conn.commit()
conn.close()
def get_daily_data(date_str):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT autodms, starts, channels_added, msgs_processed FROM daily_stats WHERE date = ?', (date_str,))
row = c.fetchone()
conn.close()
if row: return {"autodms": row[0], "starts": row[1], "channels_added": row[2], "msgs_processed": row[3]}
return {"autodms": 0, "starts": 0, "channels_added": 0, "msgs_processed": 0}
def get_custom_text(key, default_val):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT value FROM custom_texts WHERE key = ?', (key,))
res = c.fetchone()
conn.close()
return res[0] if res else default_val
def set_custom_text(key, value):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('INSERT OR REPLACE INTO custom_texts (key, value) VALUES (?, ?)', (key, value))
conn.commit()
conn.close()
def refresh_cache():
global WATCHED_CACHE
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT chat_id FROM watched_channels ORDER BY id ASC')
rows = c.fetchall()
WATCHED_CACHE =[row[0] for row in rows]
conn.close()
def add_watched_channel(chat_id, chat_title, owner_id=None, is_paid=0, member_count="Unknown"):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
try:
c.execute('SELECT is_paid_promo FROM watched_channels WHERE chat_id = ?', (chat_id,))
curr = c.fetchone()
is_new = False if curr else True
final_is_paid = is_paid
if curr and curr[0] == 1:
final_is_paid = 1
c.execute('INSERT OR REPLACE INTO watched_channels (chat_id, chat_title, owner_id, is_paid_promo) VALUES (?, ?, ?, ?)', (chat_id, chat_title, owner_id, final_is_paid))
conn.commit()
if is_new:
increment_daily_stat('channels_added')
add_to_json(chat_id, chat_title, member_count) # JSON UPDATE
refresh_cache()
return True
except sqlite3.IntegrityError:
return False
finally:
conn.close()
def remove_watched_channel(chat_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('DELETE FROM watched_channels WHERE chat_id = ?', (chat_id,))
conn.commit()
conn.close()
remove_from_json(chat_id) # JSON UPDATE
refresh_cache()
def get_channel_position(chat_id):
try: return WATCHED_CACHE.index(chat_id) + 1
except ValueError: return 0
def get_user_watched_channels(user_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT chat_id, chat_title FROM watched_channels WHERE owner_id = ?', (user_id,))
rows = c.fetchall()
conn.close()
return rows
def add_user(user_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
try:
c.execute('INSERT INTO users (user_id) VALUES (?)', (user_id,))
conn.commit()
except: pass
conn.close()
def get_all_users():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT user_id FROM users')
rows = c.fetchall()
conn.close()
return [row[0] for row in rows]
def save_broadcast_log(user_id, message_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('INSERT OR REPLACE INTO broadcast_logs (user_id, message_id) VALUES (?, ?)', (user_id, message_id))
conn.commit()
conn.close()
def get_broadcast_logs():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT user_id, message_id FROM broadcast_logs')
logs = c.fetchall()
conn.close()
return logs
def clear_broadcast_logs():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('DELETE FROM broadcast_logs')
conn.commit()
conn.close()
def get_stats():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT COUNT() FROM users')
users_count = c.fetchone()[0]
c.execute('SELECT COUNT() FROM watched_channels')
chats_count = c.fetchone()[0]
conn.close()
return users_count, chats_count
def set_config(key, value):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)', (key, value))
conn.commit()
conn.close()
def get_config(key):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT value FROM settings WHERE key = ?', (key,))
res = c.fetchone()
conn.close()
return res[0] if res else None
init_db()
init_daily_db()
# --- CONSTANTS & DEFAULT TEXTS ---
REACTION_EMOJIS =["โค๏ธ","๐ฅฐ","๐ฅ","๐","๐","๐","โบ๏ธ","๐ฏ","๐","โค๏ธโ๐ฅ","๐ค","๐","๐คฉ", "๐", "๐", "๐ค", "๐", "โก๏ธ", "๐", "๐"]
START_MEDIA = "https://envs.sh/iZf.jpg"
DEFAULT_START_MSG = """<b>Mแดสแดษช Rแดแดแดแดษชแดษด + Vษชแดแดก Bแดแด</b>
๐ฃ <code>I Aแดแดแดแดแดแดษชแดแดสสส Mแดสแดษช Rแดแดแดแด Tแด Eแด แดสส Nแดแดก Pแด๊ฑแด Iษด Yแดแดส Cสแดษดษดแดส Wษชแดส Eแดแดแดษช๊ฑ + Vษชแดแดก</code>
<b>Hแดแดก Tแด Usแด:</b>
โ 1. <b>Mแดแดแด Mแด Aแด
แดษชษด Iษด Yแดแดส Cสแดษดษดแดส</b>
โ 2. <b>Mแดแดแด Aแด
แดษชษด Sแดแดสแด Rแดแดแดแดษชแดษด</b>"""
DEFAULT_HELP_MSG = """๐ <b>๐๐ผ๐ ๐๐ผ ๐จ๐๐ฒ ๐ ๐๐น๐๐ถ ๐ฅ๐ฒ๐ฎ๐ฐ๐ ๐๐ผ๐:</b>
1. โ Add me as admin in your channel
2. ๐ Give Admin Full Permission
3. Bots will join automatically based on queue.
โจ Use /start to return to main menu."""
DEFAULT_ALLCMD_MSG = """๐ฎ <b>ALL AVAILABLE COMMANDS</b> ๐ฎ
๐ฐ <b>Bแดsษชแด Cแดแดแดแดษดแด
s:</b>
โ /start : Cสแดแดแด Iา Bแดแด Is Aสษชแด แด
โ /use : Gแดแด Usแดษขแด Hแดสแด
โ /allCommand : Sสแดแดก Tสษชs Lษชsแด
โ /scan : Scan Your Channels
โ /mycommunity : Cแดษดษดแดแดแดแดแด
Cสแดษดษดแดสs
โ ๏ธ <b>Nแดแดแด:</b> Use Tสแดsแด Cแดแดแดแดษดแด
s Iษดsษชแด
แด Tสแด Cสแดษดษดแดส."""
DEFAULT_USE_CMD = """๐ <b>๐๐ผ๐ ๐๐ผ ๐จ๐๐ฒ ๐ ๐๐น๐๐ถ ๐ฅ๐ฒ๐ฎ๐ฐ๐ ๐๐ผ๐:</b>
1. <b>๐ฉ๐ถ๐ฑ๐ฒ๐ผ ๐๐ผ๐บ๐ถ๐ป๐ด ๐ฆ๐ผ๐ผ๐ป</b>
2. <b>๐ฉ๐ถ๐ฑ๐ฒ๐ผ ๐๐ผ๐บ๐ถ๐ป๐ด ๐ฆ๐ผ๐ผ๐ป</b>
3. <b>๐ฉ๐ถ๐ฑ๐ฒ๐ผ ๐๐ผ๐บ๐ถ๐ป๐ด ๐ฆ๐ผ๐ผ๐ป.</b>"""
DEFAULT_SETUP_COMPLETE = """โ
<b>Setup Complete!</b>
๐ค IDs Joined: {success}
๐ฆ Batch: {batch}
๐ฅ Reactions: <b>Active</b>"""
DEFAULT_SCAN_NO_COMM_MSG = "โ ๏ธ Add your community then Scan!"
DEFAULT_SCAN_FINAL_MSG = """โ ๏ธ **Sแดแดแดสษชแดส Sแดแดษด Cแดแดแดสแดแดแดแด
**
โโโโโโโโโโโโโโโโโโโ
๐ **Cสแดษดษดแดสs Sแดแดษดษดแดแด
:** {count}
๐ก๏ธ **Oแด แดสแดสส Sแดแดแดแดs:** Sแดแดแดสแดแด
{scan_results}
โโโโโโโโโโโโโโโโโโโ
โ
Aษดแดษช-Rแดแดแดสแด Sสษชแดสแด
s Oษดสษชษดแด
โ
Tสสแดแดแด Dแดแดแดแดแดษชแดษด Aแดแดษชแด แด"""
DEFAULT_MYCOMMUNITY_MSG = "โ You haven't added this bot to any channel or group yet."
DEFAULT_SUPPORT_MSG = "โญ Any problem to contact 24/7 costumer service @ezupo โ
"
# ๐ NEW DYNAMIC STATS TEMPLATE
DEFAULT_STATS_MSG = """โโโโ๐ GLOBAL STATS ๐โโโโ
๐ค Community Members: {users}+
๐ก Protected Channels: {chats}+
๐ System Uptime: 99.98%
โ๐PROTECT PERFORMANCE๐โ
ยฉ๏ธ Copyright Reports Blocked: {copyright}+
๐ Messages Processed: {msgs_processed}+
๐ฏ Protection Accuracy: 99.99%
๐ก Strikes Prevented: {strikes}+
๐ซ Spam Messages Blocked: {spam}+
๐คFake Ids Report Block: 5919+"""
DEFAULT_ADMIN_MSG = """๐ <b>OWNER ADMIN PANEL</b> ๐\n
๐ <b>Owner Only Commands:</b>
โ /day : View Today & Yesterday Stats ๐
โ /setmedia : Reply to Photo/Video to set Start Media
โ /buttons : Change Start Menu Buttons Text/URL
โ /control : Manage Bot Texts & Premium Emojis
โ /broadcast : Broadcast Message to Users
โ /broadcastinfo : Info About Broadcast Actions
โ /stats : View Bot Statistics
โ /send : ๐ Manually Send Report Scan to All Channels
โ /autodm : Set Auto DM for Join Requests
โ /fsub : Force Sub / Link Setup
โ /syncjson : ๐ Save All Old Channels & Members to JSON
โ /admin : Show This List
๐ค <b>Public / User Commands:</b>
โ /start : Main Menu
โ /scan : Scan Connected Channels
โ /stats : Show Bot Stats"""
DEFAULT_BROADCAST_INFO_MSG = """๐๏ธ <b>Broadcast All Info Command</b>\n\nTo : /broadcast - Start New Broadcast\nTo : /stopBroadcast - Stop Running Broadcast\nTo : /BroadMessageDelete - Delete Last Broadcast Message\nTo : /stats - Check Users"""
BTN1_DEFAULT_NAME = "โ๐๐ฑ๐ฑ ๐๐ต๐ฎ๐ป๐ป๐ฒ๐น"
BTN1_DEFAULT_URL = "https://t.me/{username}?startchannel=true&admin=change_info+post_messages+edit_messages+delete_messages+restrict_members+invite_users+pin_messages+promote_members+manage_video_chats+anonymous+manage_chat+manage_topics+post_stories+edit_stories+delete_stories"
BTN2_DEFAULT_NAME = "โ๐๐ฑ๐ฑ ๐๐ฟ๐ผ๐๐ฝ"
BTN2_DEFAULT_URL = "https://t.me/{username}?startgroup=true&admin=change_info+post_messages+edit_messages+delete_messages+restrict_members+invite_users+pin_messages+promote_members+manage_video_chats+anonymous+manage_chat+manage_topics+post_stories+edit_stories+delete_stories"
def get_start_keyboard(bot_username):
b1_n = get_config("btn1_name") or BTN1_DEFAULT_NAME
b1_u = get_config("btn1_url") or BTN1_DEFAULT_URL.format(username=bot_username)
b2_n = get_config("btn2_name") or BTN2_DEFAULT_NAME
b2_u = get_config("btn2_url") or BTN2_DEFAULT_URL.format(username=bot_username)
return InlineKeyboardMarkup([
[InlineKeyboardButton(b1_n, url=b1_u), InlineKeyboardButton(b2_n, url=b2_u)],
[InlineKeyboardButton("๐ ๐จ๐๐ฎ๐ด๐ฒ", callback_data="help_usage")],
[InlineKeyboardButton("๐ ๐ฆ๐๐๐ก", callback_data="trigger_scan")]
])
def get_mycommunity_keyboard(bot_username):
b1_n = get_config("btn1_name") or BTN1_DEFAULT_NAME
b1_u = get_config("btn1_url") or BTN1_DEFAULT_URL.format(username=bot_username)
b2_n = get_config("btn2_name") or BTN2_DEFAULT_NAME
b2_u = get_config("btn2_url") or BTN2_DEFAULT_URL.format(username=bot_username)
return InlineKeyboardMarkup([
[InlineKeyboardButton(b1_n, url=b1_u), InlineKeyboardButton(b2_n, url=b2_u)],
[InlineKeyboardButton("๐ Refresh", callback_data="refresh_community")],
[InlineKeyboardButton("๐ SCAN", callback_data="trigger_scan")]
])
async def send_start_menu(client, chat_id):
buttons = get_start_keyboard(client.me.username)
caption_text = get_custom_text("start_msg", DEFAULT_START_MSG)
media_val = get_config("start_media") or START_MEDIA
is_video = get_config("is_video") == "True"
try:
if is_video:
await client.send_video(chat_id, media_val, caption=caption_text, reply_markup=buttons, parse_mode=ParseMode.HTML)
else:
await client.send_photo(chat_id, media_val, caption=caption_text, reply_markup=buttons, parse_mode=ParseMode.HTML)
except Exception as e:
await client.send_message(chat_id, caption_text, reply_markup=buttons, parse_mode=ParseMode.HTML)
def get_target_bots(chat_id):
position = get_channel_position(chat_id)
if position == 0: return[], 0
batch_index = ((position - 1) // 500) + 1
if batch_index > 5: batch_index = 5
return USERBOTS_BATCHES.get(batch_index,[]), batch_index
async def load_userbots():
global USERBOTS_BATCHES, ALL_USERBOTS, ALL_PRIVATE_USERBOTS, PRIVATE_BOTS_MAP
print("โณ Loading Global Userbots...")
USERBOTS_BATCHES = {1: [], 2: [], 3: [], 4:[], 5:[]}
ALL_USERBOTS =[]
session_files = glob.glob("sessions/*.session")
session_files.sort()
for s_file in session_files:
try:
filename = os.path.basename(s_file)
session_name = filename.replace(".session", "")
ub = Client(name=session_name, api_id=API_ID, api_hash=API_HASH, workdir="sessions/")
await ub.start()
ALL_USERBOTS.append(ub)
USERBOTS_BATCHES[1].append(ub)
except Exception as e:
try: os.remove(s_file)
except: pass
print(f"๐ Global Active: {len(ALL_USERBOTS)}")
async def send_raw_api_message(client, chat_id, text, reply_markup_list, photo_url_or_id=None):
if text:
text = text.replace("<emoji id=", "<tg-emoji emoji-id=").replace("</emoji>", "</tg-emoji>")
url = f"https://api.telegram.org/bot{BOT_TOKEN}/"
payload = {
"chat_id": chat_id,
"parse_mode": "HTML",
"reply_markup": {"inline_keyboard": reply_markup_list}
}
if photo_url_or_id:
url += "sendPhoto"
payload["photo"] = photo_url_or_id
payload["caption"] = text
else:
url += "sendMessage"
payload["text"] = text
headers = {'Content-Type': 'application/json'}
req = urllib.request.Request(url, data=json.dumps(payload).encode('utf-8'), headers=headers)
def fetch():
try:
with urllib.request.urlopen(req, timeout=10) as response:
return json.loads(response.read().decode())
except Exception:
return {"ok": False}
res = await asyncio.to_thread(fetch)
if res and not res.get("ok"):
pyro_kb = []
for row in reply_markup_list:
pyro_row = []
for btn in row:
if "url" in btn: pyro_row.append(InlineKeyboardButton(btn["text"], url=btn["url"]))
else: pyro_row.append(InlineKeyboardButton(btn["text"], callback_data=btn.get("callback_data", "none")))
pyro_kb.append(pyro_row)
pyro_markup = InlineKeyboardMarkup(pyro_kb)
pyro_text = text.replace("<tg-emoji emoji-id=", "<emoji id=").replace("</tg-emoji>", "</emoji>")
try:
if photo_url_or_id:
await client.send_photo(chat_id, photo_url_or_id, caption=pyro_text, reply_markup=pyro_markup, parse_mode=ParseMode.HTML)
else:
await client.send_message(chat_id, pyro_text, reply_markup=pyro_markup, parse_mode=ParseMode.HTML)
except Exception: pass
FSUB_STATE = {}
async def is_user_joined(client, user_id):
if user_id in ADMINS:
return True
fsub_on = get_config("fsub_enabled")
if fsub_on != "1":
return True
fsub_id = get_config("fsub_channel_id")
fsub_id_2 = get_config("fsub_channel_id_2")
fsub_id_3 = get_config("fsub_channel_id_3")
if not fsub_id and not fsub_id_2 and not fsub_id_3:
return True
async def check_membership(target_id):
if not target_id: return True
try:
target = int(target_id) if target_id.lstrip('-').isdigit() else target_id
member = await client.get_chat_member(target, user_id)
if member.status in [ChatMemberStatus.LEFT, ChatMemberStatus.BANNED]:
return False
return True
except UserNotParticipant:
return False
except Exception:
return True
if fsub_id and not await check_membership(fsub_id): return False
if fsub_id_2 and not await check_membership(fsub_id_2): return False
if fsub_id_3 and not await check_membership(fsub_id_3): return False
return True
async def send_fsub_message(client, chat_id):
ftext = get_custom_text("fsub_msg", "โ ๏ธ **You must join our main channels to use this bot!**")
flink1 = get_config("fsub_link") or "https://t.me/"
n1 = get_config("fsub_b_1_name") or "JOIN CH 1"
flink2 = get_config("fsub_link_2")
n2 = get_config("fsub_b_2_name") or "JOIN CH 2"
flink3 = get_config("fsub_link_3")
n3 = get_config("fsub_b_3_ch_name") or "JOIN CH 3"
n_joined = get_config("fsub_b_joined_name") or get_config("fsub_b_3_name") or "โ
JOINED"
join_buttons_row = []
fsub_id = get_config("fsub_channel_id")
fsub_id_2 = get_config("fsub_channel_id_2")
fsub_id_3 = get_config("fsub_channel_id_3")
if fsub_id: join_buttons_row.append({"text": n1, "url": flink1, "style": "primary"})
if fsub_id_2 and flink2: join_buttons_row.append({"text": n2, "url": flink2, "style": "primary"})
if fsub_id_3 and flink3: join_buttons_row.append({"text": n3, "url": flink3, "style": "primary"})
kb = []
if join_buttons_row:
if len(join_buttons_row) > 2:
kb.append(join_buttons_row[:2])
kb.append(join_buttons_row[2:])
else:
kb.append(join_buttons_row)
kb.append([{"text": n_joined, "callback_data": "fsub_joined_check", "style": "success"}])
await send_raw_api_message(client, chat_id, ftext, kb, None)
@app.on_message(filters.private, group=-1)
async def fsub_global_message_watcher(client, message):
if not await is_user_joined(client, message.from_user.id):
await send_fsub_message(client, message.chat.id)
raise StopPropagation
@app.on_callback_query(group=-1)
async def fsub_global_callback_watcher(client, callback_query):
if callback_query.data.startswith("fsub_") or callback_query.data.startswith("ctrl_") or callback_query.data.startswith("adm_"):
return
if not await is_user_joined(client, callback_query.from_user.id):
await send_fsub_message(client, callback_query.message.chat.id)
await callback_query.answer("โ ๏ธ Please join the channels first!", show_alert=True)
raise StopPropagation
@app.on_message(filters.command("fsub") & filters.user(ADMINS))
async def set_fsub_cmd(client, message):
kb = InlineKeyboardMarkup([
[InlineKeyboardButton("๐ Edit Fsub Text", callback_data="fsub_text")],
[InlineKeyboardButton("๐ Turn ON", callback_data="fsub_on"), InlineKeyboardButton("โ
Turn OFF", callback_data="fsub_off")],
[InlineKeyboardButton("1๏ธโฃ Set CH1 Link", callback_data="fsub_link"), InlineKeyboardButton("1๏ธโฃ Set CH1 ID", callback_data="fsub_id")],
[InlineKeyboardButton("2๏ธโฃ Set CH2 Link", callback_data="fsub_link_2"), InlineKeyboardButton("2๏ธโฃ Set CH2 ID", callback_data="fsub_id_2")],
[InlineKeyboardButton("3๏ธโฃ Set CH3 Link", callback_data="fsub_link_3"), InlineKeyboardButton("3๏ธโฃ Set CH3 ID", callback_data="fsub_id_3")],
[InlineKeyboardButton("๐ Edit Btn 1 (CH1)", callback_data="fsub_b1_name"), InlineKeyboardButton("๐ Edit Btn 2 (CH2)", callback_data="fsub_b2_name")],
[InlineKeyboardButton("๐ Edit Btn 3 (CH3)", callback_data="fsub_b3_ch_name"), InlineKeyboardButton("๐ Edit Joined", callback_data="fsub_b_joined")],
[InlineKeyboardButton("๐๏ธ Preview FSub Message", callback_data="fsub_preview")]
])
await message.reply("๐ **Force Subscribe Setup Panel**\n\n*(Note: You can setup up to 3 channels. If you want to remove any button, send `none` in Link or ID setup)*", reply_markup=kb)
@app.on_callback_query(filters.regex(r"^fsub_(.*)"))
async def fsub_cb(client, cb):
action = cb.data.replace("fsub_", "")
uid = cb.from_user.id
if action == "on":
set_config("fsub_enabled", "1")
await cb.answer("โ
Force Sub Enabled", show_alert=True)
elif action == "off":
set_config("fsub_enabled", "0")
await cb.answer("๐ Force Sub Disabled", show_alert=True)
elif action == "text":
FSUB_STATE[uid] = {"step": "TEXT"}
await cb.message.reply("๐ Send the **New Fsub Text** (Supports HTML/Premium Emojis):")
elif action == "link":
FSUB_STATE[uid] = {"step": "LINK"}
await cb.message.reply("๐ Send the **Channel 1 Link** for the first JOIN button:\n*(Send `none` to disable/remove CH1 button)*")
elif action == "id":
FSUB_STATE[uid] = {"step": "ID"}
await cb.message.reply("๐ Send the **Channel 1 ID or Username** (eg. -100123456789 or @username):\n*(Send `none` to disable/remove CH1 button)*")
elif action == "link_2":
FSUB_STATE[uid] = {"step": "LINK_2"}
await cb.message.reply("๐ Send the **Channel 2 Link** for the second JOIN button:\n*(Send `none` to disable/remove CH2 button)*")
elif action == "id_2":
FSUB_STATE[uid] = {"step": "ID_2"}
await cb.message.reply("๐ Send the **Channel 2 ID or Username**:\n*(Send `none` to disable/remove CH2 button)*")
elif action == "link_3":
FSUB_STATE[uid] = {"step": "LINK_3"}
await cb.message.reply("๐ Send the **Channel 3 Link** for the third JOIN button:\n*(Send `none` to disable/remove CH3 button)*")
elif action == "id_3":
FSUB_STATE[uid] = {"step": "ID_3"}
await cb.message.reply("๐ Send the **Channel 3 ID or Username**:\n*(Send `none` to disable/remove CH3 button)*")
elif action == "b1_name":
FSUB_STATE[uid] = {"step": "B1_NAME"}
await cb.message.reply("๐ Send the **New Name** for Button 1 (CH 1):")
elif action == "b2_name":
FSUB_STATE[uid] = {"step": "B2_NAME"}
await cb.message.reply("๐ Send the **New Name** for Button 2 (CH 2):")
elif action == "b3_ch_name":
FSUB_STATE[uid] = {"step": "B3_CH_NAME"}
await cb.message.reply("๐ Send the **New Name** for Button 3 (CH 3):")
elif action == "b_joined":
FSUB_STATE[uid] = {"step": "B_JOINED"}
await cb.message.reply("๐ Send the **New Name** for the Joined Button (e.g. โ
JOINED):")
elif action == "preview":
await send_fsub_message(client, cb.message.chat.id)
await cb.answer("๐๏ธ Fsub Preview Generated!", show_alert=False)
elif action == "joined_check":
if not await is_user_joined(client, cb.from_user.id):
return await cb.answer("โ You haven't joined all channels yet!", show_alert=True)
try: await cb.message.delete()
except Exception: pass
await send_start_menu(client, cb.message.chat.id)
try: await cb.answer()
except: pass
CONTROL_STATE = {}
@app.on_message(filters.command("setmedia") & filters.user(ADMINS))
async def set_media_cmd(client, message):
if not message.reply_to_message or (not message.reply_to_message.photo and not message.reply_to_message.video):
return await message.reply("โ ๏ธ **Please reply to a Photo or Video** to set it as the Start Menu media.")
if message.reply_to_message.photo:
set_config("start_media", message.reply_to_message.photo.file_id)
set_config("is_video", "False")
await message.reply("โ
**Start Photo updated successfully!**")
elif message.reply_to_message.video:
set_config("start_media", message.reply_to_message.video.file_id)
set_config("is_video", "True")
await message.reply("โ
**Start Video updated successfully!**")
@app.on_message(filters.command("control") & filters.user(ADMINS))
async def control_cmd(client, message):
kb = InlineKeyboardMarkup([
[InlineKeyboardButton("Start Msg", callback_data="ctrl_start_msg"), InlineKeyboardButton("Help Msg", callback_data="ctrl_help_usage_msg")],
[InlineKeyboardButton("Use Cmd Msg", callback_data="ctrl_use_cmd_msg")],
[InlineKeyboardButton("All Command Msg", callback_data="ctrl_allcommand_msg"), InlineKeyboardButton("Setup Complete", callback_data="ctrl_setup_complete_msg")],
[InlineKeyboardButton("Scan Final Msg", callback_data="ctrl_scan_final_msg"), InlineKeyboardButton("Scan No Comm Msg", callback_data="ctrl_scan_no_comm_msg")],
[InlineKeyboardButton("My Community Msg", callback_data="ctrl_mycommunity_msg"), InlineKeyboardButton("Support Msg", callback_data="ctrl_support_msg")],
[InlineKeyboardButton("Admin Msg", callback_data="ctrl_admin_msg"), InlineKeyboardButton("Stats Msg", callback_data="ctrl_stats_msg")],
[InlineKeyboardButton("Broadcast Info", callback_data="ctrl_broadcast_info_msg")]
])
await message.reply("๐ **Text Control Panel**\n\nSelect the message you want to edit:", reply_markup=kb)
@app.on_callback_query(filters.regex(r"^ctrl_(.*)"))
async def cb_control(client, cb):
key = cb.data.replace("ctrl_", "")
CONTROL_STATE[cb.from_user.id] = {"key": key}
await cb.message.reply(f"๐ Send the new text for `{key}` now.\nโ
**You can use HTML tags and Premium Emojis!**")
await cb.answer()
BUTTONS_STATE = {}
@app.on_message(filters.command("buttons") & filters.user(ADMINS))
async def buttons_setup_cmd(client, message):
BUTTONS_STATE[message.from_user.id] = {"step": "BTN1_NAME"}
await message.reply("โ๏ธ **Start Menu Buttons Setup**\n\n๐ Send the **NAME** for Button 1 (e.g. `โ Add Channel`):")
@app.on_message(filters.command("start") & filters.private)
async def start_private(client, message):
add_user(message.from_user.id)
increment_daily_stat("starts")
if message.from_user.id in BROADCAST_STATE: del BROADCAST_STATE[message.from_user.id]
if message.from_user.id in AUTODM_STATE: del AUTODM_STATE[message.from_user.id]
if len(message.command) > 1 and "startchannel" in message.command[1]: return
await send_start_menu(client, message.chat.id)
@app.on_callback_query(filters.regex("help_usage"))
async def help_usage_callback(client, callback_query):
text = get_custom_text("help_usage_msg", DEFAULT_HELP_MSG)
buttons = InlineKeyboardMarkup([[InlineKeyboardButton("๐ Back", callback_data="back_home")]])
if callback_query.message.media:
await callback_query.message.edit_caption(caption=text, reply_markup=buttons, parse_mode=ParseMode.HTML)
else:
await callback_query.message.edit_text(text=text, reply_markup=buttons, parse_mode=ParseMode.HTML)
@app.on_callback_query(filters.regex("back_home"))
async def back_home_callback(client, callback_query):
buttons = get_start_keyboard(client.me.username)
caption_text = get_custom_text("start_msg", DEFAULT_START_MSG)
if callback_query.message.media:
await callback_query.message.edit_caption(caption=caption_text, reply_markup=buttons, parse_mode=ParseMode.HTML)
else:
await callback_query.message.edit_text(text=caption_text, reply_markup=buttons, parse_mode=ParseMode.HTML)
@app.on_message(filters.command("start") & (filters.channel | filters.group))
async def activate_in_channel(client, message):
chat = message.chat
adder_id = message.from_user.id if message.from_user else None
try:
mem_count = await client.get_chat_members_count(chat.id)
except Exception:
mem_count = "Unknown"
add_watched_channel(chat.id, chat.title or "Unknown", owner_id=adder_id, member_count=mem_count)
target_bots, batch_num = get_target_bots(chat.id)
msg = await message.reply(f"โก **Verified!**\n๐ **IDs Joining...**")
invite_link = None
try:
if chat.username: invite_link = chat.username
else: invite_link = await client.export_chat_invite_link(chat.id)
except Exception:
await msg.edit("โ **Admin Permission Error!** I need 'Invite Users' permission.")
return
success_count = 0
for ub in target_bots:
try:
await ub.join_chat(invite_link)
success_count += 1
await asyncio.sleep(random.uniform(2, 4))
except UserAlreadyParticipant: success_count += 1
except Exception: pass
setup_msg = get_custom_text("setup_complete_msg", DEFAULT_SETUP_COMPLETE).replace("{success}", str(success_count)).replace("{batch}", str(batch_num))
await msg.edit(setup_msg, parse_mode=ParseMode.HTML)
@app.on_message(filters.command("scan"))
async def scan_command_handler(client, message):
await execute_scan_animation(client, message.chat.id, message.from_user.id)
@app.on_callback_query(filters.regex("trigger_scan"))
async def trigger_scan_callback(client, callback_query):
await execute_scan_animation(client, callback_query.message.chat.id, callback_query.from_user.id, callback_query)
async def execute_scan_animation(client, chat_id, user_id, cb=None):
channels = get_user_watched_channels(user_id)
count = len(channels)
if count == 0:
no_comm_text = get_custom_text("scan_no_comm_msg", DEFAULT_SCAN_NO_COMM_MSG)
if cb:
await cb.answer(no_comm_text, show_alert=True)
else:
await client.send_message(chat_id, no_comm_text, parse_mode=ParseMode.HTML)
return
if cb:
msg = cb.message
else:
msg = await client.send_message(chat_id, "Initializing deep security scan...")
scan_results = ""
today_str = datetime.datetime.now().strftime("%Y-%m-%d")
for c_id, c_title in channels:
try:
chat = await client.get_chat(c_id)
if getattr(chat, 'is_restricted', False):
scan_results += f"๐ซ <b>{c_title}</b> : Ban / Restricted\n"
continue
try: mem_count = await client.get_chat_members_count(c_id)
except: mem_count = 500
seed_str = f"{c_id}_{today_str}"
rng = random.Random(seed_str)
if mem_count < 100: reports_blocked = 0
elif mem_count <= 200: reports_blocked = rng.randint(1, 2)
elif mem_count <= 5000: reports_blocked = rng.randint(2, 20)
elif mem_count <= 20000: reports_blocked = rng.randint(20, 50)
else: reports_blocked = rng.randint(50, 100)
reasons = ["Cแดแดสสษชษขสแด", "Sแดแดแด", "Pแดสษดแดษขสแดohส", "Vษชแดสแดษดแดแด", "Iสสแดษขแดส Sแดแดาา", "Fแดแดแด Cแดษดแดแดษดแด"]
reason = rng.choice(reasons)
chat_name = chat.title or c_title
scan_results += f"โ
<b>{chat_name}</b> : Sแดแดแดสแดแด
| ๐ก๏ธ {reports_blocked} Rแดแดแดสแดs ({reason})\n"
except Exception:
scan_results += f"๐ซ <b>{c_title}</b> : Ban / Inaccessible\n"
frames = [
f"โข๏ธ **SYSTEM OVERRIDE INITIATED** โข๏ธ\n\nScanning {count} Connected Nodes...\n[โโโโโโโโโโโโโโโ] 10%\n\n> โ๏ธ Initializing Deep Engine...",
f"โข๏ธ **SYSTEM OVERRIDE INITIATED** โข๏ธ\n\nScanning {count} Connected Nodes...\n[โโโโโโโโโโโโโโโ] 30%\n\n> ๐ก Pinging Telegram Main Servers...",
f"โข๏ธ **SYSTEM OVERRIDE INITIATED** โข๏ธ\n\nScanning {count} Connected Nodes...\n[โโโโโโโโโโโโโโโ] 50%\n\n> ๐ก๏ธ Bypassing Firewalls & Fetching Logs...",
f"โข๏ธ **SYSTEM OVERRIDE INITIATED** โข๏ธ\n\nScanning {count} Connected Nodes...\n[โโโโโโโโโโโโโโโ] 75%\n\n> โ ๏ธ Isolating Spam & Ban Vectors...",
f"โข๏ธ **SYSTEM OVERRIDE INITIATED** โข๏ธ\n\nScanning {count} Connected Nodes...\n[โโโโโโโโโโโโโโโ] 90%\n\n> ๐ฌ Extracting Real-time Report Data...",
f"โ
**DECRYPTION SUCCESSFUL** โ
\n\nScanning {count} Connected Nodes...\n[โโโโโโโโโโโโโโโ] 100%\n\n> ๐ Compiling Security Matrix..."
]
try:
for frame in frames:
if cb and msg.photo: await msg.edit_caption(frame)
elif cb and msg.video: await msg.edit_caption(frame)
else: await msg.edit_text(frame)
await asyncio.sleep(1.2)
final_text_template = get_custom_text("scan_final_msg", DEFAULT_SCAN_FINAL_MSG)
final_text = final_text_template.replace("{count}", str(count)).replace("{scan_results}", scan_results)
if cb and (msg.photo or msg.video): await msg.edit_caption(final_text, parse_mode=ParseMode.HTML)
else: await msg.edit_text(final_text, parse_mode=ParseMode.HTML)
except Exception as e:
pass
BROADCAST_STATE = {}
IS_BROADCASTING = False
STOP_BROADCAST = False
AUTODM_STATE = {}
@app.on_message(filters.command("day") & filters.user(ADMINS))
async def day_stats_command(client, message):
users_count, chats_count = get_stats()
today = datetime.datetime.now().strftime("%Y-%m-%d")
yesterday = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
t_data = get_daily_data(today)
y_data = get_daily_data(yesterday)
t_total_users = t_data["autodms"] + t_data["starts"]
y_total_users = y_data["autodms"] + y_data["starts"]
text = f"""๐ <b>๐๐ข๐ง ๐ฆ๐ง๐๐ง๐๐ฆ๐ง๐๐ฆ</b> ๐
๐ค Total Users: {users_count}
๐ข Connected Channels/Groups: {chats_count}
๐
<b>TODAY ({today})</b>
โ Auto DMs Sent: {t_data['autodms']}
โ Manual Starts: {t_data['starts']}
โ <b>Total New Users Today:</b> {t_total_users}
โ Channels Made Admin: {t_data['channels_added']}
โ Messages Processed (Reports Sent): {t_data['msgs_processed']}
๐
<b>YESTERDAY ({yesterday})</b>
โ Auto DMs Sent: {y_data['autodms']}
โ Manual Starts: {y_data['starts']}
โ <b>Total New Users Yesterday:</b> {y_total_users}
โ Channels Made Admin: {y_data['channels_added']}
โ Messages Processed (Reports Sent): {y_data['msgs_processed']}"""
await message.reply_text(text, parse_mode=ParseMode.HTML)
@app.on_message(filters.command("stats"))
async def stats_command(client, message):
users, chats = get_stats()
anchor_time = float(get_config("stats_anchor_time") or time.time())
elapsed_days = (time.time() - anchor_time) / 86400.0
base_users = 1233297 + users
base_chats = 24482 + chats
base_strikes = 6384
base_spam = 23680
base_copyright = 5768
curr_strikes = int(base_strikes + (1000 * elapsed_days))
curr_spam = int(base_spam + (1500 * elapsed_days))
curr_copyright = int(base_copyright + (1200 * elapsed_days))
today = datetime.datetime.now().strftime("%Y-%m-%d")
daily_data = get_daily_data(today)
curr_msgs_processed = 1782037 + daily_data["msgs_processed"]
text_template = get_custom_text("stats_msg", DEFAULT_STATS_MSG)
stats_text = text_template.replace("{users}", str(base_users))\
.replace("{chats}", str(base_chats))\
.replace("{strikes}", str(curr_strikes))\
.replace("{spam}", str(curr_spam))\
.replace("{copyright}", str(curr_copyright))\
.replace("{msgs_processed}", str(curr_msgs_processed))
await message.reply_text(stats_text, quote=True, parse_mode=ParseMode.HTML)
@app.on_message(filters.command("2stats") & filters.user(ADMINS))
async def autodm_stats(client, message):
count_1 = get_config("autodm_1_count") or "0"
count_2 = get_config("autodm_2_count") or "0"
text = f"๐ **Auto DM Statistics** ๐\n\n1๏ธโฃ Default Auto DMs Sent: `{count_1}`\n2๏ธโฃ Controlled Auto DMs Sent: `{count_2}`"
await message.reply_text(text)
@app.on_message(filters.command("autodm") & filters.user(ADMINS))
async def autodm_wizard_start(client, message):
kb = InlineKeyboardMarkup([
[InlineKeyboardButton("1๏ธโฃ Default Auto DM", callback_data="adm_menu_1")],
[InlineKeyboardButton("2๏ธโฃ Controlled Auto DM", callback_data="adm_menu_2")]
])
await message.reply("โ**Auto DM Advanced Setup**\nChoose which Auto DM you want to configure:", reply_markup=kb)
@app.on_message(filters.command("broadcastinfo") & filters.user(ADMINS))
async def broadcast_info_command(client, message):
text = get_custom_text("broadcast_info_msg", DEFAULT_BROADCAST_INFO_MSG)
await message.reply(text, parse_mode=ParseMode.HTML)
@app.on_message(filters.command("broadcast") & filters.user(ADMINS))
async def broadcast_init(client, message):
if IS_BROADCASTING: return await message.reply_text("โ ๏ธ A broadcast is already running!")
BROADCAST_STATE[message.from_user.id] = {"step": "WAIT_MSG"}
await message.reply_text("๐ข **Broadcast Setup**\nPlease send the message to broadcast.\n๐ **Drop it below:**")
@app.on_message(filters.command("stopBroadcast") & filters.user(ADMINS))
async def stop_broadcast_command(client, message):
global STOP_BROADCAST, IS_BROADCASTING
if not IS_BROADCASTING: return await message.reply_text("โ No broadcast running.")
STOP_BROADCAST = True
await message.reply_text("๐ **Stopping Broadcast...**")
@app.on_message(filters.command("BroadMessageDelete") & filters.user(ADMINS))
async def delete_broadcast_messages(client, message):
logs = get_broadcast_logs()
if not logs:
return await message.reply_text("โ ๏ธ No recent broadcast messages found to delete.")
msg = await message.reply_text("๐ **Deleting last broadcast messages... Please wait.**")
deleted_count = 0
for uid, mid in logs:
try:
await client.delete_messages(chat_id=uid, message_ids=mid)
deleted_count += 1
await asyncio.sleep(0.05)
except Exception:
pass
clear_broadcast_logs()
await msg.edit_text(f"โ
**Broadcast Deletion Complete!**\n๐ Deleted from `{deleted_count}` chats.")
# ==========================================
# ๐ TELEGRAM RAW HTTP BROADCAST BYPASS ๐
# ==========================================
async def broadcast_safely(chat_id, text, btn_url):
markup = InlineKeyboardMarkup([[InlineKeyboardButton("Save your Channel", url=btn_url)]])
while True:
try:
await app.send_message(chat_id, text, reply_markup=markup)
return True
except FloodWait as e:
await asyncio.sleep(e.value + 1)
except Exception:
url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
payload = {
"chat_id": chat_id,
"text": text,
"parse_mode": "HTML",
"reply_markup": {"inline_keyboard": [[{"text": "Save your Channel", "url": btn_url}]]}
}
try:
req = urllib.request.Request(url, data=json.dumps(payload).encode('utf-8'), headers={'Content-Type': 'application/json'})
def fetch():
with urllib.request.urlopen(req, timeout=5) as response:
return json.loads(response.read().decode())
res = await asyncio.to_thread(fetch)
if res and res.get("ok"):
return True
except Exception:
pass
return False
# ==========================================
# ๐ UPGRADED OWNER MANUAL SEND REPORT (RESTART/FLOODWAIT FIX) + BATCHING SPEED UP + CUSTOM TIME
# ==========================================
async def broadcast_safely_report(chat_id, bot_username, today_str):
try:
try: mem_count = await app.get_chat_members_count(chat_id)
except: mem_count = 500
seed_str = f"{chat_id}_{today_str}"
rng = random.Random(seed_str)
if mem_count < 100: reports_blocked = 0
elif mem_count <= 200: reports_blocked = rng.randint(1, 2)
elif mem_count <= 5000: reports_blocked = rng.randint(2, 20)
elif mem_count <= 20000: reports_blocked = rng.randint(20, 50)
else: reports_blocked = rng.randint(50, 100)
reasons = ["Cแดแดสสษชษขสแด", "Sแดแดแด", "Pแดสษดแดษขสแดแดสส", "Vษชแดสแดษดแดแด", "Iสสแดษขแดส Sแดแดาา", "Fแดแดแด Cแดษดแดแดษดแด"]
reason = rng.choice(reasons)
text = (
f"๐ก **{reports_blocked} Rแดแดแดสแดs ({reason}) แดสแด Bสแดแดแดแดแด
สส @{bot_username}**\n\n"
f"โ
Yแดแดส Cสแดษดษดแดส ษชs Sแดแด แดแด
Fสแดแด Rแดแดแดสแดs ษชษด Lแดsแด 24 Hแดแดสs."
)
btn_url = f"https://t.me/{bot_username}?startchannel=true&admin=change_info+post_messages+edit_messages+delete_messages+restrict_members+invite_users+pin_messages+promote_members+manage_video_chats+anonymous+manage_chat+manage_topics+post_stories+edit_stories+delete_stories"
success = await broadcast_safely(chat_id, text, btn_url)
return success
except Exception:
return False
@app.on_message(filters.command("send") & filters.user(ADMINS))
async def manual_send_report(client, message):
args = message.command
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT chat_id FROM watched_channels')
channels = c.fetchall()
conn.close()
total_channels = len(channels)
chunk_size = 25
total_chunks = (total_channels + chunk_size - 1) // chunk_size
if total_chunks == 0:
total_chunks = 1
min_time_sec = total_chunks * 1.5
min_time_min = round(min_time_sec / 60, 2)
target_minutes = 0
if len(args) > 1 and args[1].isdigit():
target_minutes = int(args[1])
if target_minutes > 0:
target_sec = target_minutes * 60
delay = target_sec / total_chunks
if delay < 1.5:
delay = 1.5
msg = await message.reply(f"๐ **Sending Manual Security Reports (Custom Time Mode) โก**\n\n๐ **Target Time:** `{target_minutes}` minutes\nโฑ **Delay per batch:** `{round(delay, 2)}s`\n*(Normal min time is approx {min_time_min} mins)*")
else:
delay = 1.5
msg = await message.reply(f"๐ **Sending Manual Security Reports to ALL connected channels...\n(Ultra Fast Batch Mode ONโก)**\n\n*(Note: You can use `/send [minutes]` to set a custom duration. Normal minimum time is approx {min_time_min} mins)*")
bot_username = app.me.username if app.me else "teleprotectorbot"
today_str = datetime.datetime.now().strftime("%Y-%m-%d")
sent = 0
for i in range(0, total_channels, chunk_size):
chunk = channels[i:i+chunk_size]
tasks = [broadcast_safely_report(chat_id[0], bot_username, today_str) for chat_id in chunk]
results = await asyncio.gather(*tasks)
success_count = sum([1 for r in results if r])
if success_count > 0:
sent += success_count
increment_daily_stat("msgs_processed", success_count)
await asyncio.sleep(delay)
await msg.edit(f"โ
**Manual Report Broadcast Completed!**\nSuccessfully sent to: `{sent}` channels out of `{total_channels}`.")
@app.on_callback_query(filters.regex(r"^adm_"))
async def adm_callbacks(client, cb):
data = cb.data.split("_")
action = data[1]
if action == "menu":
dm_id = int(data[2])
kb = InlineKeyboardMarkup([
[InlineKeyboardButton("๐ Set Message Content", callback_data=f"adm_setmsg_{dm_id}")],
[InlineKeyboardButton("๐ Manage Buttons", callback_data=f"adm_btns_{dm_id}")],
([InlineKeyboardButton("โฑ Set Speed", callback_data=f"adm_speed_{dm_id}")] if dm_id == 2 else []),
[InlineKeyboardButton("๐ Clear This DM", callback_data=f"adm_clear_{dm_id}")]
])
dm_name = "1๏ธโฃ Default Auto DM" if dm_id == 1 else "2๏ธโฃ Controlled Auto DM"
await cb.message.edit_text(f"โ๏ธ **{dm_name} Settings**\nSelect an option below:", reply_markup=kb)
elif action == "setmsg":
dm_id = int(data[2])
AUTODM_STATE[cb.from_user.id] = {"step": "WAIT_CONTENT", "dm_id": dm_id}
await cb.message.reply("โ Please send the message/media you want to use for this Auto DM:")
elif action == "btns":
dm_id = int(data[2])
prefix = "" if dm_id == 1 else "2_"
btns_str = get_config(f"auto_dm_{prefix}buttons") or "[]"
text = f"๐ **Current Buttons for DM {dm_id}:**\n\n"
try:
btns = json.loads(btns_str)
if not btns:
text += "No buttons added yet.\n"
else:
for i, row in enumerate(btns):
text += f"**Row {i+1}:**\n"
for j, btn in enumerate(row):
text += f" [{j+1}] {btn['text']} - {btn['url']}\n"
except:
text += "Error loading buttons.\n"
kb = InlineKeyboardMarkup([
[InlineKeyboardButton("โ Add New Row", callback_data=f"adm_addrow_{dm_id}"),
InlineKeyboardButton("โ Add Same Row", callback_data=f"adm_addsame_{dm_id}")],
[InlineKeyboardButton("โ๏ธ Edit", callback_data=f"adm_edit_{dm_id}"),
InlineKeyboardButton("๐ Delete", callback_data=f"adm_del_{dm_id}")],
[InlineKeyboardButton("๐ Back", callback_data=f"adm_menu_{dm_id}")]
])
await cb.message.edit_text(text, reply_markup=kb, disable_web_page_preview=True)
elif action == "addrow":
dm_id = int(data[2])
AUTODM_STATE[cb.from_user.id] = {"step": "WAIT_BTN_NEW_ROW", "dm_id": dm_id}
await cb.message.reply("โ **Add New Row**\nSend the button name and URL in this format:\n`Button Name - https://link.com`")
elif action == "addsame":
dm_id = int(data[2])
AUTODM_STATE[cb.from_user.id] = {"step": "WAIT_BTN_SAME_ROW", "dm_id": dm_id}
await cb.message.reply("โ **Add Same Row (Side by Side)**\nSend Row Number, Button Name and URL:\n`1 Button Name - https://link.com`")
elif action == "edit":
dm_id = int(data[2])
AUTODM_STATE[cb.from_user.id] = {"step": "WAIT_BTN_EDIT", "dm_id": dm_id}
await cb.message.reply("โ๏ธ **Edit Button**\nSend Row Num, Col Num, New Name and New URL:\n`1 1 New Name - https://newlink.com`")
elif action == "del":
dm_id = int(data[2])
AUTODM_STATE[cb.from_user.id] = {"step": "WAIT_BTN_DEL", "dm_id": dm_id}
await cb.message.reply("๐ **Delete Button**\nSend Row Num and Col Num to delete:\n`1 1`")
elif action == "speed":
kb = InlineKeyboardMarkup([
[InlineKeyboardButton("โก Fast (0.5s)", callback_data="adm_setspeed_0.5"),
InlineKeyboardButton("โณ Default (2s)", callback_data="adm_setspeed_2.0")],
[InlineKeyboardButton("โ๏ธ Custom Speed", callback_data="adm_setspeed_custom")]
])
await cb.message.edit_text("โฑ **Select Controlled Auto DM Speed:**", reply_markup=kb)
elif action == "setspeed":
val = data[2]
if val == "custom":
AUTODM_STATE[cb.from_user.id] = {"step": "WAIT_SPEED_CUSTOM"}
await cb.message.reply("โ๏ธ **Custom Speed**\nSend the speed in seconds (e.g. `1.5` ya `3`):")
else:
set_config("auto_dm_2_speed", val)
await cb.answer(f"โ
Speed set to {val}s", show_alert=True)
elif action == "clear":
dm_id = int(data[2])
prefix = "" if dm_id == 1 else "2_"
set_config(f"auto_dm_{prefix}type", "")
set_config(f"auto_dm_{prefix}content", "")
set_config(f"auto_dm_{prefix}caption", "")
set_config(f"auto_dm_{prefix}buttons", "[]")
await cb.answer("โ
Auto DM Cleared Successfully!", show_alert=True)
@app.on_message(filters.private & filters.user(ADMINS) & ~filters.command(["start", "setmedia", "send", "day", "broadcast", "broadcastinfo", "stopBroadcast", "BroadMessageDelete", "stats", "2stats", "autodm", "mycommunity", "support", "use", "allcommand", "admin", "control", "buttons", "scan", "fsub", "cheak", "cheakreal", "syncjson"]))
async def master_wizard(client, message):
user_id = message.from_user.id
if user_id in FSUB_STATE:
step = FSUB_STATE[user_id]["step"]
if step == "TEXT":
new_text = message.text.html if message.text else message.caption.html
set_custom_text("fsub_msg", new_text)
await message.reply("โ
FSub text updated!")
elif step == "LINK":
if message.text.lower() == 'none': set_config("fsub_link", "")
else: set_config("fsub_link", message.text)
await message.reply("โ
FSub CH 1 link updated!")
elif step == "ID":
if message.text.lower() == 'none': set_config("fsub_channel_id", "")
else: set_config("fsub_channel_id", message.text)
await message.reply("โ
FSub CH 1 ID/Username updated!")
elif step == "LINK_2":
if message.text.lower() == 'none': set_config("fsub_link_2", "")
else: set_config("fsub_link_2", message.text)
await message.reply("โ
FSub CH 2 link updated!")
elif step == "ID_2":
if message.text.lower() == 'none': set_config("fsub_channel_id_2", "")
else: set_config("fsub_channel_id_2", message.text)
await message.reply("โ
FSub CH 2 ID/Username updated!")
elif step == "LINK_3":
if message.text.lower() == 'none': set_config("fsub_link_3", "")
else: set_config("fsub_link_3", message.text)
await message.reply("โ
FSub CH 3 link updated!")
elif step == "ID_3":
if message.text.lower() == 'none': set_config("fsub_channel_id_3", "")
else: set_config("fsub_channel_id_3", message.text)
await message.reply("โ
FSub CH 3 ID/Username updated!")
elif step == "B1_NAME":
set_config("fsub_b_1_name", message.text)
await message.reply("โ
FSub Button 1 (CH 1) Name updated!")
elif step == "B2_NAME":
set_config("fsub_b_2_name", message.text)
await message.reply("โ
FSub Button 2 (CH 2) Name updated!")
elif step == "B3_CH_NAME":
set_config("fsub_b_3_ch_name", message.text)
await message.reply("โ
FSub Button 3 (CH 3) Name updated!")
elif step == "B_JOINED":
set_config("fsub_b_joined_name", message.text)
await message.reply("โ
FSub Joined Button Name updated!")
del FSUB_STATE[user_id]
return
if user_id in BUTTONS_STATE:
step = BUTTONS_STATE[user_id]["step"]
if step == "BTN1_NAME":
set_config("btn1_name", message.text)
BUTTONS_STATE[user_id]["step"] = "BTN1_URL"
await message.reply("๐ Send **URL** for Button 1:")
elif step == "BTN1_URL":
set_config("btn1_url", message.text)
BUTTONS_STATE[user_id]["step"] = "BTN2_NAME"
await message.reply("๐ Send **NAME** for Button 2:")
elif step == "BTN2_NAME":
set_config("btn2_name", message.text)
BUTTONS_STATE[user_id]["step"] = "BTN2_URL"
await message.reply("๐ Send **URL** for Button 2:")
elif step == "BTN2_URL":
set_config("btn2_url", message.text)
del BUTTONS_STATE[user_id]
await message.reply("โ
**All Buttons Updated Successfully!** Check /start.")
return
if user_id in CONTROL_STATE:
key = CONTROL_STATE[user_id]["key"]
if message.text: new_text = message.text.html
elif message.caption: new_text = message.caption.html
else: return await message.reply("โ Please send text or media with a caption!")
set_custom_text(key, new_text)
await message.reply(f"โ
Text for `{key}` updated successfully!\n\n**Live Preview:**\n{new_text}", parse_mode=ParseMode.HTML)
del CONTROL_STATE[user_id]
return
if user_id in AUTODM_STATE:
state = AUTODM_STATE[user_id]
step = state["step"]
dm_id = state.get("dm_id", 1)
prefix = "" if dm_id == 1 else "2_"
if step == "WAIT_CONTENT":
file_id = None
file_type = "text"
caption = message.caption.html if message.caption else message.text.html if message.text else ""
if message.photo: file_id, file_type = message.photo.file_id, "photo"
elif message.video: file_id, file_type = message.video.file_id, "video"
set_config(f"auto_dm_{prefix}type", file_type)
set_config(f"auto_dm_{prefix}content", file_id or "None")
set_config(f"auto_dm_{prefix}caption", caption or "")
del AUTODM_STATE[user_id]
await message.reply(f"โ
**Auto DM {dm_id} Message Saved Successfully!**")
elif step == "WAIT_BTN_NEW_ROW":
try:
name, url = message.text.split(" - ", 1)
btns_str = get_config(f"auto_dm_{prefix}buttons") or "[]"
btns = json.loads(btns_str)
btns.append([{"text": name.strip(), "url": url.strip()}])
set_config(f"auto_dm_{prefix}buttons", json.dumps(btns))
await message.reply("โ
**Button added in a new row!**")
del AUTODM_STATE[user_id]
except:
await message.reply("โ Invalid format. Please send as: `Button Name - https://link.com`")
elif step == "WAIT_BTN_SAME_ROW":
try:
parts = message.text.split(" ", 1)
row_num = int(parts[0]) - 1
name, url = parts[1].split(" - ", 1)
btns_str = get_config(f"auto_dm_{prefix}buttons") or "[]"
btns = json.loads(btns_str)
if row_num < 0 or row_num >= len(btns):
return await message.reply("โ Invalid Row Number!")
btns[row_num].append({"text": name.strip(), "url": url.strip()})
set_config(f"auto_dm_{prefix}buttons", json.dumps(btns))
await message.reply("โ
**Button added to same row!**")
del AUTODM_STATE[user_id]
except Exception as e:
await message.reply("โ Invalid format. Make sure row number exists. Format: `1 Button Name - https://link.com`")
elif step == "WAIT_BTN_EDIT":
try:
parts = message.text.split(" ", 2)
row_num = int(parts[0]) - 1
col_num = int(parts[1]) - 1
name, url = parts[2].split(" - ", 1)
btns_str = get_config(f"auto_dm_{prefix}buttons") or "[]"
btns = json.loads(btns_str)
btns[row_num][col_num] = {"text": name.strip(), "url": url.strip()}
set_config(f"auto_dm_{prefix}buttons", json.dumps(btns))
await message.reply("โ
**Button edited successfully!**")
del AUTODM_STATE[user_id]
except:
await message.reply("โ Invalid format. Format: `1 1 New Name - https://link.com`")
elif step == "WAIT_BTN_DEL":
try:
parts = message.text.split(" ")
row_num = int(parts[0]) - 1
col_num = int(parts[1]) - 1
btns_str = get_config(f"auto_dm_{prefix}buttons") or "[]"
btns = json.loads(btns_str)
del btns[row_num][col_num]
if len(btns[row_num]) == 0:
del btns[row_num]
set_config(f"auto_dm_{prefix}buttons", json.dumps(btns))
await message.reply("โ
**Button deleted successfully!**")
del AUTODM_STATE[user_id]
except:
await message.reply("โ Invalid format. Format: `1 1`")
elif step == "WAIT_SPEED_CUSTOM":
try:
speed = float(message.text)
set_config("auto_dm_2_speed", str(speed))
await message.reply(f"โ
**Custom speed set to {speed} seconds!**")
del AUTODM_STATE[user_id]
except:
await message.reply("โ Invalid number. Send a number like `1.5` or `3`")
return
if user_id in BROADCAST_STATE:
state = BROADCAST_STATE[user_id]
step = state["step"]
if step == "WAIT_MSG":
file_id = None
file_type = "text"
caption = message.caption.html if message.caption else message.text.html if message.text else ""
if message.photo: file_id, file_type = message.photo.file_id, "photo"
elif message.video: file_id, file_type = message.video.file_id, "video"
BROADCAST_STATE[user_id].update({"msg_file_id": file_id, "msg_type": file_type, "caption": caption, "step": "WAIT_BTN_NAME"})
await message.reply_text("โ
Message Received!\nโจ๏ธ **Enter Button Name** (or 'skip')")
elif step == "WAIT_BTN_NAME":
if message.text.lower() == "skip":
BROADCAST_STATE[user_id]["btn_name"] = None
BROADCAST_STATE[user_id]["step"] = "CONFIRM"
await show_broadcast_preview(client, user_id)
else:
BROADCAST_STATE[user_id]["btn_name"] = message.text
BROADCAST_STATE[user_id]["step"] = "WAIT_BTN_URL"
await message.reply_text("๐ **Now Enter Button Link** (URL):")
elif step == "WAIT_BTN_URL":
BROADCAST_STATE[user_id]["btn_url"] = message.text
BROADCAST_STATE[user_id]["step"] = "CONFIRM"
await show_broadcast_preview(client, user_id)
async def show_broadcast_preview(client, user_id):
data = BROADCAST_STATE[user_id]
buttons =[]
if data.get("btn_name") and data.get("btn_url"):
buttons.append([InlineKeyboardButton(data["btn_name"], url=data["btn_url"])])
buttons.append([
InlineKeyboardButton("โ
SEND", callback_data="broadcast_confirm"),
InlineKeyboardButton("โ CANCEL", callback_data="broadcast_cancel")
])
markup = InlineKeyboardMarkup(buttons)
await client.send_message(user_id, "๐โ๐จ **PREVIEW OF BROADCAST** ๐")
if data["msg_type"] == "photo":
await client.send_photo(user_id, data["msg_file_id"], caption=data.get("caption", ""), reply_markup=markup, parse_mode=ParseMode.HTML)
elif data["msg_type"] == "video":
await client.send_video(user_id, data["msg_file_id"], caption=data.get("caption", ""), reply_markup=markup, parse_mode=ParseMode.HTML)
else:
await client.send_message(user_id, data.get("caption", "Broadcast"), reply_markup=markup, parse_mode=ParseMode.HTML)
@app.on_callback_query(filters.regex("broadcast_confirm"))
async def start_broadcasting(client, callback_query):
global IS_BROADCASTING, STOP_BROADCAST
user_id = callback_query.from_user.id
if user_id not in BROADCAST_STATE: return await callback_query.answer("Session expired.", show_alert=True)
data = BROADCAST_STATE[user_id]
del BROADCAST_STATE[user_id]
try: await callback_query.message.edit_reply_markup(None)
except: pass
await client.send_message(user_id, "๐ **Broadcast Started!**")
IS_BROADCASTING = True
STOP_BROADCAST = False
clear_broadcast_logs()
users = get_all_users()
sent = 0
markup = None
if data.get("btn_name") and data.get("btn_url"):
markup = InlineKeyboardMarkup([[InlineKeyboardButton(data["btn_name"], url=data["btn_url"])]])
for uid in users:
if STOP_BROADCAST: break
try:
msg = None
if data["msg_type"] == "photo":
msg = await client.send_photo(uid, data["msg_file_id"], caption=data.get("caption", ""), reply_markup=markup, parse_mode=ParseMode.HTML)
elif data["msg_type"] == "video":
msg = await client.send_video(uid, data["msg_file_id"], caption=data.get("caption", ""), reply_markup=markup, parse_mode=ParseMode.HTML)
else:
msg = await client.send_message(uid, data.get("caption", "Broadcast"), reply_markup=markup, parse_mode=ParseMode.HTML)
if msg: save_broadcast_log(uid, msg.id)
sent += 1
await asyncio.sleep(0.05)
except Exception:
pass
IS_BROADCASTING = False
await client.send_message(user_id, f"๐ฃ **Broadcast Completed!**\nโ
Sent: `{sent}`")
@app.on_callback_query(filters.regex("broadcast_cancel"))
async def cancel_broadcasting(client, callback_query):
user_id = callback_query.from_user.id
if user_id in BROADCAST_STATE: del BROADCAST_STATE[user_id]
try: await callback_query.message.delete()
except: pass
await client.send_message(user_id, "โ Broadcast Cancelled.")
def build_autodm_markup(prefix):
btns_str = get_config(f"auto_dm_{prefix}buttons")
if prefix == "" and (not btns_str or btns_str == "[]"):
b_name = get_config("auto_dm_btn_name")
b_url = get_config("auto_dm_btn_url")
if b_name and b_name != "None" and b_url and b_url != "None":
return InlineKeyboardMarkup([[InlineKeyboardButton(b_name, url=b_url)]])
return None
if not btns_str or btns_str == "[]": return None
try:
btns = json.loads(btns_str)
kb = []
for row in btns:
kb_row = [InlineKeyboardButton(btn["text"], url=btn["url"]) for btn in row]
kb.append(kb_row)
return InlineKeyboardMarkup(kb) if kb else None
except: return None
@app.on_chat_join_request()
async def auto_dm_join_request(client, message: ChatJoinRequest):
user_id = message.from_user.id
add_user(user_id)
increment_daily_stat("autodms")
dm_type = get_config("auto_dm_type")
if dm_type and dm_type != "":
dm_content = get_config("auto_dm_content")
dm_caption = get_config("auto_dm_caption") or ""
markup = build_autodm_markup("")
while True:
try:
if dm_type == "photo":
await client.send_photo(user_id, dm_content, caption=dm_caption, reply_markup=markup, parse_mode=ParseMode.HTML)
elif dm_type == "video":
await client.send_video(user_id, dm_content, caption=dm_caption, reply_markup=markup, parse_mode=ParseMode.HTML)
else:
await client.send_message(user_id, dm_caption, reply_markup=markup, parse_mode=ParseMode.HTML)
c1 = get_config("autodm_1_count") or "0"
set_config("autodm_1_count", str(int(c1) + 1))
break
except FloodWait as e:
await asyncio.sleep(e.value + 1)
except Exception:
break
dm2_type = get_config("auto_dm_2_type")
if dm2_type and dm2_type != "":
dm2_content = get_config("auto_dm_2_content")
dm2_caption = get_config("auto_dm_2_caption") or ""
markup2 = build_autodm_markup("2_")
speed_str = get_config("auto_dm_2_speed") or "2.0"
try: speed_val = float(speed_str)
except: speed_val = 2.0
await asyncio.sleep(speed_val)
while True:
try:
if dm2_type == "photo":
await client.send_photo(user_id, dm2_content, caption=dm2_caption, reply_markup=markup2, parse_mode=ParseMode.HTML)
elif dm2_type == "video":
await client.send_video(user_id, dm2_content, caption=dm2_caption, reply_markup=markup2, parse_mode=ParseMode.HTML)
else:
await client.send_message(user_id, dm2_caption, reply_markup=markup2, parse_mode=ParseMode.HTML)
c2 = get_config("autodm_2_count") or "0"
set_config("autodm_2_count", str(int(c2) + 1))
break
except FloodWait as e:
await asyncio.sleep(e.value + 1)
except Exception:
break
@app.on_chat_member_updated()
async def on_bot_permission_change(client, event: ChatMemberUpdated):
user = event.new_chat_member.user if event.new_chat_member else (event.old_chat_member.user if event.old_chat_member else None)
if not user or user.id != client.me.id:
return
status = event.new_chat_member.status if event.new_chat_member else None
if status in [ChatMemberStatus.BANNED, ChatMemberStatus.LEFT]:
remove_watched_channel(event.chat.id)
for ub in ALL_USERBOTS:
try: await ub.leave_chat(event.chat.id)
except: pass
elif status in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.MEMBER]:
adder_id = event.from_user.id if event.from_user else None
try:
mem_count = await client.get_chat_members_count(event.chat.id)
except Exception:
mem_count = "Unknown"
add_watched_channel(event.chat.id, event.chat.title or "Unknown", owner_id=adder_id, member_count=mem_count)
invite_link = None
try:
if event.chat.username: invite_link = event.chat.username
else: invite_link = await client.export_chat_invite_link(event.chat.id)
except: pass
if invite_link:
for ub in ALL_USERBOTS:
try:
await ub.join_chat(invite_link)
await asyncio.sleep(1)
except: pass
@app.on_message(filters.command("admin") & filters.user(ADMINS))
async def admin_help_command(client, message):
text = get_custom_text("admin_msg", DEFAULT_ADMIN_MSG)
await message.reply(text, parse_mode=ParseMode.HTML)
# ๐ NAYA COMMAND BNAYA GYA HAI PURANE CHANNELS KE MEMBERS JSON ME LAAANE KE LIYE BINA BAN HUE
@app.on_message(filters.command("syncjson") & filters.user(ADMINS))
async def sync_json_command(client, message):
msg = await message.reply("๐ **Starting JSON Sync...**\nFetching old channels and updating member counts in JSON.\n*(Speed: 1.5s per channel to prevent FloodWait)*")
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT chat_id, chat_title FROM watched_channels')
channels = c.fetchall()
conn.close()
updated = 0
total = len(channels)
for chat_id, chat_title in channels:
try:
mem_count = await client.get_chat_members_count(chat_id)
except FloodWait as e:
await asyncio.sleep(e.value + 1)
try: mem_count = await client.get_chat_members_count(chat_id)
except: mem_count = "Unknown"
except Exception:
mem_count = "Unknown"
add_to_json(chat_id, chat_title, mem_count)
updated += 1
if updated % 15 == 0:
try: await msg.edit(f"๐ **Syncing JSON...**\nProcessed: `{updated}/{total}` channels.")
except: pass
await asyncio.sleep(1.5)
await msg.edit(f"โ
**JSON Sync Complete!**\nAll `{updated}` channels have been saved with their exact member counts in `channels_backup.json`.")
async def generate_community_text(client, user_id):
raw_list = get_user_watched_channels(user_id)
if not raw_list: return None
channels_text = ""
groups_text = ""
has_channels = False
has_groups = False
for chat_id, title in raw_list:
try:
chat = await client.get_chat(chat_id)
if chat.type == enums.ChatType.CHANNEL:
channels_text += f"โขโค {chat.title}\n"
has_channels = True
elif chat.type in[enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]:
groups_text += f"โขโค {chat.title}\n"
has_groups = True
except Exception:
channels_text += f"โขโค {title} (Unknown/Kicked)\n"
has_channels = True
final_msg = "โโ๐ ๐ฌ๐ข๐จ๐ฅ ๐๐๐๐ก๐ก๐๐๐ฆ ๐โโ\n\n"
final_msg += channels_text if has_channels else "โขโค No Channels Found\n"
final_msg += "\n๐ฃ Your Admin Channels List:\n(Your bots will join these)\n\n"
final_msg += "โ๏ธโโโโโโโโโโโโโโโโโโโ๏ธ\n\n"
final_msg += "โโ๐ ๐ฌ๐ข๐จ๐ฅ ๐๐ฅ๐ข๐จ๐ฃ๐ฆ ๐โโ\n\n"
final_msg += groups_text if has_groups else "โขโค No Groups Found\n"
final_msg += "\n๐ฃ Your Admin Group List:\n(Your bots will join these)"
return final_msg
@app.on_message(filters.command("mycommunity"))
async def mycommunity_command_handler(client, message):
user_id = message.from_user.id
status_msg = await message.reply("๐ Fetching your community list...")
final_msg = await generate_community_text(client, user_id)
keyboard = get_mycommunity_keyboard(client.me.username)
if not final_msg:
text = get_custom_text("mycommunity_msg", DEFAULT_MYCOMMUNITY_MSG)
await status_msg.edit(text, reply_markup=keyboard, parse_mode=ParseMode.HTML)
return
await status_msg.edit(final_msg, reply_markup=keyboard, parse_mode=ParseMode.HTML)
@app.on_callback_query(filters.regex("refresh_community"))
async def refresh_community_callback(client, callback_query):
user_id = callback_query.from_user.id
final_msg = await generate_community_text(client, user_id)
keyboard = get_mycommunity_keyboard(client.me.username)
if not final_msg:
text = get_custom_text("mycommunity_msg", DEFAULT_MYCOMMUNITY_MSG)
try:
await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode=ParseMode.HTML)
await callback_query.answer("๐ List Refreshed!", show_alert=False)
except MessageNotModified: await callback_query.answer("โ ๏ธ List is already up-to-date.", show_alert=False)
except: pass
else:
try:
await callback_query.message.edit_text(final_msg, reply_markup=keyboard, parse_mode=ParseMode.HTML)
await callback_query.answer("โ
List Refreshed Successfully!", show_alert=False)
except MessageNotModified: await callback_query.answer("โ ๏ธ List is already up-to-date.", show_alert=False)
async def daily_report_broadcaster():
while True:
now = datetime.datetime.now()
next_midnight = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
sleep_secs = (next_midnight - now).total_seconds()
await asyncio.sleep(sleep_secs)
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT chat_id FROM watched_channels')
channels = c.fetchall()
conn.close()
bot_username = app.me.username if app.me else "teleprotectorbot"
today_str = datetime.datetime.now().strftime("%Y-%m-%d")
chunk_size = 25
for i in range(0, len(channels), chunk_size):
chunk = channels[i:i+chunk_size]
tasks = [broadcast_safely_report(chat_id[0], bot_username, today_str) for chat_id in chunk]
results = await asyncio.gather(*tasks)
success_count = sum([1 for r in results if r])
if success_count > 0:
increment_daily_stat("msgs_processed", success_count)
await asyncio.sleep(1.5)
FETCH_MODE = False
FETCHED_CHANNELS_COUNT = 0
# ๐ฅ NAYA ADDITION: Ek list jo check karegi ki kis channel ka json update ho chuka hai, taaki rate limit (Ban) na ho
UPDATED_CHANNELS = set()
@app.on_message(filters.command("cheak") & filters.user(ADMINS))
async def toggle_cheak_mode(client, message):
global FETCH_MODE, FETCHED_CHANNELS_COUNT
FETCH_MODE = not FETCH_MODE
if FETCH_MODE:
FETCHED_CHANNELS_COUNT = 0
await message.reply("โ
**Fetch Mode Activated!**\nAb jaise hi kisi channel/group me koi naya message post hoga jisme ye bot admin hai, bot automatically us channel ko database me wapas save kar lega.")
else:
await message.reply("โ **Fetch Mode Deactivated!**\nAuto-recovery of channels band ho chuki hai.")
@app.on_message(filters.command("cheakreal") & filters.user(ADMINS))
async def cheakreal_command(client, message):
global FETCH_MODE, FETCHED_CHANNELS_COUNT
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('SELECT COUNT() FROM watched_channels')
total_chats = c.fetchone()[0]
conn.close()
status = "๐ข ON" if FETCH_MODE else "๐ด OFF"
text = (
f"๐ **LIVE FETCH TRACKER** ๐\n\n"
f"๐ก **Fetch Mode:** {status}\n"
f"๐ **Channels Recovered (This Session):** `{FETCHED_CHANNELS_COUNT}`\n"
f"๐ **Total Channels In Database:** `{total_chats}`\n\n"
f"*(Midnight Auto-Message will be sent to all {total_chats} channels)*"
)
await message.reply(text)
@app.on_message((filters.channel | filters.group), group=-2)
async def passive_chat_fetcher(client, message):
global FETCH_MODE, FETCHED_CHANNELS_COUNT
if FETCH_MODE:
chat = message.chat
if chat.id not in WATCHED_CACHE:
try:
mem_count = await client.get_chat_members_count(chat.id)
except Exception:
mem_count = "Unknown"
success = add_watched_channel(chat.id, chat.title or "Unknown", owner_id=None, member_count=mem_count)
if success:
FETCHED_CHANNELS_COUNT += 1
# ๐ฅ NAYA ADDITION: Jaise hi kisi bhi purane channel me koi NEW POST aayega, ye uske member count ko exactly tabhi JSON me save kar lega automatically! (Sirf ek baar hoga channel per restart)
@app.on_message((filters.channel | filters.group), group=-3)
async def auto_json_updater_on_post(client, message):
chat = message.chat
if chat.id not in UPDATED_CHANNELS:
try:
mem_count = await client.get_chat_members_count(chat.id)
add_to_json(chat.id, chat.title or "Unknown", mem_count)
UPDATED_CHANNELS.add(chat.id)
except Exception:
pass
async def main():
await app.start()
try:
await app.set_bot_commands([
BotCommand("start", "Start Bot"),
BotCommand("scan", "Scan Channels"),
BotCommand("stats", "Check Statistics")
])
print("โ
Menu Commands Set Successfully")
except Exception as e:
print(f"โ Failed to set menu commands: {e}")
print("๐ฅ Manager Bot Started!")
await load_userbots()
print("โก System Active.")
asyncio.create_task(daily_report_broadcaster())
await idle()
await app.stop()
for ub in ALL_USERBOTS:
try: await ub.stop()
except: pass
if __name__ == "__main__":
app.run(main())
Initializing secure terminal connection. Waiting for system boot...