虎牙人工兑换改用本机浏览器并新增扩展自动注入登录态

移除服务器浏览器方案(容器/Xvfb/noVNC/CDP 会话管理),后端仅下发
兑换材料;新增内置 Chrome/Edge 扩展一键写入 huya.com 登录态,
未安装扩展时回退控制台脚本手动注入,兑换始终由用户手动完成。
This commit is contained in:
yml2213
2026-09-05 17:55:31 +08:00
parent 95ad900ef0
commit 230d6c1918
15 changed files with 477 additions and 4 deletions
+50 -3
View File
@@ -30,7 +30,7 @@ from core.huya import (
login_huya_sms,
send_huya_sms_code,
)
from core.huya.cookie_utils import normalize_huya_cookie
from core.huya.cookie_utils import browser_login_script, cookie_pairs, normalize_huya_cookie
from core.huya.device_fingerprint import account_state_dir as _fp_state_dir
from core.huya.device_profile import (
_load_db as _load_profile_db,
@@ -90,6 +90,7 @@ from ..services.huya_register_runner import (
list_success_logs,
)
from ..services.huya_runner import HuyaBatchRunner, huya_batch_registry
from ..services.huya_runner_bind import BindMixin
from ..services.huya_service import (
HUYA_CONFIG_FIELDS,
SUPPORTED_TASK_TYPES,
@@ -107,6 +108,36 @@ from ..services.huya_service import (
router = APIRouter(prefix="/api/huya", tags=["虎牙"])
@router.post("/accounts/{account_id}/browser-exchange")
def create_browser_exchange_kit(
account_id: int,
db: Session = Depends(get_db),
current: User = Depends(get_current_user),
):
"""生成指定账号的本机浏览器人工兑换材料。
登录态由前端引导用户在自己的 Chrome/Edge 中写入,服务端不托管浏览器会话。
"""
_require_huya_perm(current, "huya:task")
account = _visible_huya_accounts_query(db, current).filter(HuyaAccount.id == account_id).first()
if account is None:
raise HTTPException(status_code=404, detail="虎牙账号不存在或无权操作")
if not account.cookie:
raise HTTPException(status_code=400, detail="该账号没有可用 Cookie,请先登录")
config = ensure_huya_config(db)
target_url = BindMixin._bind_redirect_url({
"room_pid": huya_config_value("room_pid", config.room_pid),
}) or "https://zt.huya.com/b02faae1/pc/index.html"
pairs = dict(cookie_pairs(normalize_huya_cookie(account.cookie)))
return {
"account_id": account.id,
"username": account.username or account.yyuid or "",
"target_url": target_url,
"cookie_string": "; ".join(f"{key}={value}" for key, value in pairs.items()),
"cookie_script": browser_login_script(pairs, target_url),
}
def _has_huya_perm(user: User, permission: str) -> bool:
"""虎牙新权限兼容旧的 huya:account 大权限。"""
return user_has_permission(user, permission) or user_has_permission(
@@ -323,6 +354,7 @@ def _account_out(account: HuyaAccount, include_cookie: bool = True) -> HuyaAccou
yyuid=account.yyuid or "",
username=account.username or "",
has_password=bool(account.account_password),
has_cookie=bool(account.cookie),
nickname=account.nickname or "",
cookie=cookie if include_cookie else "",
cookie_preview=_fmt_cookie_preview(cookie) if include_cookie else "***",
@@ -344,7 +376,7 @@ def _account_out(account: HuyaAccount, include_cookie: bool = True) -> HuyaAccou
def _account_out_light(
account: HuyaAccount, *, has_password: bool = False
account: HuyaAccount, *, has_password: bool = False, has_cookie: bool = False
) -> HuyaAccountOut:
"""虎牙账号列表轻量输出,不读取加密字段。"""
return HuyaAccountOut(
@@ -353,6 +385,7 @@ def _account_out_light(
yyuid=account.yyuid or "",
username=account.username or "",
has_password=has_password,
has_cookie=has_cookie,
nickname=account.nickname or "",
cookie="",
cookie_preview="***",
@@ -480,6 +513,17 @@ def _huya_password_state_map(db: Session, account_ids: list[int]) -> dict[int, b
return {account_id: bool(has_password) for account_id, has_password in rows}
def _huya_cookie_state_map(db: Session, account_ids: list[int]) -> dict[int, bool]:
if not account_ids:
return {}
rows = (
db.query(HuyaAccount.id, (HuyaAccount.cookie != "").label("has_cookie"))
.filter(HuyaAccount.id.in_(account_ids))
.all()
)
return {account_id: bool(has_cookie) for account_id, has_cookie in rows}
@router.get("/task-types")
def task_types(current: User = Depends(require_permission("huya:task"))):
"""返回当前规划的虎牙任务类型。"""
@@ -531,9 +575,12 @@ def list_accounts(
password_map = _huya_password_state_map(
db, [account.id for account in accounts]
)
cookie_map = _huya_cookie_state_map(db, [account.id for account in accounts])
result = [
_account_out_light(
account, has_password=password_map.get(account.id, False)
account,
has_password=password_map.get(account.id, False),
has_cookie=cookie_map.get(account.id, False),
)
for account in accounts
]
+2
View File
@@ -428,6 +428,7 @@ class HuyaAccountOut(BaseModel):
yyuid: str = ""
username: str = ""
has_password: bool = False
has_cookie: bool = False
nickname: str = ""
cookie: str = ""
cookie_preview: str = ""
@@ -455,6 +456,7 @@ class HuyaAccountOut(BaseModel):
"yyuid": self.yyuid,
"username": self.username,
"has_password": self.has_password,
"has_cookie": self.has_cookie,
"nickname": self.nickname,
"cookie": self.cookie,
"cookie_preview": self.cookie_preview,