Files
live-hub-py/web/backend/routers/huya/register.py
T
yml2213 a3c3a46b9c fix(tooling): 修复 pyright 解释器配置与类型守卫,补齐 ruff 门禁与两处历史 bug
- pyrightconfig.json 钉死 Python 3.12 虚拟环境,消除由于查找系统 Python 3.9 带来的假性报错
- 修复 huya/login.py 引用不存在函数的问题并补充单元测试
- 修复 browser_harvest.py 对 set 下标访问的错误并提升报错信息质量
- 虎牙 6 个子路由显式导入依赖,消除 import * 带来的未定义变量报警
- 规范化 Pydantic Field(default=...) 默认值声明
- 完善 solver.py / app_login.py 等核心路径类型守卫与 @overload 重载
- 在 pyproject.toml 中显式锁定 ruff lint 规则集 (E4, E7, E9, F, B, I, BLE)
- 门禁脚本同步增加 ruff check 检查并在 AGENTS.md 补齐实践经验总结
2026-10-08 12:33:39 +08:00

205 lines
7.1 KiB
Python

"""虎牙自动注册批次与成功流水。"""
from fastapi import APIRouter
from ._common import (
Depends,
HTTPException,
HuyaAutoRegisterBatchOut,
HuyaAutoRegisterRequest,
HuyaAutoRegisterRetryRequest,
HuyaRegisterSuccessLogOut,
ProxyConfig,
Query,
Session,
StreamingResponse,
User,
_require_huya_perm,
export_success_logs_text,
get_current_user,
get_db,
huya_register_registry,
list_success_logs,
parse_sms_lines,
threading,
)
router = APIRouter()
@router.post("/register/batches", response_model=HuyaAutoRegisterBatchOut)
def create_auto_register_batch(
req: HuyaAutoRegisterRequest,
db: Session = Depends(get_db),
current: User = Depends(get_current_user),
):
"""启动虎牙手机号自动注册批次。"""
_require_huya_perm(current, "huya:import")
sms_lines = parse_sms_lines(req.text)
if not sms_lines:
raise HTTPException(
status_code=400,
detail="没有识别到有效手机号,格式为:手机号----短信查询URL 或 虎牙号----密码----手机号----短信查询URL",
)
proxy_config = db.query(ProxyConfig).first() if req.use_proxy else None
runner = huya_register_registry.create(
sms_lines=sms_lines,
tag=req.tag.strip(),
created_by=current.id,
concurrency=req.concurrency,
wait_seconds=req.wait_seconds,
poll_interval=req.poll_interval,
password_prefix=req.password_prefix,
fixed_password=req.fixed_password,
use_proxy=req.use_proxy,
proxy_config=proxy_config,
)
runner.mark_running("批次运行中")
thread = threading.Thread(target=runner.run, daemon=True)
thread.start()
return runner.snapshot()
@router.get("/register/batches", response_model=list[HuyaAutoRegisterBatchOut])
def list_auto_register_batches(
limit: int = Query(50, ge=1, le=200),
current: User = Depends(get_current_user),
):
"""列出历史自动注册批次(摘要,不含明细)。"""
_require_huya_perm(current, "huya:import")
return huya_register_registry.list_summaries(limit=limit)
@router.get("/register/batches/{batch_id}", response_model=HuyaAutoRegisterBatchOut)
def get_auto_register_batch(
batch_id: str,
current: User = Depends(get_current_user),
):
"""查询虎牙手机号自动注册批次状态(优先内存,否则读库)。"""
_require_huya_perm(current, "huya:import")
snapshot = huya_register_registry.get_snapshot(batch_id)
if not snapshot:
raise HTTPException(status_code=404, detail="批次不存在")
return snapshot
@router.post("/register/batches/{batch_id}/stop")
def stop_auto_register_batch(
batch_id: str,
current: User = Depends(get_current_user),
):
"""停止虎牙手机号自动注册批次。"""
_require_huya_perm(current, "huya:import")
runner = huya_register_registry.get(batch_id)
if not runner:
# 无内存 runner:若 DB 中存在且处于 running/interrupted,标记停止
snapshot = huya_register_registry.get_snapshot(batch_id)
if not snapshot:
raise HTTPException(status_code=404, detail="批次不存在")
return {"message": "批次未在本进程运行,无需停止", "success": True}
runner.stop()
return {"message": "已发送停止信号", "success": True}
@router.post(
"/register/batches/{batch_id}/retry", response_model=HuyaAutoRegisterBatchOut
)
def retry_auto_register_batch(
batch_id: str,
req: HuyaAutoRegisterRetryRequest | None = None,
db: Session = Depends(get_db),
current: User = Depends(get_current_user),
):
"""继续批次:默认从停止处往下跑(跳过成功与已失败);可传 mode 改行为。"""
_require_huya_perm(current, "huya:import")
if req is None:
req = HuyaAutoRegisterRetryRequest.model_construct()
use_proxy = req.use_proxy
# 先看历史批次是否用过代理
snapshot = huya_register_registry.get_snapshot(batch_id)
if not snapshot:
raise HTTPException(status_code=404, detail="批次不存在")
effective_proxy = (
snapshot.get("use_proxy", False) if use_proxy is None else bool(use_proxy)
)
proxy_config = db.query(ProxyConfig).first() if effective_proxy else None
try:
runner = huya_register_registry.retry(
batch_id,
proxy_config=proxy_config,
mode=req.mode,
concurrency=req.concurrency,
wait_seconds=req.wait_seconds,
poll_interval=req.poll_interval,
password_prefix=req.password_prefix,
fixed_password=req.fixed_password,
use_proxy=use_proxy,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except RuntimeError as exc:
raise HTTPException(status_code=409, detail=str(exc)) from exc
thread = threading.Thread(target=runner.run, daemon=True)
thread.start()
return runner.snapshot()
@router.get("/register/batches/{batch_id}/export")
def export_auto_register_batch_success(
batch_id: str,
current: User = Depends(get_current_user),
):
"""导出指定批次的成功账号 txt。"""
_require_huya_perm(current, "huya:import")
snapshot = huya_register_registry.get_snapshot(batch_id)
if not snapshot:
raise HTTPException(status_code=404, detail="批次不存在")
content = export_success_logs_text(batch_id=batch_id)
if not content.strip():
raise HTTPException(status_code=404, detail="该批次没有可导出的成功记录")
return StreamingResponse(
iter([content]),
media_type="text/plain; charset=utf-8",
headers={
"Content-Disposition": f"attachment; filename=huya-register-{batch_id}.txt"
},
)
@router.get("/register/success-logs", response_model=list[HuyaRegisterSuccessLogOut])
def list_register_success_logs(
batch_id: str | None = Query(None),
tag: str | None = Query(None),
limit: int = Query(200, ge=1, le=2000),
current: User = Depends(get_current_user),
):
"""列出注册成功流水(换电脑也可查看)。"""
_require_huya_perm(current, "huya:import")
return list_success_logs(batch_id=batch_id, tag=tag, limit=limit)
@router.get("/register/success-logs/export")
def export_register_success_logs(
batch_id: str | None = Query(None),
tag: str | None = Query(None),
limit: int = Query(5000, ge=1, le=20000),
current: User = Depends(get_current_user),
):
"""导出注册成功流水 txt:账号----密码----手机号----接码链接。"""
_require_huya_perm(current, "huya:import")
content = export_success_logs_text(batch_id=batch_id, tag=tag, limit=limit)
if not content.strip():
raise HTTPException(status_code=404, detail="没有可导出的成功记录")
filename = "huya-register-success"
if batch_id:
filename += f"-{batch_id}"
if tag:
filename += f"-{tag}"
filename += ".txt"
return StreamingResponse(
iter([content]),
media_type="text/plain; charset=utf-8",
headers={"Content-Disposition": f"attachment; filename={filename}"},
)