diff --git a/telegram_bot.py b/telegram_bot.py index 7ddade4..9eda085 100644 --- a/telegram_bot.py +++ b/telegram_bot.py @@ -137,6 +137,7 @@ class ProvisionerBot: ("dashboard", self.cmd_dashboard), ("import", self.cmd_import), ("verify", self.cmd_verify), + ("verify_all", self.cmd_verify_all), ("stock", self.cmd_stock), ("gptmail_keys", self.cmd_gptmail_keys), ("gptmail_add", self.cmd_gptmail_add), @@ -270,7 +271,8 @@ class ProvisionerBot: BotCommand("stock", "查看账号库存"), BotCommand("s2a_config", "配置 S2A 参数"), BotCommand("import", "导入账号到 team.json"), - BotCommand("verify", "验证账号并移除无效账号"), + BotCommand("verify", "验证未验证的账号"), + BotCommand("verify_all", "强制重新验证所有账号"), # GPTMail BotCommand("gptmail_keys", "查看 GPTMail API Keys"), BotCommand("gptmail_add", "添加 GPTMail API Key"), @@ -338,7 +340,8 @@ class ProvisionerBot: 📤 导入账号: /import - 导入账号到 team.json -/verify - 验证账号并移除无效账号 +/verify - 验证未验证的账号 +/verify_all - 强制重新验证所有账号 或直接发送 JSON 文件 📧 GPTMail 管理: @@ -2041,20 +2044,23 @@ class ProvisionerBot: if added_count > 0: await self._validate_and_cleanup_accounts(chat_id) - async def _validate_and_cleanup_accounts(self, chat_id: int): + async def _validate_and_cleanup_accounts(self, chat_id: int, force_all: bool = False): """验证新导入账号的 account_id,移除无效账号 Args: chat_id: Telegram 聊天 ID,用于发送进度消息 + force_all: 是否强制重新验证所有有 token 的账号 """ import json from pathlib import Path from concurrent.futures import ThreadPoolExecutor, as_completed + mode_text = "重新验证" if force_all else "验证" + # 发送开始验证的消息 progress_msg = await self.app.bot.send_message( chat_id=chat_id, - text="🔍 正在验证账号...\n\n⏳ 获取 account_id 中...", + text=f"🔍 正在{mode_text}账号...\n\n⏳ 获取 account_id 中...", parse_mode="HTML" ) @@ -2075,13 +2081,19 @@ class ProvisionerBot: if not isinstance(accounts, list): accounts = [accounts] - # 筛选需要验证的账号 (有 token 但没有 account_id) + # 筛选需要验证的账号 accounts_to_verify = [] for i, acc in enumerate(accounts): token = acc.get("token", "") account_id = acc.get("account_id", "") - if token and not account_id: - accounts_to_verify.append((i, acc)) + if force_all: + # 强制模式:验证所有有 token 的账号 + if token: + accounts_to_verify.append((i, acc)) + else: + # 普通模式:只验证有 token 但没有 account_id 的账号 + if token and not account_id: + accounts_to_verify.append((i, acc)) if not accounts_to_verify: await self.app.bot.edit_message_text( @@ -2093,10 +2105,23 @@ class ProvisionerBot: return total = len(accounts_to_verify) + + # 生成进度条的辅助函数 + def make_progress_bar(current: int, total: int, width: int = 16) -> str: + """生成进度条字符串""" + if total == 0: + return "[" + "░" * width + "]" + filled = int(width * current / total) + empty = width - filled + percent = int(100 * current / total) + return f"[{'█' * filled}{'░' * empty}] {current}/{total} ({percent}%)" + await self.app.bot.edit_message_text( chat_id=chat_id, message_id=progress_msg.message_id, - text=f"🔍 正在验证账号...\n\n⏳ 验证 {total} 个账号的 account_id (20 并发)...", + text=f"🔍 正在{mode_text}账号...\n\n" + f"{make_progress_bar(0, total)}\n\n" + f"⏳ 验证 {total} 个账号的 account_id (20 并发)...", parse_mode="HTML" ) @@ -2148,11 +2173,12 @@ class ProvisionerBot: if completed_count % 10 == 0 or completed_count == total or current_time - last_update_time > 1: last_update_time = current_time try: + progress_bar = make_progress_bar(completed_count, total) await self.app.bot.edit_message_text( chat_id=chat_id, message_id=progress_msg.message_id, - text=f"🔍 正在验证账号...\n\n" - f"进度: {completed_count}/{total}\n" + text=f"🔍 正在{mode_text}账号...\n\n" + f"{progress_bar}\n\n" f"✅ 成功: {len(valid_indices)}\n" f"❌ 失败: {len(failed_accounts)}", parse_mode="HTML" @@ -2176,6 +2202,8 @@ class ProvisionerBot: lines = [ "✅ 账号验证完成", "", + f"{make_progress_bar(total, total)}", + "", f"📊 验证结果:", f" • 验证总数: {total}", f" • 成功: {len(valid_indices)}", @@ -2217,7 +2245,83 @@ class ProvisionerBot: @admin_only async def cmd_verify(self, update: Update, context: ContextTypes.DEFAULT_TYPE): - """手动验证 team.json 中的账号,获取 account_id 并移除无效账号""" + """手动验证 team.json 中的账号,获取 account_id 并移除无效账号 + + 用法: + /verify - 验证未验证的账号 + /verify_all - 强制重新验证所有账号 + """ + chat_id = update.effective_chat.id + + # 检查是否有任务正在运行 + if self.current_task and not self.current_task.done(): + await update.message.reply_text( + f"⚠️ 有任务正在运行: {self.current_team}\n" + "请等待任务完成或使用 /stop 停止后再验证" + ) + return + + # 解析参数 + force_all = context.args and context.args[0].lower() == "all" + + # 检查 team.json 是否存在 + from pathlib import Path + team_json_path = Path(TEAM_JSON_FILE) + if not team_json_path.exists(): + await update.message.reply_text("❌ team.json 不存在,请先导入账号") + return + + # 统计需要验证的账号 + import json + try: + with open(team_json_path, "r", encoding="utf-8") as f: + accounts = json.load(f) + if not isinstance(accounts, list): + accounts = [accounts] + except Exception as e: + await update.message.reply_text(f"❌ 读取 team.json 失败: {e}") + return + + total_accounts = len(accounts) + has_token = sum(1 for acc in accounts if acc.get("token")) + already_verified = sum(1 for acc in accounts if acc.get("account_id")) + + if force_all: + # 强制重新验证所有有 token 的账号 + need_verify = has_token + else: + # 只验证未验证的账号 + need_verify = sum(1 for acc in accounts if acc.get("token") and not acc.get("account_id")) + + if need_verify == 0: + await update.message.reply_text( + f"✅ 无需验证\n\n" + f"team.json 共 {total_accounts} 个账号\n" + f"有 Token: {has_token}\n" + f"已验证: {already_verified}\n" + f"待验证: 0\n\n" + f"💡 使用 /verify_all 强制重新验证所有账号", + parse_mode="HTML" + ) + return + + mode_text = "强制重新验证" if force_all else "验证" + await update.message.reply_text( + f"🔍 开始{mode_text}账号\n\n" + f"team.json 共 {total_accounts} 个账号\n" + f"有 Token: {has_token}\n" + f"已验证: {already_verified}\n" + f"待验证: {need_verify}\n\n" + f"⏳ 正在验证...", + parse_mode="HTML" + ) + + # 执行验证 + await self._validate_and_cleanup_accounts(chat_id, force_all=force_all) + + @admin_only + async def cmd_verify_all(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """强制重新验证所有账号""" chat_id = update.effective_chat.id # 检查是否有任务正在运行 @@ -2247,30 +2351,31 @@ class ProvisionerBot: return total_accounts = len(accounts) - need_verify = sum(1 for acc in accounts if acc.get("token") and not acc.get("account_id")) + has_token = sum(1 for acc in accounts if acc.get("token")) already_verified = sum(1 for acc in accounts if acc.get("account_id")) - if need_verify == 0: + if has_token == 0: await update.message.reply_text( - f"✅ 无需验证\n\n" + f"❌ 无法验证\n\n" f"team.json 共 {total_accounts} 个账号\n" - f"已验证: {already_verified}\n" - f"待验证: 0", + f"有 Token: 0\n\n" + f"没有可验证的账号", parse_mode="HTML" ) return await update.message.reply_text( - f"🔍 开始验证账号\n\n" + f"🔍 开始强制重新验证所有账号\n\n" f"team.json 共 {total_accounts} 个账号\n" + f"有 Token: {has_token}\n" f"已验证: {already_verified}\n" - f"待验证: {need_verify}\n\n" + f"待验证: {has_token}\n\n" f"⏳ 正在验证...", parse_mode="HTML" ) - # 执行验证 - await self._validate_and_cleanup_accounts(chat_id) + # 执行验证 (强制模式) + await self._validate_and_cleanup_accounts(chat_id, force_all=True) async def _import_batch_timeout_callback(self, context: ContextTypes.DEFAULT_TYPE): """批量导入超时回调 - 由 job_queue 调用"""