Files
live-hub-py/core/huya/auto_register.py
T

298 lines
10 KiB
Python

"""虎牙手机号自动注册流程。"""
from __future__ import annotations
import threading
import time
from dataclasses import dataclass
from datetime import datetime
from core.sms_provider import SmsLine, SmsProviderClient
from .change_password import change_huya_password_with_sms_line, generate_huya_password
from .cookie_utils import cookie_value
from .login import HuyaLoginError
from .sms_login import login_huya_sms, normalize_huya_phone, send_huya_sms_code
@dataclass
class HuyaAutoRegisterResult:
"""单个手机号自动注册结果。"""
phone: str
provider: str
success: bool
status: str
message: str
cookie: str = ""
code: str = ""
change_code: str = ""
sdid: str = ""
normalized_phone: str = ""
username: str = ""
uid: str = ""
password: str = ""
sms_url: str = ""
attempts: int = 0
change_attempts: int = 0
password_changed: bool = False
def _sleep_or_stop(stop_event: threading.Event | None, seconds: float) -> bool:
"""等待一小段时间;返回 False 表示收到停止信号。"""
if seconds <= 0:
return not (stop_event and stop_event.is_set())
if stop_event:
return not stop_event.wait(seconds)
time.sleep(seconds)
return True
def register_huya_with_sms_line(
item: SmsLine,
wait_seconds: float = 180,
poll_interval: float = 5,
change_password: bool = True,
password_prefix: str = "hy",
fixed_password: str = "",
stop_event: threading.Event | None = None,
) -> HuyaAutoRegisterResult:
"""使用固定手机号和接码地址完成虎牙短信注册/登录。"""
phone = item.phone.strip()
normalized_phone = normalize_huya_phone(phone)
wait_seconds = max(15.0, float(wait_seconds or 180))
poll_interval = max(1.0, float(poll_interval or 5))
if stop_event and stop_event.is_set():
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="stopped",
message="已停止",
normalized_phone=normalized_phone,
sms_url=item.url,
)
sent_at = datetime.now()
try:
code_result = send_huya_sms_code(phone=phone)
except HuyaLoginError as exc:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=str(exc),
normalized_phone=normalized_phone,
sms_url=item.url,
)
except Exception as exc:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=f"发送虎牙短信失败: {exc}",
normalized_phone=normalized_phone,
sms_url=item.url,
)
if not code_result.success or not code_result.state:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=code_result.message or "发送虎牙短信失败",
sdid=code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
)
client = SmsProviderClient()
deadline = time.monotonic() + wait_seconds
attempts = 0
last_message = "等待验证码"
while time.monotonic() < deadline:
if stop_event and stop_event.is_set():
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="stopped",
message="已停止",
sdid=code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
attempts=attempts,
)
attempts += 1
poll_result = client.poll(item, after_time=sent_at)
last_message = poll_result.message or last_message
if poll_result.has_code:
try:
login_result = login_huya_sms(
authcode=poll_result.code,
state=code_result.state,
phone=phone,
)
except HuyaLoginError as exc:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=str(exc),
code=poll_result.code,
sdid=code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
attempts=attempts,
)
except Exception as exc:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=f"提交虎牙短信登录失败: {exc}",
code=poll_result.code,
sdid=code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
attempts=attempts,
)
if login_result.success and login_result.cookie:
cookie = login_result.cookie
uid = cookie_value(cookie, "udb_uid") or cookie_value(cookie, "yyuid")
username = cookie_value(cookie, "udb_passport") or cookie_value(cookie, "username") or uid
if not change_password:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=True,
status="success",
message="注册/登录成功",
cookie=cookie,
code=poll_result.code,
sdid=login_result.sdid or code_result.sdid,
normalized_phone=normalized_phone,
username=username,
uid=uid,
sms_url=item.url,
attempts=attempts,
)
if not uid:
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message="注册成功但 Cookie 中没有识别到虎牙 uid,无法改密",
cookie=cookie,
code=poll_result.code,
sdid=login_result.sdid or code_result.sdid,
normalized_phone=normalized_phone,
username=username,
uid=uid,
sms_url=item.url,
attempts=attempts,
)
password = fixed_password.strip() or generate_huya_password(password_prefix)
change_result = change_huya_password_with_sms_line(
uid=uid,
cookie=cookie,
password=password,
item=item,
wait_seconds=wait_seconds,
poll_interval=poll_interval,
ignore_codes={poll_result.code},
stop_event=stop_event,
)
if not change_result.success:
failed_status = "stopped" if change_result.message == "已停止" else "error"
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status=failed_status,
message=f"注册成功但改密失败: {change_result.message}",
cookie=cookie,
code=poll_result.code,
change_code=change_result.code,
sdid=change_result.sdid or login_result.sdid or code_result.sdid,
normalized_phone=normalized_phone,
username=username,
uid=uid,
password=password,
sms_url=item.url,
attempts=attempts,
change_attempts=change_result.attempts,
)
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=True,
status="success",
message="注册并改密成功",
cookie=cookie,
code=poll_result.code,
change_code=change_result.code,
sdid=login_result.sdid or code_result.sdid,
normalized_phone=normalized_phone,
username=username,
uid=uid,
password=password,
sms_url=item.url,
attempts=attempts,
change_attempts=change_result.attempts,
password_changed=True,
)
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=login_result.message or "虎牙短信登录失败",
code=poll_result.code,
sdid=login_result.sdid or code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
attempts=attempts,
)
remaining = deadline - time.monotonic()
if remaining <= 0:
break
if not _sleep_or_stop(stop_event, min(poll_interval, remaining)):
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="stopped",
message="已停止",
sdid=code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
attempts=attempts,
)
return HuyaAutoRegisterResult(
phone=phone,
provider=item.provider,
success=False,
status="error",
message=f"等待验证码超时: {last_message}",
sdid=code_result.sdid,
normalized_phone=normalized_phone,
sms_url=item.url,
attempts=attempts,
)