Update bot/handlers.py
Browse files- bot/handlers.py +68 -15
bot/handlers.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
import os
|
| 2 |
import asyncio
|
| 3 |
import random
|
| 4 |
-
import re
|
| 5 |
import datetime
|
| 6 |
from pyrogram import filters, enums
|
| 7 |
-
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
| 8 |
from pyrogram.errors import MessageNotModified
|
| 9 |
from bot.client import bot
|
| 10 |
from bot.state import state
|
|
@@ -13,12 +13,12 @@ from bot.scheduler import scheduler, schedule_next, get_pkt_time
|
|
| 13 |
from utils.logger import log, get_recent_logs
|
| 14 |
from bot.sniper import fleet
|
| 15 |
from bot.proxy_manager import proxy_mgr
|
| 16 |
-
from pyrogram.types import LinkPreviewOptions
|
| 17 |
|
| 18 |
from bot.ui.keyboards import (
|
| 19 |
markup_cancel, markup_main, markup_settings,
|
| 20 |
markup_claim_settings, markup_fragment_settings,
|
| 21 |
-
markup_channel_accounts, markup_db_manager, markup_confirm
|
|
|
|
| 22 |
)
|
| 23 |
from bot.ui.text_views import (
|
| 24 |
text_main, get_settings_text, text_dashboard,
|
|
@@ -61,7 +61,8 @@ def is_admin(_, __, update):
|
|
| 61 |
|
| 62 |
admin_filter = filters.create(is_admin)
|
| 63 |
|
| 64 |
-
def get_account_by_index(idx: int):
|
|
|
|
| 65 |
|
| 66 |
async def input_timeout(user_id: int, expected_state: str, msg):
|
| 67 |
await asyncio.sleep(60)
|
|
@@ -209,7 +210,7 @@ async def cmd_addsnipe(client, message):
|
|
| 209 |
try: await message.react("β‘")
|
| 210 |
except Exception: pass
|
| 211 |
else:
|
| 212 |
-
await message.reply_text(f"β οΈ <b>@{target}</b> is already in the snipe queue.", parse_mode=enums.ParseMode.HTML)
|
| 213 |
|
| 214 |
@bot.on_message(filters.command("rmsnipe") & admin_filter)
|
| 215 |
async def cmd_rmsnipe(client, message):
|
|
@@ -311,10 +312,11 @@ async def cmd_fragcheck(client, message):
|
|
| 311 |
|
| 312 |
@bot.on_message(filters.command("unfrag") & admin_filter)
|
| 313 |
async def cmd_unfrag(client, message):
|
|
|
|
| 314 |
if len(message.command) < 2:
|
| 315 |
state["waiting_for_input"][user_id] = "unfrag_input"
|
| 316 |
msg = await message.reply_text("Send the username to remove from Fragment Scraper:", reply_markup=markup_cancel(), parse_mode=enums.ParseMode.HTML)
|
| 317 |
-
asyncio.create_task(input_timeout(
|
| 318 |
return
|
| 319 |
|
| 320 |
target = message.command[1].replace("@", "").strip().lower()
|
|
@@ -338,7 +340,6 @@ async def cmd_proxy_mapping_dashboard(client, message):
|
|
| 338 |
if not state.get("account_pool"):
|
| 339 |
return await message.reply_text("β System error: Account pool is empty.")
|
| 340 |
|
| 341 |
-
# β‘ UI UPGRADE: Wrapped in Expandable Blockquote to save screen space
|
| 342 |
dashboard_lines = [
|
| 343 |
"<b>π‘οΈ Cluster Network Egress Mapping</b>\n",
|
| 344 |
f"<b>Proxy Engine:</b> {'β
ACTIVE' if proxy_mgr.is_enabled else 'β DISABLED'}",
|
|
@@ -523,7 +524,6 @@ async def handle_media_and_text_input(client, message):
|
|
| 523 |
state["waiting_for_input"][user_id] = None
|
| 524 |
return
|
| 525 |
|
| 526 |
-
# β‘ ENGINE UPGRADE: Fully Automated Secure Transfer Initiation
|
| 527 |
if waiting_for and waiting_for.startswith("trans_target|"):
|
| 528 |
_, idx_str, chat_id_str = waiting_for.split("|")
|
| 529 |
target = message.text.strip()
|
|
@@ -551,7 +551,6 @@ async def handle_media_and_text_input(client, message):
|
|
| 551 |
else:
|
| 552 |
await msg.edit_text("β³ <b>Telegram Security Lock:</b> Session must be active for 24 hours before transferring ownership.", parse_mode=enums.ParseMode.HTML)
|
| 553 |
elif "PASSWORD_REQUIRED" in result or "PASSWORD_HASH_INVALID" in result:
|
| 554 |
-
# Fallback to manual password input if the user changed the default 2FA password
|
| 555 |
state["waiting_for_input"][user_id] = f"trans_2fa|{idx_str}|{chat_id_str}|{target}"
|
| 556 |
await msg.edit_text(f"π <b>2FA Password Required</b>\n\nAccount #{idx_str} has a custom Two-Step Verification password.\nPlease send the password:", reply_markup=markup_cancel(), parse_mode=enums.ParseMode.HTML)
|
| 557 |
asyncio.create_task(input_timeout(user_id, state["waiting_for_input"][user_id], msg))
|
|
@@ -576,7 +575,7 @@ async def handle_media_and_text_input(client, message):
|
|
| 576 |
if success:
|
| 577 |
await msg.edit_text(f"β
<b>Ownership transferred to {target}.</b>", parse_mode=enums.ParseMode.HTML)
|
| 578 |
else:
|
| 579 |
-
|
| 580 |
return
|
| 581 |
|
| 582 |
if waiting_for == "watchdog_add":
|
|
@@ -642,9 +641,64 @@ async def callback_router(client, callback_query):
|
|
| 642 |
data = callback_query.data
|
| 643 |
user_id = callback_query.from_user.id
|
| 644 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 645 |
if data == "toggle_proxy":
|
| 646 |
if len(proxy_mgr.proxies) == 0:
|
| 647 |
-
return await callback_query.answer("β οΈ
|
| 648 |
|
| 649 |
proxy_mgr.is_enabled = not proxy_mgr.is_enabled
|
| 650 |
proxy_text = "π’ Proxy: ON" if proxy_mgr.is_enabled else "π΄ Proxy: OFF"
|
|
@@ -701,7 +755,7 @@ async def callback_router(client, callback_query):
|
|
| 701 |
|
| 702 |
text = f"π <b>@{target}</b>\n\n<blockquote>Snipe: {in_snipe}\nCheck: {in_check}\nWatchdog: {in_watchdog}\nFragment: {in_frag}\nUnavailable DB: {in_unavail}</blockquote>"
|
| 703 |
buttons = []
|
| 704 |
-
if target in state["snipe_queue"]: buttons.append([InlineKeyboardButton("ποΈ Remove from Snipe", callback_data=f"rm_q|s|{target}", style=enums.ButtonStyle.DANGER)])
|
| 705 |
if target in state["watchdog_queue"]: buttons.append([InlineKeyboardButton("ποΈ Remove from Watchdog", callback_data=f"rm_q|w|{target}", style=enums.ButtonStyle.DANGER)])
|
| 706 |
if target in state["fragcheck_queue"]: buttons.append([InlineKeyboardButton("ποΈ Remove from Fragment", callback_data=f"rm_q|f|{target}", style=enums.ButtonStyle.DANGER)])
|
| 707 |
buttons.append([InlineKeyboardButton("β Dismiss", callback_data="cancel_input", style=enums.ButtonStyle.DEFAULT)])
|
|
@@ -786,7 +840,6 @@ async def callback_router(client, callback_query):
|
|
| 786 |
markup = InlineKeyboardMarkup([[InlineKeyboardButton("π Live Dashboard", callback_data="start_live_dash", style=enums.ButtonStyle.PRIMARY)], [InlineKeyboardButton("β¬
οΈ Back", callback_data="main_panel", style=enums.ButtonStyle.PRIMARY)]])
|
| 787 |
await callback_query.message.edit_text(text_dashboard(), reply_markup=markup, parse_mode=enums.ParseMode.HTML)
|
| 788 |
|
| 789 |
-
# β‘ UI UPGRADE: Expandable Blockquote
|
| 790 |
elif data in ["view_logs", "refresh_logs"]:
|
| 791 |
logs = get_recent_logs(20)
|
| 792 |
log_text = "\n".join(logs) if logs else "No logs yet."
|
|
@@ -1370,7 +1423,7 @@ async def callback_router(client, callback_query):
|
|
| 1370 |
state["unavailable_set"].discard(username)
|
| 1371 |
if hasattr(db, "remove_unavailable"): await db.remove_unavailable(username)
|
| 1372 |
await purge_target_from_queues(username)
|
| 1373 |
-
await callback_query.message.edit_text(f"ποΈ
|
| 1374 |
except Exception as e:
|
| 1375 |
if "FROZEN" in str(e).upper(): account.status = "frozen"
|
| 1376 |
await callback_query.message.edit_text(f"β Undo Failed: <b>{e}</b>", parse_mode=enums.ParseMode.HTML)
|
|
|
|
| 1 |
import os
|
| 2 |
import asyncio
|
| 3 |
import random
|
| 4 |
+
import re
|
| 5 |
import datetime
|
| 6 |
from pyrogram import filters, enums
|
| 7 |
+
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, LinkPreviewOptions
|
| 8 |
from pyrogram.errors import MessageNotModified
|
| 9 |
from bot.client import bot
|
| 10 |
from bot.state import state
|
|
|
|
| 13 |
from utils.logger import log, get_recent_logs
|
| 14 |
from bot.sniper import fleet
|
| 15 |
from bot.proxy_manager import proxy_mgr
|
|
|
|
| 16 |
|
| 17 |
from bot.ui.keyboards import (
|
| 18 |
markup_cancel, markup_main, markup_settings,
|
| 19 |
markup_claim_settings, markup_fragment_settings,
|
| 20 |
+
markup_channel_accounts, markup_db_manager, markup_confirm,
|
| 21 |
+
markup_bot_query
|
| 22 |
)
|
| 23 |
from bot.ui.text_views import (
|
| 24 |
text_main, get_settings_text, text_dashboard,
|
|
|
|
| 61 |
|
| 62 |
admin_filter = filters.create(is_admin)
|
| 63 |
|
| 64 |
+
def get_account_by_index(idx: int):
|
| 65 |
+
return next((a for a in state["account_pool"] if a.index == idx), None)
|
| 66 |
|
| 67 |
async def input_timeout(user_id: int, expected_state: str, msg):
|
| 68 |
await asyncio.sleep(60)
|
|
|
|
| 210 |
try: await message.react("β‘")
|
| 211 |
except Exception: pass
|
| 212 |
else:
|
| 213 |
+
await message.reply_text(f"β οΈοΈ <b>@{target}</b> is already in the snipe queue.", parse_mode=enums.ParseMode.HTML)
|
| 214 |
|
| 215 |
@bot.on_message(filters.command("rmsnipe") & admin_filter)
|
| 216 |
async def cmd_rmsnipe(client, message):
|
|
|
|
| 312 |
|
| 313 |
@bot.on_message(filters.command("unfrag") & admin_filter)
|
| 314 |
async def cmd_unfrag(client, message):
|
| 315 |
+
user_id = message.from_user.id
|
| 316 |
if len(message.command) < 2:
|
| 317 |
state["waiting_for_input"][user_id] = "unfrag_input"
|
| 318 |
msg = await message.reply_text("Send the username to remove from Fragment Scraper:", reply_markup=markup_cancel(), parse_mode=enums.ParseMode.HTML)
|
| 319 |
+
asyncio.create_task(input_timeout(user_id, "unfrag_input", msg))
|
| 320 |
return
|
| 321 |
|
| 322 |
target = message.command[1].replace("@", "").strip().lower()
|
|
|
|
| 340 |
if not state.get("account_pool"):
|
| 341 |
return await message.reply_text("β System error: Account pool is empty.")
|
| 342 |
|
|
|
|
| 343 |
dashboard_lines = [
|
| 344 |
"<b>π‘οΈ Cluster Network Egress Mapping</b>\n",
|
| 345 |
f"<b>Proxy Engine:</b> {'β
ACTIVE' if proxy_mgr.is_enabled else 'β DISABLED'}",
|
|
|
|
| 524 |
state["waiting_for_input"][user_id] = None
|
| 525 |
return
|
| 526 |
|
|
|
|
| 527 |
if waiting_for and waiting_for.startswith("trans_target|"):
|
| 528 |
_, idx_str, chat_id_str = waiting_for.split("|")
|
| 529 |
target = message.text.strip()
|
|
|
|
| 551 |
else:
|
| 552 |
await msg.edit_text("β³ <b>Telegram Security Lock:</b> Session must be active for 24 hours before transferring ownership.", parse_mode=enums.ParseMode.HTML)
|
| 553 |
elif "PASSWORD_REQUIRED" in result or "PASSWORD_HASH_INVALID" in result:
|
|
|
|
| 554 |
state["waiting_for_input"][user_id] = f"trans_2fa|{idx_str}|{chat_id_str}|{target}"
|
| 555 |
await msg.edit_text(f"π <b>2FA Password Required</b>\n\nAccount #{idx_str} has a custom Two-Step Verification password.\nPlease send the password:", reply_markup=markup_cancel(), parse_mode=enums.ParseMode.HTML)
|
| 556 |
asyncio.create_task(input_timeout(user_id, state["waiting_for_input"][user_id], msg))
|
|
|
|
| 575 |
if success:
|
| 576 |
await msg.edit_text(f"β
<b>Ownership transferred to {target}.</b>", parse_mode=enums.ParseMode.HTML)
|
| 577 |
else:
|
| 578 |
+
await msg.edit_text(f"β Transfer Failed: <b>{result}</b>", parse_mode=enums.ParseMode.HTML)
|
| 579 |
return
|
| 580 |
|
| 581 |
if waiting_for == "watchdog_add":
|
|
|
|
| 641 |
data = callback_query.data
|
| 642 |
user_id = callback_query.from_user.id
|
| 643 |
try:
|
| 644 |
+
if data == "ignore":
|
| 645 |
+
return await callback_query.answer()
|
| 646 |
+
|
| 647 |
+
if data == "menu_bot_query":
|
| 648 |
+
await callback_query.message.edit_text(
|
| 649 |
+
"<b>πͺ Account Bot Query Menu</b>\nSelect an account to send <code>/coins</code> and fetch its balance:",
|
| 650 |
+
reply_markup=markup_bot_query(),
|
| 651 |
+
parse_mode=enums.ParseMode.HTML
|
| 652 |
+
)
|
| 653 |
+
return
|
| 654 |
+
|
| 655 |
+
if data.startswith("query_coins|"):
|
| 656 |
+
acc_idx = int(data.split("|")[1])
|
| 657 |
+
acc = get_account_by_index(acc_idx)
|
| 658 |
+
if not acc:
|
| 659 |
+
return await callback_query.answer("Account unavailable.", show_alert=True)
|
| 660 |
+
|
| 661 |
+
await callback_query.message.edit_text(f"β³ Sending <code>/coins</code> from Account #{acc_idx}...", parse_mode=enums.ParseMode.HTML)
|
| 662 |
+
|
| 663 |
+
from bot.checker import send_and_await_reply
|
| 664 |
+
target_bot = "@info_id_bot"
|
| 665 |
+
reply = await send_and_await_reply(acc, target_bot, "/coins", timeout=8)
|
| 666 |
+
|
| 667 |
+
text = (
|
| 668 |
+
f"<b>πͺ Balance Report (Acc #{acc_idx})</b>\n"
|
| 669 |
+
f"Target Bot: <code>{target_bot}</code>\n\n"
|
| 670 |
+
f"<blockquote expandable>{reply}</blockquote>"
|
| 671 |
+
)
|
| 672 |
+
buttons = [
|
| 673 |
+
[InlineKeyboardButton("π Re-check", callback_data=f"query_coins|{acc_idx}", style=enums.ButtonStyle.PRIMARY)],
|
| 674 |
+
[InlineKeyboardButton("β¬
οΈ Back", callback_data="menu_bot_query", style=enums.ButtonStyle.PRIMARY)]
|
| 675 |
+
]
|
| 676 |
+
await callback_query.message.edit_text(text, reply_markup=InlineKeyboardMarkup(buttons), parse_mode=enums.ParseMode.HTML)
|
| 677 |
+
return
|
| 678 |
+
|
| 679 |
+
if data == "query_coins_all":
|
| 680 |
+
await callback_query.message.edit_text("β³ Querying <code>/coins</code> across all active accounts...", parse_mode=enums.ParseMode.HTML)
|
| 681 |
+
|
| 682 |
+
from bot.checker import send_and_await_reply
|
| 683 |
+
target_bot = "@info_id_bot"
|
| 684 |
+
active_accounts = [a for a in state["account_pool"] if a.status in ["active", "paused"] and a.client]
|
| 685 |
+
|
| 686 |
+
results = []
|
| 687 |
+
for acc in active_accounts:
|
| 688 |
+
masked = f"****{acc.phone[-4:]}" if len(acc.phone) >= 4 else acc.phone
|
| 689 |
+
res = await send_and_await_reply(acc, target_bot, "/coins", timeout=6)
|
| 690 |
+
first_line = res.split("\n")[0] if res else "No response"
|
| 691 |
+
results.append(f"<b>Acc #{acc.index} ({masked}):</b>\n{first_line}")
|
| 692 |
+
|
| 693 |
+
summary = "\n\n".join(results) if results else "No active accounts found."
|
| 694 |
+
text = f"<b>πͺ Fleet Balance Summary</b>\n\n<blockquote expandable>{summary}</blockquote>"
|
| 695 |
+
buttons = [[InlineKeyboardButton("β¬
οΈ Back", callback_data="menu_bot_query", style=enums.ButtonStyle.PRIMARY)]]
|
| 696 |
+
await callback_query.message.edit_text(text, reply_markup=InlineKeyboardMarkup(buttons), parse_mode=enums.ParseMode.HTML)
|
| 697 |
+
return
|
| 698 |
+
|
| 699 |
if data == "toggle_proxy":
|
| 700 |
if len(proxy_mgr.proxies) == 0:
|
| 701 |
+
return await callback_query.answer("β οΈ No proxies available! Check WEBSHARE_API_KEY.", show_alert=True)
|
| 702 |
|
| 703 |
proxy_mgr.is_enabled = not proxy_mgr.is_enabled
|
| 704 |
proxy_text = "π’ Proxy: ON" if proxy_mgr.is_enabled else "π΄ Proxy: OFF"
|
|
|
|
| 755 |
|
| 756 |
text = f"π <b>@{target}</b>\n\n<blockquote>Snipe: {in_snipe}\nCheck: {in_check}\nWatchdog: {in_watchdog}\nFragment: {in_frag}\nUnavailable DB: {in_unavail}</blockquote>"
|
| 757 |
buttons = []
|
| 758 |
+
if target in state["snipe_queue"]: buttons.append([InlineKeyboardButton("ποΈοΈ Remove from Snipe", callback_data=f"rm_q|s|{target}", style=enums.ButtonStyle.DANGER)])
|
| 759 |
if target in state["watchdog_queue"]: buttons.append([InlineKeyboardButton("ποΈ Remove from Watchdog", callback_data=f"rm_q|w|{target}", style=enums.ButtonStyle.DANGER)])
|
| 760 |
if target in state["fragcheck_queue"]: buttons.append([InlineKeyboardButton("ποΈ Remove from Fragment", callback_data=f"rm_q|f|{target}", style=enums.ButtonStyle.DANGER)])
|
| 761 |
buttons.append([InlineKeyboardButton("β Dismiss", callback_data="cancel_input", style=enums.ButtonStyle.DEFAULT)])
|
|
|
|
| 840 |
markup = InlineKeyboardMarkup([[InlineKeyboardButton("π Live Dashboard", callback_data="start_live_dash", style=enums.ButtonStyle.PRIMARY)], [InlineKeyboardButton("β¬
οΈ Back", callback_data="main_panel", style=enums.ButtonStyle.PRIMARY)]])
|
| 841 |
await callback_query.message.edit_text(text_dashboard(), reply_markup=markup, parse_mode=enums.ParseMode.HTML)
|
| 842 |
|
|
|
|
| 843 |
elif data in ["view_logs", "refresh_logs"]:
|
| 844 |
logs = get_recent_logs(20)
|
| 845 |
log_text = "\n".join(logs) if logs else "No logs yet."
|
|
|
|
| 1423 |
state["unavailable_set"].discard(username)
|
| 1424 |
if hasattr(db, "remove_unavailable"): await db.remove_unavailable(username)
|
| 1425 |
await purge_target_from_queues(username)
|
| 1426 |
+
await callback_query.message.edit_text(f"ποΈ Channel deleted. <b>@{username}</b> released and purged from active queues.", parse_mode=enums.ParseMode.HTML)
|
| 1427 |
except Exception as e:
|
| 1428 |
if "FROZEN" in str(e).upper(): account.status = "frozen"
|
| 1429 |
await callback_query.message.edit_text(f"β Undo Failed: <b>{e}</b>", parse_mode=enums.ParseMode.HTML)
|