import asyncio, aiohttp, json, html, requests, re, os
from datetime import datetime, timezone
from typing import cast
from aiogram import Bot, Dispatcher
from aiogram.filters import Command, BaseFilter
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery, Message
from aiogram.client.default import DefaultBotProperties
from dotenv import load_dotenv
load_dotenv()
API_TOKEN = os.getenv("API_TOKEN")
ADMIN_ID = int(os.getenv("ADMIN_ID")) # type: ignore
ASF_URL = os.getenv("ASF_URL")
ASF_PASSWORD = os.getenv("ASF_PASSWORD")
PAGE_SIZE = 40
GAMES = {730: "CS2", 440: "TF2", 570: "Dota 2"}
appid = 753
contextid = 6
console_users, redeem_users = set(), set()
twofa_tasks, inventory_cache, redeem_messages, bot_redeem_users, bot_redeem_messages = {}, {}, {}, {}, {}
bot = Bot(token=API_TOKEN, default=DefaultBotProperties(parse_mode="HTML")) # type: ignore
dp = Dispatcher()
class AdminFilter(BaseFilter):
async def __call__(self, message: Message) -> bool:
return message.from_user.id == ADMIN_ID # type: ignore
class AdminCallbackFilter(BaseFilter):
async def __call__(self, callback: CallbackQuery) -> bool:
return callback.from_user.id == ADMIN_ID
def asf_get(path: str):
return requests.get(f"http://127.0.0.1:1242{path}", headers={"Authentication": ASF_PASSWORD})
def get_currency_name(currency_id: int) -> str:
if currency_id == 1:
return "USD"
elif currency_id == 3:
return "EUR"
elif currency_id == 5:
return "RUB"
elif currency_id == 18:
return "UAH"
elif currency_id == 6:
return "PLN"
elif currency_id == 0:
return ""
else:
return "???"
def get_inventory_icon(desc: dict) -> str:
tags = desc.get("tags", [])
for tag in tags:
category = tag.get("category", "")
name = tag.get("localized_tag_name", "")
if category == "item_class":
if "Trading Card" in name:
return "🃏"
if "Emoticon" in name:
return "😀"
if "Profile Background" in name:
return "🖼"
if "Booster Pack" in name:
return "📦"
if "Steam Gems" in name:
return "💎"
if "Gift" in name:
return "🎁"
item_type = desc.get("type", "").lower()
if "knife" in item_type:
return "🔪"
if "pistol" in item_type:
return "🔫"
if "rifle" in item_type:
return "🎯"
if "graffiti" in item_type:
return "🎨"
if "music kit" in item_type:
return "🎵"
return "📦"
def format_asf(data: dict) -> str:
result = data.get("Result", {})
config = result.get("GlobalConfig", {})
current_version = result.get("Version")
latest_version = result.get("LatestVersion", current_version)
lines = [f"Версия ASF: {current_version}"]
if current_version != latest_version:
lines.append(f"Доступно обновление: {latest_version}")
memory_kb = result.get("MemoryUsage", 0)
memory_mb = memory_kb / 1024
lines.append(f"Используется памяти: {memory_mb:.2f} MB")
lines.append(f"Работает: {get_uptime(result.get('ProcessStartTime'))}")
return "\n".join(lines)
def get_uptime(start_time_str: str) -> str:
start_time_str = start_time_str[:26] + "Z"
start_time = datetime.fromisoformat(start_time_str.replace("Z", "+00:00"))
now = datetime.now(timezone.utc)
delta = now - start_time
days = delta.days
hours, remainder = divmod(delta.seconds, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{days}д {hours}ч {minutes}м {seconds}с"
def get_bot_status_icon(bot: dict) -> str:
online = bot.get("IsConnectedAndLoggedOn", False)
farming = bot.get("CardsFarmer", {}).get("NowFarming", False)
idle_games = bot.get("BotConfig", {}).get("GamesPlayedWhileIdle", [])
loaded = bool(bot.get("BotName")) and bool(bot.get("SteamID"))
if not loaded:
return "🔄"
if farming:
return "🎴"
if idle_games and online:
return "⌚"
if online:
return "🟢"
return "🔴"
def format_bot_ui(bot: dict) -> str:
online = get_bot_status_icon(bot)
now_farming = bot.get("CardsFarmer", {}).get("NowFarming")
if now_farming:
status_line = "🃏 Идет фарм карточек"
else:
status_line = "🃏 Карточки не фармится"
time = bot.get("CardsFarmer", {}).get("TimeRemaining", "00:00:00")
games_to_farm = len(bot.get("CardsFarmer", {}).get("GamesToFarm", []))
twofa = "есть" if bot.get("HasMobileAuthenticator") else "нет"
balance = bot.get("WalletBalance", 0) / 100
currency = get_currency_name(bot.get("WalletCurrency", 0))
redeem = bot.get("GamesToRedeemInBackgroundCount", 0)
steam_id = bot.get("SteamID")
nickname = html.escape(str(bot.get("Nickname") or ""))
profile_url = f"https://steamcommunity.com/profiles/{steam_id}"
text = (
f"{online}"
f" {bot.get('BotName') or 'Загрузка...'}"
f"({nickname})\n"
f"{status_line}\n")
idle_games = bot.get("BotConfig", {}).get("GamesPlayedWhileIdle", [])
if idle_games:
names = [GAMES.get(g, str(g)) for g in idle_games]
if bot.get("IsConnectedAndLoggedOn"):
idle_text = f"⌚ Накрутка часов: включена ({', '.join(names)})"
else:
idle_text = f"⌚ Накрутка часов: включена ({', '.join(names)}) применится после запуска"
text += f"{idle_text}\n"
else:
text += "⌚ Накрутка часов: выключена\n"
text += (
f"🆔 : {steam_id}\n"
f"🔐 2FA: {twofa}\n\n"
f"💰 Баланс: {balance:.2f} {currency}\n")
if redeem > 0:
text += f"\nКлючей в очереди: {redeem}\n"
if now_farming:
text += f"\nОсталось: {time}\n"
if games_to_farm > 0:
text += f"В очереди игр: {games_to_farm}\n"
return text
def get_asf_status_text():
response = requests.get(ASF_URL, headers={"Authentication": ASF_PASSWORD}) # type: ignore
if response.status_code != 200:
return f"Ошибка API: {response.status_code}"
data = response.json()
if not data.get("Success"):
return "ASF вернул ошибку"
status_text = format_asf(data)
return f"💻 Панель управления ASF\n\n{status_text}"
def get_farm_summary(bots: dict) -> str:
total_games = 0
total_time_seconds = 0
for bot in bots.values():
farmer = bot.get("CardsFarmer", {})
if farmer.get("NowFarming"):
games = farmer.get("CurrentGamesFarming", [])
total_games += len(games)
time_str = farmer.get("TimeRemaining", "00:00:00")
h, m, s = map(int, time_str.split(":"))
total_time_seconds += h * 3600 + m * 60 + s
if total_games == 0:
return "На аккаунтах нечего не фармиться"
hours = total_time_seconds // 3600
minutes = (total_time_seconds % 3600) // 60
return (
f"Игр фармится: {total_games}\n"
f"Осталось времени: {hours}ч {minutes}м\n"
f"Карт осталось: ~{total_games * 3}")
def format_bot(bot_data: dict) -> str:
return json.dumps(bot_data, indent=2, ensure_ascii=False)
def main_keyboard():
return InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="🆙 Обновить", callback_data="refresh")],
[InlineKeyboardButton(text="🤖 Боты", callback_data="bots")],
[InlineKeyboardButton(text="🔑 Активация ключей на всех аккаунтах", callback_data="redeem_keys")],
[InlineKeyboardButton(text="📁 Плагины", callback_data="plugins")],
[InlineKeyboardButton(text="💻 Консоль", callback_data="console")],
[InlineKeyboardButton(text="♻ Перезапустить ASF", callback_data="restart_asf_confirm")]])
def back_keyboard():
return InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data="back")]])
def games_keyboard(bot_name, is_enabled):
if is_enabled:
text = "Остановить накрутку CS2"
else:
text = "⌚ Накрутить часы CS2"
return InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text=text, callback_data=f"farm|{bot_name}|730")],
[InlineKeyboardButton(text="🔙 Назад", callback_data=f"bot_{bot_name}")]])
def bots_keyboard(bots: dict):
keyboard = []
for name, bot in bots.items():
status = get_bot_status_icon(bot)
loaded = (bool(bot.get("BotName")) and bool(bot.get("SteamID")))
if not loaded:
callback_data = "bot_loading"
else:
callback_data = f"bot_{name}"
keyboard.append([InlineKeyboardButton(text=f"{status} {name}", callback_data=callback_data)])
keyboard.append([InlineKeyboardButton(text="🔙 Назад", callback_data="back")])
return InlineKeyboardMarkup(inline_keyboard=keyboard)
def is_bot_playing(bot_name: str) -> bool:
response = asf_get("/Api/Bot/ASF")
if response.status_code != 200:
return False
data = response.json()
bot = data.get("Result", {}).get(bot_name, {})
return bool(bot.get("PlayingBlocked", False)) or bool(bot.get("CurrentGamesPlayed", []))
def is_idle_enabled(bot_name: str, app_id: int) -> bool:
response = requests.get(f"http://127.0.0.1:1242/Api/Bot/{bot_name}", headers={"Authentication": ASF_PASSWORD})
if response.status_code != 200:
return False
data = response.json()
bot = data.get("Result", {}).get(bot_name, {})
config = bot.get("BotConfig", {})
return app_id in config.get("GamesPlayedWhileIdle", [])
async def get_2fa_code(bot_name: str) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(f"http://127.0.0.1:1242/Api/Bot/{bot_name}/TwoFactorAuthentication/Token", headers={"Authentication": ASF_PASSWORD}) as response: # type: ignore
if response.status != 200:
return f"Ошибка HTTP {response.status}"
data = await response.json()
if not data.get("Success"):
return "Ошибка ASF"
try:
return data["Result"][bot_name]["Result"]
except:
return "Не удалось получить код"
async def get_confirmations(bot_name: str):
async with aiohttp.ClientSession() as session:
async with session.get(f"http://127.0.0.1:1242/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations", headers={"Authentication": ASF_PASSWORD}) as response: # type: ignore
if response.status != 200:
return []
data = await response.json()
if not data.get("Success"):
return []
try:
return data["Result"][bot_name]["Result"]
except:
return []
async def get_inventory(bot_name: str, appid: int, contextid: int = 2):
url = (f"http://127.0.0.1:1242/Api/Bot/{bot_name}/Inventory/{appid}/{contextid}")
async with aiohttp.ClientSession() as session:
async with session.get(url, headers={"Authentication": ASF_PASSWORD}) as response: # type: ignore
if response.status != 200:
return None
data = await response.json()
if not data.get("Success"):
return None
try:
return data["Result"]
except:
return None
async def render_inventory_page(callback: CallbackQuery, bot_name: str, inventory_type: str, appid: int, contextid: int, page: int):
await callback.message.edit_text("Загрузка inventory...") # type: ignore
inventory = await get_inventory(bot_name, appid, contextid)
if not inventory:
await callback.message.edit_text("Не удалось загрузить inventory") # type: ignore
return
bot_inventory = inventory.get(bot_name, {})
assets = bot_inventory.get("Assets", [])
descriptions = bot_inventory.get("Descriptions", [])
if not assets:
await callback.message.edit_text("Инвентарь пуст", reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data=f"inventory_{bot_name}")]])) # type: ignore
return
desc_map = {}
for desc in descriptions:
key = (str(desc.get("classid")), str(desc.get("instanceid")))
desc_map[key] = desc
total_pages = (len(assets) + PAGE_SIZE - 1) // PAGE_SIZE
start = page * PAGE_SIZE
end = start + PAGE_SIZE
page_assets = assets[start:end]
lines = []
marketable_count = 0
tradable_count = 0
cards_count = 0
emotes_count = 0
backgrounds_count = 0
gems_count = 0
for asset in page_assets:
key = (str(asset.get("classid")), str(asset.get("instanceid")))
desc = desc_map.get(key, {})
name = desc.get("market_name", "Unknown")
amount = asset.get("amount", 1)
tradable = ("🔄" if desc.get("tradable") else "❌")
marketable = ("💰" if desc.get("marketable") else "🔒")
icon = get_inventory_icon(desc)
if desc.get("marketable"):
marketable_count += 1
if desc.get("tradable"):
tradable_count += 1
if icon == "🃏":
cards_count += amount
elif icon == "😀":
emotes_count += amount
elif icon == "🖼":
backgrounds_count += amount
elif icon == "💎":
gems_count += amount
lines.append(f"{icon} {tradable}{marketable} {name} x{amount}")
inv_name = ("CS2" if appid == 730 else "Steam")
stats = (
f"📦 Items: {len(assets)}\n"
f"💰 Marketable: {marketable_count}\n"
f"🔄 Tradable: {tradable_count}")
if appid == 753:
stats += (
f"\n🃏 Cards: {cards_count}"
f"\n😀 Emotes: {emotes_count}"
f"\n🖼 Backgrounds: {backgrounds_count}"
f"\n💎 Gems: {gems_count}")
text = (
f"📦 {inv_name} Inventory {bot_name}\n"
f"📄 Страница {page + 1}/{total_pages}\n\n"
f"{stats}\n\n"
+ "\n".join(lines))
nav_buttons = []
if page > 0:
nav_buttons.append(InlineKeyboardButton(text="◀", callback_data=f"invpage|{inventory_type}|{bot_name}|{page - 1}"))
if page < total_pages - 1:
nav_buttons.append(InlineKeyboardButton(text="▶", callback_data=f"invpage|{inventory_type}|{bot_name}|{page + 1}"))
keyboard = []
if nav_buttons:
keyboard.append(nav_buttons)
keyboard.append([InlineKeyboardButton(text="🔙 Назад", callback_data=f"inventory_{bot_name}")])
await callback.message.edit_text(text[:4000], reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard)) # type: ignore
async def reload_bot(bot_name: str):
try:
requests.post("http://127.0.0.1:1242/Api/Command", headers={"Authentication": ASF_PASSWORD}, json={"Command": f"!reload {bot_name}"})
except:
pass
async def stop_twofa_task(message_id: int):
task = twofa_tasks.pop(message_id, None)
if task:
task.cancel()
try:
await task
except:
pass
async def redeem_key(bot_name: str, key: str):
async with aiohttp.ClientSession() as session:
async with session.post("http://127.0.0.1:1242/Api/Command", headers={"Authentication": ASF_PASSWORD}, json={"Command": f"!redeem {bot_name} {key}"}) as response: # type: ignore
if response.status != 200:
return False, f"HTTP_ERROR_{response.status}"
data = await response.json()
if not data.get("Success"):
return False, "ASF_ERROR"
return True, str(data.get("Result", ""))
@dp.callback_query(lambda c: c.data == "bot_loading", AdminCallbackFilter())
async def bot_loading_handler(callback: CallbackQuery):
await callback.answer("Аккаунт ещё загружается. Попробуйте через несколько секунд.", show_alert=True)
async def auto_update_2fa(message, bot_name):
last_code = None
message_id = message.message_id
try:
while True:
code = await get_2fa_code(bot_name)
if code != last_code:
confirmations = await get_confirmations(bot_name)
keyboard = []
if confirmations:
keyboard.append([InlineKeyboardButton(text="Подтверждения", callback_data=f"confirm_list_{bot_name}")])
keyboard.append([InlineKeyboardButton(text="🔙 Назад", callback_data=f"bot_{bot_name}")])
text = (
f"🔐 {bot_name}\n\n"
f"{code}")
try:
await message.edit_text(text, reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard))
last_code = code
except:
break
await asyncio.sleep(15)
except asyncio.CancelledError:
pass
except Exception as e:
print(f"2FA updater error: {e}")
finally:
twofa_tasks.pop(message_id, None)
@dp.message(Command("start"), AdminFilter())
async def start_handler(message: Message):
try:
await message.delete()
except:
pass
try:
text = get_asf_status_text()
await message.answer(text, reply_markup=main_keyboard())
except Exception as e:
await message.answer(f"Ошибка: {e}")
@dp.callback_query(lambda c: c.data == "console", AdminCallbackFilter())
async def console_enter(callback: CallbackQuery):
await callback.answer()
console_users.add(callback.from_user.id)
await callback.message.edit_text("💻 Консоль ASF\n\nОтправь команду (без !)", reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data="console_exit")]])) # type: ignore
@dp.callback_query(lambda c: c.data == "console_exit", AdminCallbackFilter())
async def console_exit(callback: CallbackQuery):
await callback.answer()
console_users.discard(callback.from_user.id)
text = get_asf_status_text()
await callback.message.edit_text(text, reply_markup=main_keyboard()) # type: ignore
@dp.callback_query(lambda c: c.data == "delete_msg", AdminCallbackFilter())
async def delete_message(callback: CallbackQuery):
await callback.answer()
try:
await callback.message.delete() # type: ignore
except:
pass
@dp.callback_query(lambda c: c.data == "bots", AdminCallbackFilter())
async def bots_handler(callback: CallbackQuery):
await stop_twofa_task(callback.message.message_id) # type: ignore
await callback.answer()
try:
response = requests.get("http://127.0.0.1:1242/Api/Bot/ASF", headers={"Authentication": ASF_PASSWORD})
if response.status_code != 200:
await callback.message.edit_text("Ошибка API") # type: ignore
return
data = response.json()
if not data.get("Success"):
await callback.message.edit_text("ASF вернул ошибку") # type: ignore
return
bots = data.get("Result", {})
count = len(bots)
summary = get_farm_summary(bots)
text = (
f"🤖 Ботов всего: {count}\n\n"
f"{summary}")
await callback.message.edit_text(text, reply_markup=bots_keyboard(bots)) # type: ignore
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data and c.data.startswith("bot_"), AdminCallbackFilter())
async def bot_selected(callback: CallbackQuery):
await stop_twofa_task(callback.message.message_id) # type: ignore
await callback.answer()
if not callback.data:
return
bot_name = callback.data.replace("bot_", "")
try:
response = asf_get("/Api/Bot/ASF")
data = response.json()
bots = data.get("Result", {})
bot = bots.get(bot_name)
if not bot or not bot.get("BotName") or not bot.get("SteamID"):
await callback.answer("Аккаунт ещё загружается. Попробуйте через несколько секунд.", show_alert=True)
return
if not bot:
await callback.message.edit_text("Бот не найден") # type: ignore
return
text = format_bot_ui(bot)
keyboard = []
if bot.get("HasMobileAuthenticator"):
keyboard.append([InlineKeyboardButton(text="🔐 2FA", callback_data=f"2fa_{bot_name}")])
keyboard.append([InlineKeyboardButton(text="⌚ Накрутка часов", callback_data=f"games_{bot_name}")])
keyboard.append([InlineKeyboardButton(text="🔑 Активировать ключ", callback_data=f"redeem_bot_{bot_name}")])
keyboard.append([InlineKeyboardButton(text="📦 Инвентарь", callback_data=f"inventory_{bot_name}")])
keyboard.append([InlineKeyboardButton(text="🔙 Назад", callback_data="bots")])
await callback.message.edit_text(text, disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard)) # type: ignore
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data and c.data.startswith("games_"), AdminCallbackFilter())
async def games(callback: CallbackQuery):
await callback.answer()
if not callback.data:
return
bot_name = callback.data.replace("games_", "")
idle_enabled = is_idle_enabled(bot_name, 730)
await callback.message.edit_text("⌚ Выберите игру для накрутки часов", reply_markup=games_keyboard(bot_name, idle_enabled)) # type: ignore
@dp.callback_query(lambda c: c.data == "back", AdminCallbackFilter())
async def back_button(callback: CallbackQuery):
redeem_users.discard(callback.from_user.id)
redeem_messages.pop(callback.from_user.id, None)
console_users.discard(callback.from_user.id)
bot_redeem_users.pop(callback.from_user.id, None)
bot_redeem_messages.pop(callback.from_user.id, None)
await stop_twofa_task(callback.message.message_id) # type: ignore
await callback.answer()
try:
text = get_asf_status_text()
await callback.message.edit_text(text, reply_markup=main_keyboard()) # type: ignore
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data == "refresh", AdminCallbackFilter())
async def refresh_handler(callback: CallbackQuery):
await callback.answer()
try:
text = get_asf_status_text()
await callback.message.edit_text(text, reply_markup=main_keyboard()) # type: ignore
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data == "restart_asf_confirm", AdminCallbackFilter())
async def restart_asf_confirm(callback: CallbackQuery):
await callback.answer()
await callback.message.edit_text( # type: ignore
"♻ Точно перезапустить ASF?\n\n"
"Во время перезапуска IPC будет недоступен несколько секунд.",
reply_markup=InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text="Да", callback_data="restart_asf")],
[InlineKeyboardButton(text="Нет", callback_data="back")]]))
@dp.callback_query(lambda c: c.data == "restart_asf", AdminCallbackFilter())
async def restart_asf(callback: CallbackQuery):
await callback.answer()
try:
await callback.message.edit_text("♻ ASF перезапускается...") # type: ignore
response = requests.post("http://127.0.0.1:1242/Api/Command", headers={"Authentication": ASF_PASSWORD}, json={"Command": "!restart"})
if response.status_code != 200:
await callback.message.edit_text(f"Ошибка HTTP {response.status_code}", reply_markup=main_keyboard()) # type: ignore
return
await asyncio.sleep(6)
text = get_asf_status_text()
await callback.message.edit_text(f"ASF успешно перезапущен\n\n{text}", reply_markup=main_keyboard()) # type: ignore
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}", reply_markup=main_keyboard()) # type: ignore
@dp.callback_query(lambda c: c.data and c.data.startswith("2fa_") and not c.data.startswith("2fa_refresh_"), AdminCallbackFilter())
async def twofa_handler(callback: CallbackQuery):
await callback.answer()
if not callback.data:
return
bot_name = callback.data.replace("2fa_", "")
message_id = callback.message.message_id # type: ignore
old_task = twofa_tasks.pop(message_id, None)
if old_task:
old_task.cancel()
try:
await old_task
except:
pass
await callback.message.edit_text( # type: ignore
f"🔐 {bot_name}\n\nЗагрузка 2FA...",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data=f"bot_{bot_name}")]]))
task = asyncio.create_task(auto_update_2fa(callback.message, bot_name))
twofa_tasks[message_id] = task
@dp.callback_query(lambda c: c.data and c.data.startswith("confirm_") and not c.data.startswith("confirm_list_") and not c.data.startswith("confirm_all_"), AdminCallbackFilter())
async def confirm_trades(callback: CallbackQuery):
await callback.answer()
bot_name = callback.data.replace("confirm_", "") # type: ignore
try:
response = requests.post(f"http://127.0.0.1:1242/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations/Accept", headers={"Authentication": ASF_PASSWORD})
if response.status_code != 200:
await callback.answer("Ошибка HTTP", show_alert=True)
return
await callback.answer("Подтверждено", show_alert=True)
await twofa_handler(callback)
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data == "plugins", AdminCallbackFilter())
async def plugins_handler(callback: CallbackQuery):
await stop_twofa_task(callback.message.message_id) # type: ignore
await callback.answer()
try:
response = requests.get("http://127.0.0.1:1242/Api/Plugins", headers={"Authentication": ASF_PASSWORD})
if response.status_code != 200:
await callback.message.edit_text("Ошибка API") # type: ignore
return
data = response.json()
if not data.get("Success"):
await callback.message.edit_text("ASF вернул ошибку") # type: ignore
return
plugins = data.get("Result", [])
if not plugins:
text = "Плагины не установлены"
else:
text = "📁 Плагины ASF:\n\n"
for plugin in plugins:
name = plugin.get("Name", "???")
version = plugin.get("Version", "???")
text += f"{name} ({version})\n"
await callback.message.edit_text(text.strip(), reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data="back")]])) # type: ignore
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data and c.data.startswith("confirm_list_"), AdminCallbackFilter())
async def confirm_list(callback: CallbackQuery):
await stop_twofa_task(callback.message.message_id) # type: ignore
await callback.answer()
if not callback.data:
return
bot_name = callback.data.replace("confirm_list_", "")
try:
confirmations = await get_confirmations(bot_name)
if not confirmations:
text = "Подтверждений нет"
else:
text = f" {bot_name}\n\nПодтверждения:\n\n"
for conf in confirmations:
text += (
f"- {conf['type_name']}\n"
f"ID: {conf['id']}\n\n")
await callback.message.edit_text(text, # type: ignore
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Подтвердить всё", callback_data=f"confirm_all_{bot_name}")],
[InlineKeyboardButton(text="🔙 Назад", callback_data=f"2fa_{bot_name}")]]))
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data and c.data.startswith("confirm_all_"), AdminCallbackFilter())
async def confirm_all(callback: CallbackQuery):
await stop_twofa_task(callback.message.message_id) # type: ignore
await callback.answer()
if not callback.data:
return
bot_name = callback.data.replace("confirm_all_", "")
try:
response = requests.post(f"http://127.0.0.1:1242/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations/Accept", headers={"Authentication": ASF_PASSWORD})
if response.status_code != 200:
await callback.answer("Ошибка HTTP", show_alert=True)
return
# заново получаем список
confirmations = await get_confirmations(bot_name)
if not confirmations:
text = f" {bot_name}\n\nПодтверждений больше нет"
else:
text = f" {bot_name}\n\nПодтверждения:\n\n"
for conf in confirmations:
text += (
f"- {conf['type_name']}\n"
f"ID: {conf['id']}\n\n")
await callback.message.edit_text( # type: ignore
text,
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Подтвердить всё", callback_data=f"confirm_all_{bot_name}")],
[InlineKeyboardButton(text="Назад", callback_data=f"2fa_{bot_name}")]]))
await callback.answer(" Все подтверждено", show_alert=True)
except Exception as e:
await callback.message.edit_text(f"Ошибка: {e}") # type: ignore
@dp.callback_query(lambda c: c.data and c.data.startswith("farm|"), AdminCallbackFilter())
async def farm_game(callback: CallbackQuery):
await callback.answer()
if not callback.data:
return
_, bot_name, app_id = callback.data.split("|")
app_id = int(app_id)
try:
# получаем текущий конфиг
response = requests.get(f"http://127.0.0.1:1242/Api/Bot/{bot_name}", headers={"Authentication": ASF_PASSWORD})
data = response.json()
bot_data = data.get("Result", {}).get(bot_name, {})
config = bot_data.get("BotConfig", {})
idle_games = config.get("GamesPlayedWhileIdle", [])
if app_id in idle_games:
idle_games.remove(app_id)
action = "Idle выключен"
else:
idle_games.append(app_id)
action = "Idle включен"
config["GamesPlayedWhileIdle"] = idle_games
save = requests.post(
f"http://127.0.0.1:1242/Api/Bot/{bot_name}", headers={"Authentication": ASF_PASSWORD}, json={"BotConfig": config})
if save.status_code != 200:
await callback.answer("Ошибка сохранения", show_alert=True)
return
asyncio.create_task(reload_bot(bot_name))
await callback.answer(action, show_alert=True)
try:
await callback.message.edit_reply_markup(reply_markup=games_keyboard(bot_name, app_id in idle_games)) # type: ignore
except:
pass
except Exception as e:
await callback.answer(f"Ошибка: {e}", show_alert=True)
@dp.callback_query(lambda c: c.data and c.data.startswith("inventory_"), AdminCallbackFilter())
async def inventory_menu(callback: CallbackQuery):
await callback.answer()
bot_name = callback.data.replace("inventory_", "") # type: ignore
await callback.message.edit_text("Проверка inventory...") # type: ignore
cs2_inventory = await get_inventory(bot_name, 730, 2)
steam_inventory = await get_inventory(bot_name, 753, 6)
cs2_assets = []
steam_assets = []
try:
cs2_assets = (cs2_inventory.get(bot_name, {}).get("Assets", [])) # type: ignore
except:
pass
try:
steam_assets = (steam_inventory.get(bot_name, {}).get("Assets", [])) # type: ignore
except:
pass
if not cs2_assets and not steam_assets:
await callback.message.edit_text(f"📦 Инвентарь {bot_name} пуст", reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data=f"bot_{bot_name}")]])) # type: ignore
return
keyboard = []
if cs2_assets:
keyboard.append([InlineKeyboardButton(text=f"CS2 ({len(cs2_assets)})", callback_data=f"inv_cs2_{bot_name}")])
if steam_assets:
keyboard.append([InlineKeyboardButton(text=f"Steam ({len(steam_assets)})", callback_data=f"inv_steam_{bot_name}")])
keyboard.append([InlineKeyboardButton(text="🔙 Назад", callback_data=f"bot_{bot_name}")])
await callback.message.edit_text( # type: ignore
(
f"📦 Инвентарь {bot_name}\n\n"
"🔄 — можно трейдить\n"
"💰 — можно продавать\n"
"🔒 — нельзя продавать\n"
"❌ — нельзя трейдить"
),
reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard)
)
@dp.callback_query(lambda c: c.data and c.data.startswith("inv_cs2_"), AdminCallbackFilter())
async def cs2_inventory(callback: CallbackQuery):
await callback.answer()
bot_name = callback.data.replace("inv_cs2_", "") # type: ignore
await render_inventory_page(callback, bot_name, "cs2", 730, 2, 0)
@dp.callback_query(lambda c: c.data and c.data.startswith("inv_steam_"), AdminCallbackFilter())
async def steam_inventory(callback: CallbackQuery):
await callback.answer()
bot_name = callback.data.replace("inv_steam_", "") # type: ignore
await render_inventory_page(callback, bot_name, "steam", 753, 6, 0)
@dp.callback_query(lambda c: c.data and c.data.startswith("invpage|"), AdminCallbackFilter())
async def inventory_page(callback: CallbackQuery):
await callback.answer()
_, inv_type, bot_name, page = callback.data.split("|") # type: ignore
page = int(page)
if inv_type == "cs2":
await render_inventory_page(callback, bot_name, "cs2", 730, 2, page)
else:
await render_inventory_page(callback, bot_name, "steam", 753, 6, page)
@dp.callback_query(lambda c: c.data == "redeem_keys", AdminCallbackFilter())
async def redeem_keys_menu(callback: CallbackQuery):
await callback.answer()
redeem_users.add(callback.from_user.id)
redeem_messages[callback.from_user.id] = callback.message
await callback.message.edit_text( # type: ignore
"Отправьте ключ Steam для активации\n\n"
"Можно отправить сразу несколько ключей.\n\n"
"Пример:\n"
"AAAAA-BBBBB-CCCCC\nDDDDD-EEEEE-FFFFF",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data="back")]]))
@dp.callback_query(lambda c: c.data and c.data.startswith("redeem_bot_"), AdminCallbackFilter())
async def redeem_bot_menu(callback: CallbackQuery):
await callback.answer()
bot_name = callback.data.replace("redeem_bot_", "") # type: ignore
bot_redeem_users[callback.from_user.id] = bot_name
bot_redeem_messages[callback.from_user.id] = callback.message
await callback.message.edit_text( # type: ignore
f"Отправьте ключ Steam для активации на аккаунте:\n"
f"{bot_name}\n\n"
f"Можно отправить сразу несколько ключей.",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🔙 Назад", callback_data=f"bot_{bot_name}")]]))
@dp.message(AdminFilter())
async def text_router(message: Message):
# console mode
if message.from_user.id in console_users: # type: ignore
command = message.text.strip() # type: ignore
try:
await message.delete()
except:
pass
try:
response = requests.post("http://127.0.0.1:1242/Api/Command", headers={"Authentication": ASF_PASSWORD}, json={"Command": f"!{command}"})
if response.status_code != 200:
text = f"Ошибка HTTP {response.status_code}"
else:
data = response.json()
if not data.get("Success"):
text = "Ошибка ASF"
else:
result = html.escape(str(data.get("Result", "Нет ответа")))
text = (
f"Команда: {command}\n\n"
f"Ответ:\n{result}"
)
await message.answer(text, reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="Удалить", callback_data="delete_msg")]]))
except Exception as e:
await message.answer(f"Ошибка: {e}")
return
# single bot redeem mode
if message.from_user.id in bot_redeem_users: # type: ignore
bot_name = bot_redeem_users.pop(message.from_user.id) # type: ignore
menu_message = bot_redeem_messages.pop(message.from_user.id, None) # type: ignore
if menu_message:
try:
response = requests.get("http://127.0.0.1:1242/Api/Bot/ASF",headers={"Authentication": ASF_PASSWORD})
data = response.json()
bot_data = data.get("Result", {}).get(bot_name)
if bot_data:
await menu_message.edit_text(
format_bot_ui(bot_data),
disable_web_page_preview=True,
reply_markup=InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text="🔐 2FA", callback_data=f"2fa_{bot_name}")]
if bot_data.get("HasMobileAuthenticator") else [],
[InlineKeyboardButton(text="⌚ Накрутка часов", callback_data=f"games_{bot_name}")],
[InlineKeyboardButton(text="🔑 Активировать ключ", callback_data=f"redeem_bot_{bot_name}")],
[InlineKeyboardButton(text="📦 Инвентарь", callback_data=f"inventory_{bot_name}")],
[InlineKeyboardButton(text="🔙 Назад", callback_data="bots")]]))
except:
pass
try:
await bot.delete_message(chat_id=message.chat.id, message_id=message.message_id)
except:
pass
raw_text = message.text.upper() # type: ignore
keys = re.findall(r"[A-Z0-9]{5}(?:-[A-Z0-9]{5}){2}", raw_text)
keys = list(dict.fromkeys(keys))
if not keys:
await message.answer("Ключи не найдены")
return
checking = await message.answer(
f"Аккаунт: {bot_name}\n"
f"Найдено ключей: {len(keys)}\n"
f"Начинаю активацию...")
success_count = 0
failed_count = 0
results = []
for key in keys:
success, result = await redeem_key(bot_name, key)
await asyncio.sleep(2)
if not success or not result:
failed_count += 1
results.append(f"❌ {key}: ASF ERROR")
continue
result_lower = result.lower()
if "ok/nodetail" in result_lower or "ok/" in result_lower:
success_count += 1
results.append(f"✅ {key}: активировано")
elif "ratelimited" in result_lower:
failed_count += 1
results.append(f"⏳ {key}: rate limit")
elif "alreadypurchased" in result_lower:
failed_count += 1
results.append(f"⚠️ {key}: игра уже есть")
elif "duplicateactivationcode" in result_lower:
failed_count += 1
results.append(f"❌ {key}: ключ уже использован")
elif "regionlocked" in result_lower:
failed_count += 1
results.append(f"🌍 {key}: регион лок")
elif "invalidactivationcode" in result_lower or "invalid" in result_lower:
failed_count += 1
results.append(f"❌ {key}: неверный ключ")
else:
failed_count += 1
results.append(f"❔ {key}: неизвестный ответ")
text = (
f"Результат активации для {bot_name}\n\n"
f"✅ Успешно: {success_count}\n"
f"❌ Ошибок: {failed_count}\n\n"
+ "\n".join(results[:50]))
if len(text) > 4000:
text = text[:4000] + "\n\n...обрезано"
await checking.edit_text(text)
return
if message.from_user.id in redeem_users: # type: ignore
redeem_users.discard(message.from_user.id) # type: ignore
menu_message = redeem_messages.pop(message.from_user.id, None) # type: ignore
if menu_message:
try:
await menu_message.edit_text(get_asf_status_text(), reply_markup=main_keyboard())
except:
pass
try:
await bot.delete_message(chat_id=message.chat.id, message_id=message.message_id)
except:
pass
raw_text = message.text.upper() # type: ignore
keys = re.findall(r"[A-Z0-9]{5}(?:-[A-Z0-9]{5}){2}", raw_text)
keys = list(dict.fromkeys(keys))
if not keys:
await message.answer("Ключи не найдены")
return
checking = await message.answer(f"Найдено ключей: {len(keys)}\nНачинаю активацию...")
try:
response = asf_get("/Api/Bot/ASF")
data = response.json()
bots = list(data.get("Result", {}).keys())
success_count = 0
failed_count = 0
results = []
for key in keys:
activated = False
key_report = []
for bot_name in bots:
success, result = await redeem_key(bot_name, key)
await asyncio.sleep(2)
if not success or not result:
key_report.append(f"❌ {bot_name}: ASF ERROR")
continue
print(result)
result_lower = result.lower()
bot_line = ""
for line in result.splitlines():
if f"<{bot_name.lower()}>" in line.lower():
bot_line = line
break
if bot_line:
parsed = bot_line.lower()
else:
parsed = result_lower
if "ok/nodetail" in parsed or "ok/" in parsed:
key_report.append(f"✅ {bot_name}: активировано")
success_count += 1
activated = True
break
elif "ratelimited" in parsed:
key_report.append(f"⏳ {bot_name}: rate limit")
continue
elif "alreadypurchased" in parsed or "already purchased" in parsed:
key_report.append(f"⚠️ {bot_name}: игра уже есть")
continue
elif "duplicateactivationcode" in parsed:
key_report.append(f"❌ {bot_name}: ключ уже использован")
break
elif "regionlocked" in parsed:
key_report.append(f"🌍 {bot_name}: регион лок")
continue
elif "invalidactivationcode" in parsed or "invalid" in parsed:
key_report.append(f"❌ {bot_name}: неверный ключ")
break
else:
key_report.append(f"❔ {bot_name}: неизвестный ответ")
continue
if not activated:
failed_count += 1
results.append(f"\n🔑 {key}\n" + "\n".join(key_report))
text = (
f"Результат активации\n\n"
f"✅ Успешно: {success_count}\n"
f"❌ Ошибок: {failed_count}\n\n"
+ "\n".join(results[:50]))
if len(text) > 4000:
text = text[:4000] + "\n\n...обрезано"
await checking.edit_text(text)
except Exception as e:
await checking.edit_text(f"Ошибка: {e}")
return
async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())