虎牙自动注册持久化成功流水与批次,支持失败续跑与随时导出

将注册批次/条目/成功记录落库,成功一个写入一条流水;服务中断可恢复并续跑失败项,换电脑也能导出 txt。同时修复 pending 被误判为运行中导致页面卡住的问题。
This commit is contained in:
yml2213
2026-07-12 20:05:04 +08:00
parent c3044dbf69
commit e18b2c6e0c
9 changed files with 1423 additions and 96 deletions
+121 -7
View File
@@ -32,6 +32,7 @@ from ..schemas import (
HuyaAccountOut,
HuyaAutoRegisterBatchOut,
HuyaAutoRegisterRequest,
HuyaAutoRegisterRetryRequest,
HuyaConfigOut,
HuyaConfigUpdate,
HuyaCookieImport,
@@ -40,6 +41,7 @@ from ..schemas import (
HuyaPasswordLoginRequest,
HuyaPasswordLoginSelectedRequest,
HuyaRechargeGoodsOut,
HuyaRegisterSuccessLogOut,
HuyaSmsCodeRequest,
HuyaSmsLoginRequest,
HuyaTaskBatchRequest,
@@ -58,7 +60,11 @@ from ..services.huya_service import (
upsert_huya_cookie,
)
from ..services.huya_runner import HuyaBatchRunner, huya_batch_registry
from ..services.huya_register_runner import huya_register_registry
from ..services.huya_register_runner import (
export_success_logs_text,
huya_register_registry,
list_success_logs,
)
router = APIRouter(prefix="/api/huya", tags=["虎牙"])
@@ -366,22 +372,33 @@ def create_auto_register_batch(
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")
runner = huya_register_registry.get(batch_id)
if not runner:
raise HTTPException(status_code=404, detail="批次不存在或服务已重启")
return runner.snapshot()
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")
@@ -393,11 +410,108 @@ def stop_auto_register_batch(
_require_huya_perm(current, "huya:import")
runner = huya_register_registry.get(batch_id)
if not runner:
raise HTTPException(status_code=404, detail="批次不存在或服务已重启")
# 无内存 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 = HuyaAutoRegisterRetryRequest(),
db: Session = Depends(get_db),
current: User = Depends(get_current_user),
):
"""从失败/停止/未完成条目续跑,成功项跳过。"""
_require_huya_perm(current, "huya:import")
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,
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}"},
)
@router.post("/accounts/password-login/selected")
def password_login_selected_accounts(
req: HuyaPasswordLoginSelectedRequest,