默认同时只登一个号,失败两次跳下一个,号间留间隔,结束后可一键重试失败账号。 顺带拆分虎牙路由与斗鱼工作台页面,并补齐 raw_cookie 重建入口。 Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
3.5 KiB
Python
88 lines
3.5 KiB
Python
"""虎牙设备绑定:画像与指纹状态解绑。"""
|
||
|
||
from fastapi import APIRouter
|
||
|
||
from ._common import *
|
||
|
||
router = APIRouter()
|
||
|
||
|
||
@router.get("/device-bindings")
|
||
def list_device_bindings(
|
||
db: Session = Depends(get_db), current: User = Depends(get_current_user)
|
||
):
|
||
"""列出所有账号 ↔ 设备环境绑定 (画像 + 指纹状态 + 账号表三方合并)。"""
|
||
if not any(user_has_permission(current, p) for p in _DEVICE_BINDINGS_PERMS_VIEW):
|
||
raise HTTPException(status_code=403, detail="无虎牙账号查看权限")
|
||
profiles = _load_profile_db()
|
||
accounts = {a.username: a for a in db.query(HuyaAccount).all() if a.username}
|
||
rows = []
|
||
for account, prof in sorted(profiles.items()):
|
||
acct = accounts.get(account)
|
||
state_dir = _fp_state_dir(account)
|
||
last_login = prof.get("last_login") or {}
|
||
rows.append(
|
||
{
|
||
"account": account,
|
||
"vendor": prof.get("vendor", ""),
|
||
"model": prof.get("model", ""),
|
||
"screen": prof.get("screen", ""),
|
||
"fingerprint_masked": _mask_hex(prof.get("fingerprint")),
|
||
"guid32_masked": _mask_hex(prof.get("guid32")),
|
||
"hebe_count": len(prof.get("hebe") or {}),
|
||
"hdid32": prof.get("hdid", ""), # t1.t0 app 级常量, 非敏感
|
||
"has_hydevice_state": state_dir.exists(),
|
||
"login_channel": (acct.login_channel if acct else "") or "",
|
||
"account_status": (acct.status if acct else "") or "未入库",
|
||
"bound_at": prof.get("bound_at"),
|
||
"last_login_at": last_login.get("at"),
|
||
"last_login_ok": last_login.get("ok"),
|
||
}
|
||
)
|
||
return {"items": rows, "total": len(rows)}
|
||
|
||
|
||
@router.delete("/device-bindings/{account}")
|
||
def delete_device_binding(
|
||
account: str,
|
||
db: Session = Depends(get_db),
|
||
current: User = Depends(get_current_user),
|
||
):
|
||
"""解绑: 删除该账号的设备画像与 hydevice 指纹状态, 下次登录自动生成全新环境。"""
|
||
_require_huya_perm(current, "huya:import")
|
||
profiles = _load_profile_db()
|
||
if account not in profiles:
|
||
raise HTTPException(status_code=404, detail="该账号没有设备绑定记录")
|
||
profiles.pop(account)
|
||
_save_profile_db(profiles)
|
||
state_dir = _fp_state_dir(account)
|
||
removed_state = False
|
||
if state_dir.exists():
|
||
shutil.rmtree(state_dir, ignore_errors=True)
|
||
removed_state = True
|
||
return {
|
||
"ok": True,
|
||
"account": account,
|
||
"profile_removed": True,
|
||
"fp_state_removed": removed_state,
|
||
"message": "已解绑, 下次 App 协议登录将自动生成全新设备环境并重新注册",
|
||
}
|
||
|
||
|
||
@router.post("/device-bindings/batch-delete")
|
||
def delete_device_bindings(
|
||
req: HuyaDeviceBindingsBatchDeleteRequest,
|
||
db: Session = Depends(get_db),
|
||
current: User = Depends(get_current_user),
|
||
):
|
||
"""批量解绑: 一次删除多个账号的设备画像与指纹状态。"""
|
||
_require_huya_perm(current, "huya:import")
|
||
removed, missing = _unbind_device_accounts(req.accounts)
|
||
if not removed:
|
||
raise HTTPException(status_code=404, detail="所选账号均没有设备绑定记录")
|
||
message = f"已批量解绑 {len(removed)} 个账号"
|
||
if missing:
|
||
message += f",{len(missing)} 个账号无绑定记录已跳过"
|
||
message += ",下次 App 协议登录将自动生成全新设备环境并重新注册"
|
||
return {"ok": True, "removed": removed, "missing": missing, "message": message}
|