171 lines
5.2 KiB
Python
171 lines
5.2 KiB
Python
"""登录工作线程模块"""
|
||
|
||
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,
|
||
})
|