import asyncio import re from bot.logging_utils import get_logger from bot.api.asf import get_all_bots, redeem_key KEY_PATTERN = r"[A-Z0-9]{5}(?:-[A-Z0-9]{5}){2}" logger = get_logger(__name__) def extract_keys(text: str) -> list[str]: keys = re.findall(KEY_PATTERN, text.upper()) unique_keys = list(dict.fromkeys(keys)) logger.info("Из текста извлечены ключи: count=%s", len(unique_keys)) return unique_keys def parse_redeem_result(result: str, bot_name: str | None = None) -> str: result_lower = result.lower() if bot_name: for line in result.splitlines(): if f"<{bot_name.lower()}>" in line.lower(): result_lower = line.lower() break if "ok/nodetail" in result_lower or "ok/" in result_lower: return "success" if "ratelimited" in result_lower: return "rate_limited" if "alreadypurchased" in result_lower or "already purchased" in result_lower: return "already_owned" if "duplicateactivationcode" in result_lower: return "duplicate" if "regionlocked" in result_lower: return "region_locked" if "invalidactivationcode" in result_lower or "invalid" in result_lower: return "invalid" return "unknown" async def redeem_single_bot_keys(bot_name: str, keys: list[str]) -> str: logger.info( "Начата активация ключей для одного бота: bot=%s count=%s", bot_name, len(keys), ) success_count = 0 failed_count = 0 results = [] for key in keys: logger.info( "Попытка активации ключа для одного бота: bot=%s key=%s", bot_name, key, ) success, result = await redeem_key(bot_name, key) await asyncio.sleep(2) if not success or not result: failed_count += 1 logger.warning( "Активация ключа завершилась ошибкой ASF/HTTP: bot=%s key=%s", bot_name, key, ) results.append(f"❌ {key}: ошибка ASF") continue status = parse_redeem_result(result) logger.info( "Получен результат активации ключа: bot=%s key=%s status=%s", bot_name, key, status, ) if status == "success": success_count += 1 results.append(f"✅ {key}: активировано") elif status == "rate_limited": failed_count += 1 results.append(f"⏳ {key}: лимит запросов") elif status == "already_owned": failed_count += 1 results.append(f"⚠️ {key}: игра уже есть") elif status == "duplicate": failed_count += 1 results.append(f"❌ {key}: ключ уже использован") elif status == "region_locked": failed_count += 1 results.append(f"🌍 {key}: регион лок") elif status == "invalid": 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]) ) logger.info( "Завершена активация ключей для одного бота: bot=%s success=%s failed=%s", bot_name, success_count, failed_count, ) return text[:4000] + ("\n\n...обрезано" if len(text) > 4000 else "") async def redeem_all_bots_keys(keys: list[str], allowed_bots: list[str]) -> str: """Активирует ключи только на явно указанных личных ботах.""" if not allowed_bots: logger.info("Нет личных ботов для массовой активации ключей") return ( "Результат активации\n\n" "⚠️ У вас нет ботов, доступных для массовой активации.\n" "Ключи не отправлялись в ASF." ) logger.info( "Начата активация ключей на разрешенных ботах: keys=%s bots=%s", len(keys), len(allowed_bots), ) response = get_all_bots() data = response.json() available = list(data.get("Result", {}).keys()) allowed = set(allowed_bots) bots = [name for name in available if name in allowed] logger.info("Для массовой активации найдено ботов: count=%s", len(bots)) success_count = 0 failed_count = 0 results = [] for key in keys: activated = False key_report = [] logger.info("Начата обработка ключа по всем ботам: key=%s", key) for bot_name in bots: logger.info( "Попытка активации ключа на боте: bot=%s key=%s", bot_name, key, ) success, result = await redeem_key(bot_name, key) await asyncio.sleep(2) if not success or not result: logger.warning( "Активация ключа завершилась ошибкой ASF/HTTP: bot=%s key=%s", bot_name, key, ) key_report.append(f"❌ {bot_name}: ошибка ASF") continue status = parse_redeem_result(result, bot_name) logger.info( "Получен результат активации ключа: bot=%s key=%s status=%s", bot_name, key, status, ) if status == "success": key_report.append(f"✅ {bot_name}: активировано") success_count += 1 activated = True break if status == "rate_limited": key_report.append(f"⏳ {bot_name}: лимит запросов") continue if status == "already_owned": key_report.append(f"⚠️ {bot_name}: игра уже есть") continue if status == "duplicate": key_report.append(f"❌ {bot_name}: ключ уже использован") break if status == "region_locked": key_report.append(f"🌍 {bot_name}: регион лок") continue if status == "invalid": key_report.append(f"❌ {bot_name}: неверный ключ") break key_report.append(f"❔ {bot_name}: неизвестный ответ") if not activated: failed_count += 1 logger.warning( "Ключ не удалось активировать ни на одном боте: key=%s", key, ) results.append(f"\n🔑 {key}\n" + "\n".join(key_report)) text = ( "Результат активации\n\n" f"✅ Успешно: {success_count}\n" f"❌ Ошибок: {failed_count}\n\n" + "\n".join(results[:50]) ) logger.info( "Завершена массовая активация ключей: success=%s failed=%s", success_count, failed_count, ) return text[:4000] + ("\n\n...обрезано" if len(text) > 4000 else "")