"""登录工作线程模块""" import re import threading import time from queue import Queue from typing import Optional from loguru import logger from douyu import DouyuLogin from douyu.config import Account, ProxyConfig from douyu.email_verifier import get_email_config_for_account EMAIL_PATTERN = re.compile(r'^[^\s@|]+@[^\s@|]+\.[^\s@|]+$') def get_imap_server(email: str) -> str: """从邮箱地址推导IMAP服务器""" return get_email_config_for_account(email)['server'] def _is_ascii(value: str) -> bool: """检查字符串是否为ASCII。""" try: value.encode('ascii') return True except UnicodeEncodeError: return False def parse_accounts_text(text: str) -> list[Account]: """ 解析账号文本 格式:用户名|密码|邮箱|邮箱密码 Returns: Account列表 """ accounts = [] for line_num, line in enumerate(text.strip().split('\n'), 1): line = line.strip() if not line or line.startswith('#'): continue parts = line.split('|') if len(parts) != 4: logger.warning(f"第{line_num}行格式错误,需要4个字段,实际{len(parts)}个: {line}") continue username, password, email, email_password = parts[0].strip(), parts[1].strip(), parts[2].strip(), parts[3].strip() if not all([username, password, email, email_password]): logger.warning(f"第{line_num}行存在空字段: {line}") continue if not EMAIL_PATTERN.match(email) or not _is_ascii(email): logger.warning( f"第{line_num}行邮箱格式不正确: {email}," "请确认格式为:用户名|密码|邮箱|邮箱密码" ) continue if not _is_ascii(email_password): logger.warning(f"第{line_num}行邮箱密码/授权码包含非ASCII字符,IMAP可能无法登录") continue accounts.append(Account( username=username, password=password, email=email, email_password=email_password, email_imap_server=get_imap_server(email), email_imap_port=993, )) return accounts class LoginWorker(threading.Thread): """登录工作线程""" def __init__( self, account: Account, index: int, result_queue: Queue, log_queue: Queue, proxy_config: Optional[ProxyConfig] = None, max_geetest_retries: int = 5, ): super().__init__(daemon=True) self.account = account self.index = index self.result_queue = result_queue self.log_queue = log_queue self.proxy_config = proxy_config self.max_geetest_retries = max_geetest_retries self._stop_event = threading.Event() def stop(self): """停止线程""" self._stop_event.set() def run(self): """执行登录""" username = self.account.username try: # 发送日志 self.log_queue.put(('info', f'[{self.index + 1}] 开始登录: {username}')) # 配置代理 proxy_url = None proxy_api_url = None if self.proxy_config and self.proxy_config.enabled: if self.proxy_config.api_url: proxy_api_url = self.proxy_config.api_url elif self.proxy_config.http or self.proxy_config.https: proxy_url = { 'http': self.proxy_config.http or self.proxy_config.https, 'https': self.proxy_config.https or self.proxy_config.http, } # 创建登录器 loginer = DouyuLogin( self.account, proxy=proxy_url, proxy_api_url=proxy_api_url, max_geetest_retries=self.max_geetest_retries, ) # 执行登录 result = loginer.login() if result.success: self.log_queue.put(('success', f'[{self.index + 1}] {username} 登录成功')) self.result_queue.put({ 'index': self.index, 'username': username, 'email': self.account.email, 'status': 'success', 'cookie': result.cookie, 'message': '登录成功', }) else: self.log_queue.put(('error', f'[{self.index + 1}] {username} 登录失败: {result.message}')) self.result_queue.put({ 'index': self.index, 'username': username, 'email': self.account.email, 'status': 'failed', 'cookie': '', 'message': result.message, }) except Exception as e: error_msg = str(e) self.log_queue.put(('error', f'[{self.index + 1}] {username} 登录异常: {error_msg}')) self.result_queue.put({ 'index': self.index, 'username': username, 'email': self.account.email, 'status': 'error', 'cookie': '', 'message': error_msg, })