From 94145f7dd00ef12c9083dbbcd669f5d2d409ee0a Mon Sep 17 00:00:00 2001 From: kyx236 Date: Sun, 18 Jan 2026 06:04:06 +0800 Subject: [PATCH] update --- run.py | 242 ++++++++++++++++++++++++++++---------------------------- uv.lock | 42 +++++++++- 2 files changed, 161 insertions(+), 123 deletions(-) diff --git a/run.py b/run.py index d27de90..0973472 100644 --- a/run.py +++ b/run.py @@ -364,139 +364,139 @@ def process_accounts(accounts: list, team_name: str, team_index: int = 0, if is_team_owner_otp: # 旧格式 Team Owner: 使用 OTP 登录授权 log.info("Team Owner 账号 (旧格式),使用一次性验证码登录...", icon="auth") - progress_update(step="OTP Login...") - auth_success, codex_data = login_and_authorize_with_otp(email) - register_success = auth_success - elif need_crs_only: - # 已授权但未入库: 跳过授权,直接尝试入库 - log.info(f"已授权账号 (状态: {account_status}),跳过授权,直接入库...", icon="auth") - progress_update(step="Adding to CRS...") - register_success = True - codex_data = None # CPA/S2A 模式不需要 codex_data - # CRS 模式下,由于没有 codex_data,无法入库,需要重新授权 - if AUTH_PROVIDER not in ("cpa", "s2a"): - log.warning("CRS 模式下已授权账号缺少 codex_data,需要重新授权") - auth_success, codex_data = authorize_only(email, password) + progress_update(step="OTP Login...") + auth_success, codex_data = login_and_authorize_with_otp(email) register_success = auth_success - elif need_auth_only: - # 已注册账号 (包括新格式 Owner): 使用密码登录授权 - log.info(f"已注册账号 (状态: {account_status}, 角色: {account_role}),使用密码登录授权...", icon="auth") - progress_update(step="Authorizing...") - auth_success, codex_data = authorize_only(email, password) - register_success = True - else: - # 新账号: 注册 + Codex 授权 - progress_update(step="Registering...") - register_success, codex_data = register_and_authorize(email, password) - - # 检查是否是域名黑名单错误 - if register_success == "domain_blacklisted": - domain = get_domain_from_email(email) - log.error(f"域名 {domain} 不被支持,加入黑名单") - add_domain_to_blacklist(domain) - - # 从 tracker 中移除 - remove_account_from_tracker(_tracker, team_name, email) - save_team_tracker(_tracker) - - # 尝试创建新邮箱替代 - log.info("尝试创建新邮箱替代...") - new_email, new_password = unified_create_email() - if new_email and not is_email_blacklisted(new_email): - # 邀请新邮箱 - if invite_single_to_team(new_email, _get_team_by_name(team_name)): - add_account_with_password(_tracker, team_name, new_email, new_password, "invited") - save_team_tracker(_tracker) - log.success(f"已创建新邮箱: {new_email},将在下次运行时处理") - else: - log.error("新邮箱邀请失败") - else: - log.error("无法创建有效的新邮箱") - - continue # 跳过当前账号,继续下一个 - - if register_success and register_success != "domain_blacklisted": - update_account_status(_tracker, team_name, email, "registered") - save_team_tracker(_tracker) - - # CPA 模式: codex_data 为 None,授权成功后直接标记完成 - # CRS 模式: 需要 codex_data,手动添加到 CRS - if AUTH_PROVIDER == "s2a": - # S2A 模式: 授权成功后验证账号是否入库 - from s2a_service import s2a_verify_account_in_pool - - update_account_status(_tracker, team_name, email, "authorized") - save_team_tracker(_tracker) - - # 验证账号是否成功入库 - log.step("正在验证 S2A 账号入库状态...") - progress_update(step="验证入库...") - verified, account_data = s2a_verify_account_in_pool(email) - - if verified: - account_id = account_data.get("id", "") - account_name = account_data.get("name", "") - result["status"] = "success" - result["crs_id"] = f"S2A-{account_id}" - - update_account_status(_tracker, team_name, email, "completed") - save_team_tracker(_tracker) - - log.success(f"✅ S2A 账号入库成功 (ID: {account_id}, 名称: {account_name})") - else: - log.warning("⚠️ S2A 授权成功但入库验证失败") - result["status"] = "partial" - update_account_status(_tracker, team_name, email, "partial") - save_team_tracker(_tracker) - - elif AUTH_PROVIDER == "cpa": - # CPA 模式: 授权成功即完成 (后台自动处理账号) - update_account_status(_tracker, team_name, email, "authorized") - save_team_tracker(_tracker) - - result["status"] = "success" - result["crs_id"] = "CPA-AUTO" - - update_account_status(_tracker, team_name, email, "completed") - save_team_tracker(_tracker) - - log.success(f"✅ CPA 账号处理完成: {email}") + elif need_crs_only: + # 已授权但未入库: 跳过授权,直接尝试入库 + log.info(f"已授权账号 (状态: {account_status}),跳过授权,直接入库...", icon="auth") + progress_update(step="Adding to CRS...") + register_success = True + codex_data = None # CPA/S2A 模式不需要 codex_data + # CRS 模式下,由于没有 codex_data,无法入库,需要重新授权 + if AUTH_PROVIDER not in ("cpa", "s2a"): + log.warning("CRS 模式下已授权账号缺少 codex_data,需要重新授权") + auth_success, codex_data = authorize_only(email, password) + register_success = auth_success + elif need_auth_only: + # 已注册账号 (包括新格式 Owner): 使用密码登录授权 + log.info(f"已注册账号 (状态: {account_status}, 角色: {account_role}),使用密码登录授权...", icon="auth") + progress_update(step="Authorizing...") + auth_success, codex_data = authorize_only(email, password) + register_success = True else: - # CRS 模式: 原有逻辑 - if codex_data: + # 新账号: 注册 + Codex 授权 + progress_update(step="Registering...") + register_success, codex_data = register_and_authorize(email, password) + + # 检查是否是域名黑名单错误 + if register_success == "domain_blacklisted": + domain = get_domain_from_email(email) + log.error(f"域名 {domain} 不被支持,加入黑名单") + add_domain_to_blacklist(domain) + + # 从 tracker 中移除 + remove_account_from_tracker(_tracker, team_name, email) + save_team_tracker(_tracker) + + # 尝试创建新邮箱替代 + log.info("尝试创建新邮箱替代...") + new_email, new_password = unified_create_email() + if new_email and not is_email_blacklisted(new_email): + # 邀请新邮箱 + if invite_single_to_team(new_email, _get_team_by_name(team_name)): + add_account_with_password(_tracker, team_name, new_email, new_password, "invited") + save_team_tracker(_tracker) + log.success(f"已创建新邮箱: {new_email},将在下次运行时处理") + else: + log.error("新邮箱邀请失败") + else: + log.error("无法创建有效的新邮箱") + + continue # 跳过当前账号,继续下一个 + + if register_success and register_success != "domain_blacklisted": + update_account_status(_tracker, team_name, email, "registered") + save_team_tracker(_tracker) + + # CPA 模式: codex_data 为 None,授权成功后直接标记完成 + # CRS 模式: 需要 codex_data,手动添加到 CRS + if AUTH_PROVIDER == "s2a": + # S2A 模式: 授权成功后验证账号是否入库 + from s2a_service import s2a_verify_account_in_pool + update_account_status(_tracker, team_name, email, "authorized") save_team_tracker(_tracker) - - # 添加到 CRS - log.step("添加到 CRS...") - crs_result = crs_add_account(email, codex_data) - - if crs_result: - crs_id = crs_result.get("id", "") + + # 验证账号是否成功入库 + log.step("正在验证 S2A 账号入库状态...") + progress_update(step="验证入库...") + verified, account_data = s2a_verify_account_in_pool(email) + + if verified: + account_id = account_data.get("id", "") + account_name = account_data.get("name", "") result["status"] = "success" - result["crs_id"] = crs_id - + result["crs_id"] = f"S2A-{account_id}" + update_account_status(_tracker, team_name, email, "completed") save_team_tracker(_tracker) - - log.success(f"账号处理完成: {email}") + + log.success(f"✅ S2A 账号入库成功 (ID: {account_id}, 名称: {account_name})") else: - log.warning("CRS 入库失败,但注册和授权成功") + log.warning("⚠️ S2A 授权成功但入库验证失败") result["status"] = "partial" update_account_status(_tracker, team_name, email, "partial") save_team_tracker(_tracker) - else: - log.warning("Codex 授权失败") - result["status"] = "auth_failed" - update_account_status(_tracker, team_name, email, "auth_failed") + + elif AUTH_PROVIDER == "cpa": + # CPA 模式: 授权成功即完成 (后台自动处理账号) + update_account_status(_tracker, team_name, email, "authorized") save_team_tracker(_tracker) - elif register_success != "domain_blacklisted": - if is_team_owner_otp: - log.error(f"OTP 登录授权失败: {email}") - else: - log.error(f"注册/授权失败: {email}") - update_account_status(_tracker, team_name, email, "register_failed") - save_team_tracker(_tracker) + + result["status"] = "success" + result["crs_id"] = "CPA-AUTO" + + update_account_status(_tracker, team_name, email, "completed") + save_team_tracker(_tracker) + + log.success(f"✅ CPA 账号处理完成: {email}") + else: + # CRS 模式: 原有逻辑 + if codex_data: + update_account_status(_tracker, team_name, email, "authorized") + save_team_tracker(_tracker) + + # 添加到 CRS + log.step("添加到 CRS...") + crs_result = crs_add_account(email, codex_data) + + if crs_result: + crs_id = crs_result.get("id", "") + result["status"] = "success" + result["crs_id"] = crs_id + + update_account_status(_tracker, team_name, email, "completed") + save_team_tracker(_tracker) + + log.success(f"账号处理完成: {email}") + else: + log.warning("CRS 入库失败,但注册和授权成功") + result["status"] = "partial" + update_account_status(_tracker, team_name, email, "partial") + save_team_tracker(_tracker) + else: + log.warning("Codex 授权失败") + result["status"] = "auth_failed" + update_account_status(_tracker, team_name, email, "auth_failed") + save_team_tracker(_tracker) + elif register_success != "domain_blacklisted": + if is_team_owner_otp: + log.error(f"OTP 登录授权失败: {email}") + else: + log.error(f"注册/授权失败: {email}") + update_account_status(_tracker, team_name, email, "register_failed") + save_team_tracker(_tracker) except ShutdownRequested: # 用户请求停止,保存当前状态并退出 diff --git a/uv.lock b/uv.lock index 6fd647e..4e3c5cf 100644 --- a/uv.lock +++ b/uv.lock @@ -15,6 +15,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "apscheduler" +version = "3.11.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzlocal" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/12/3e4389e5920b4c1763390c6d371162f3784f86f85cd6d6c1bfe68eef14e2/apscheduler-3.11.2.tar.gz", hash = "sha256:2a9966b052ec805f020c8c4c3ae6e6a06e24b1bf19f2e11d91d8cca0473eef41", size = 108683, upload-time = "2025-12-22T00:39:34.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/64/2e54428beba8d9992aa478bb8f6de9e4ecaa5f8f513bcfd567ed7fb0262d/apscheduler-3.11.2-py3-none-any.whl", hash = "sha256:ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d", size = 64439, upload-time = "2025-12-22T00:39:33.303Z" }, +] + [[package]] name = "certifi" version = "2025.11.12" @@ -326,7 +338,7 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "drissionpage" }, - { name = "python-telegram-bot" }, + { name = "python-telegram-bot", extra = ["job-queue"] }, { name = "requests" }, { name = "rich" }, { name = "setuptools" }, @@ -337,7 +349,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "drissionpage", specifier = ">=4.1.1.2" }, - { name = "python-telegram-bot", specifier = ">=22.5" }, + { name = "python-telegram-bot", extras = ["job-queue"], specifier = ">=22.5" }, { name = "requests", specifier = ">=2.32.5" }, { name = "rich", specifier = ">=14.2.0" }, { name = "setuptools", specifier = ">=80.9.0" }, @@ -404,6 +416,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bc/c3/340c7520095a8c79455fcf699cbb207225e5b36490d2b9ee557c16a7b21b/python_telegram_bot-22.5-py3-none-any.whl", hash = "sha256:4b7cd365344a7dce54312cc4520d7fa898b44d1a0e5f8c74b5bd9b540d035d16", size = 730976, upload-time = "2025-09-27T13:50:25.93Z" }, ] +[package.optional-dependencies] +job-queue = [ + { name = "apscheduler" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -527,6 +544,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + [[package]] name = "urllib3" version = "2.6.2"