import json import threading from datetime import datetime import pytz import config import api_client accounts_data = {} data_lock = threading.Lock() shanghai_tz = pytz.timezone(config.SHANGHAI_TZ_STR) def parse_accounts(): global accounts_data if not config.ACCOUNTS_JSON: print("错误: ACCOUNTS 环境变量未设置。") return False try: accounts_list = json.loads(config.ACCOUNTS_JSON) if not isinstance(accounts_list, list): print("错误: ACCOUNTS 环境变量必须是一个 JSON 数组。") return False temp_accounts_data = {} for acc in accounts_list: if isinstance(acc, dict) and "email" in acc and "password" in acc: temp_accounts_data[acc["email"]] = { "password": acc["password"], "token": None, "profile": None, "last_login_success": None, "last_profile_success": None, "last_login_attempt": None, "last_profile_attempt": None, "login_error": None, "profile_error": None, "cards_info": None, "last_card_info_success": None, "last_card_info_attempt": None, "card_info_error": None, } else: print(f"警告: ACCOUNTS 中的条目格式不正确: {acc}") with data_lock: accounts_data = temp_accounts_data print(f"成功加载 {len(accounts_data)} 个账户。") return True except json.JSONDecodeError: print("错误: ACCOUNTS 环境变量不是有效的 JSON 格式。") return False def login_and_store_token(email): global accounts_data with data_lock: account_info = accounts_data.get(email) if not account_info: print(f"错误: 账户 {email} 未找到。") return password = account_info["password"] print(f"[{datetime.now(shanghai_tz)}] 尝试为账户 {email} 登录...") token, error = api_client.api_login(email, password) with data_lock: accounts_data[email]["last_login_attempt"] = datetime.now(shanghai_tz) if token: accounts_data[email]["token"] = token accounts_data[email]["last_login_success"] = True accounts_data[email]["login_error"] = None print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 登录成功。") else: accounts_data[email]["token"] = None accounts_data[email]["last_login_success"] = False accounts_data[email]["login_error"] = error print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 登录失败: {error}") def fetch_and_store_profile(email): global accounts_data with data_lock: account_info = accounts_data.get(email) if not account_info: print(f"错误: 账户 {email} 未找到 (fetch_and_store_profile)。") return token = account_info.get("token") if not token: print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 没有有效的 token,跳过获取 Profile。") with data_lock: accounts_data[email]["last_profile_attempt"] = datetime.now(shanghai_tz) accounts_data[email]["last_profile_success"] = False accounts_data[email]["profile_error"] = "无有效 Token" accounts_data[email]["profile"] = None accounts_data[email]["last_card_info_attempt"] = datetime.now(shanghai_tz) accounts_data[email]["cards_info"] = None accounts_data[email]["last_card_info_success"] = False accounts_data[email]["card_info_error"] = "因 Token 为空未尝试" return print(f"[{datetime.now(shanghai_tz)}] 尝试为账户 {email} 获取 Profile...") profile, error = api_client.get_api_profile(email, token) profile_fetch_successful_this_attempt = False with data_lock: accounts_data[email]["last_profile_attempt"] = datetime.now(shanghai_tz) if profile: accounts_data[email]["profile"] = profile accounts_data[email]["last_profile_success"] = True accounts_data[email]["profile_error"] = None profile_fetch_successful_this_attempt = True print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 获取 Profile 成功。") else: accounts_data[email]["profile"] = None accounts_data[email]["last_profile_success"] = False accounts_data[email]["profile_error"] = error print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 获取 Profile 失败: {error}") if error and ("token" in error.lower() or "auth" in error.lower() or "登录" in error.lower()): print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 获取 Profile 失败,疑似 Token 失效,将尝试重新登录。") accounts_data[email]["token"] = None accounts_data[email]["last_card_info_attempt"] = datetime.now(shanghai_tz) accounts_data[email]["cards_info"] = None accounts_data[email]["last_card_info_success"] = False accounts_data[email]["card_info_error"] = "因 Profile 获取失败未尝试" return if profile_fetch_successful_this_attempt: current_token_for_cards = None with data_lock: if email in accounts_data: current_token_for_cards = accounts_data[email].get("token") else: print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 在获取卡片信息前数据结构异常,跳过。") return if not current_token_for_cards: print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 在获取卡片信息前发现 Token 已失效或被清除,跳过。") with data_lock: if email in accounts_data: accounts_data[email]["last_card_info_attempt"] = datetime.now(shanghai_tz) accounts_data[email]["cards_info"] = None accounts_data[email]["last_card_info_success"] = False accounts_data[email]["card_info_error"] = "因 Token 失效未尝试" return print(f"[{datetime.now(shanghai_tz)}] Profile 获取成功,继续为账户 {email} 获取卡片信息...") cards_info, card_error = api_client.get_api_card_info(email, current_token_for_cards) with data_lock: if email in accounts_data: accounts_data[email]["last_card_info_attempt"] = datetime.now(shanghai_tz) if cards_info: accounts_data[email]["cards_info"] = cards_info accounts_data[email]["last_card_info_success"] = True accounts_data[email]["card_info_error"] = None print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 获取卡片信息成功。") elif card_error: accounts_data[email]["cards_info"] = None accounts_data[email]["last_card_info_success"] = False accounts_data[email]["card_info_error"] = card_error print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 获取卡片信息失败: {card_error}") else: # No error, but no card_info (e.g. no cards for the account) accounts_data[email]["cards_info"] = None accounts_data[email]["last_card_info_success"] = True # Success in fetching, just no data accounts_data[email]["card_info_error"] = None print(f"[{datetime.now(shanghai_tz)}] 账户 {email} 获取卡片信息成功,但无卡片数据。") def get_accounts_data_for_display(): with data_lock: display_data = {} for email, data in accounts_data.items(): display_data[email] = { "profile": data.get("profile"), "last_login_success": data.get("last_login_success"), "last_profile_success": data.get("last_profile_success"), "last_login_attempt": data.get("last_login_attempt").isoformat() if data.get("last_login_attempt") else None, "last_profile_attempt": data.get("last_profile_attempt").isoformat() if data.get("last_profile_attempt") else None, "login_error": data.get("login_error"), "profile_error": data.get("profile_error"), "token_present": bool(data.get("token")), "cards_info": data.get("cards_info"), "last_card_info_success": data.get("last_card_info_success"), "last_card_info_attempt": data.get("last_card_info_attempt").isoformat() if data.get("last_card_info_attempt") else None, "card_info_error": data.get("card_info_error") } return display_data def get_all_account_emails(): with data_lock: return list(accounts_data.keys()) def get_accounts_from_config(): if not config.ACCOUNTS_JSON: print("错误: ACCOUNTS 环境变量未设置 (get_accounts_from_config)。") return [] try: accounts_list = json.loads(config.ACCOUNTS_JSON) if not isinstance(accounts_list, list): print("错误: ACCOUNTS 环境变量必须是一个 JSON 数组 (get_accounts_from_config)。") return [] valid_accounts = [] for acc in accounts_list: if isinstance(acc, dict) and "email" in acc and "password" in acc: valid_accounts.append({"email": acc["email"], "password": acc["password"]}) else: print(f"警告: ACCOUNTS 中的条目格式不正确,已跳过: {acc} (get_accounts_from_config)") return valid_accounts except json.JSONDecodeError: print("错误: ACCOUNTS 环境变量不是有效的 JSON 格式 (get_accounts_from_config)。") return []