fix(huya): 精英宝典绑定二维码对齐最新抓包并支持配置 bind_gid
This commit is contained in:
@@ -101,6 +101,41 @@ class BindMixin:
|
||||
"bind_phase": "role_ready" if role_info["role_name"] else "waiting_role",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _bind_protocol(config_info: dict, payload: dict | None = None) -> dict:
|
||||
"""读取绑定协议参数;有 gid 时用 2026-11 抓包协议,否则回退旧协议。"""
|
||||
payload = payload or {}
|
||||
bind_gid_text = str(
|
||||
payload.get("bind_gid") or config_info.get("bind_gid") or ""
|
||||
).strip()
|
||||
bind_gid = HuyaBatchRunnerCore._to_int(bind_gid_text)
|
||||
outer_act_id = str(
|
||||
payload.get("outer_act_id")
|
||||
or config_info.get("outer_act_id")
|
||||
or HUYA_DEFAULT_OUTER_ACT_ID
|
||||
).strip()
|
||||
if bind_gid and outer_act_id:
|
||||
return {
|
||||
"bind_gid": bind_gid_text,
|
||||
"b_act_id": 0,
|
||||
"gid": bind_gid,
|
||||
"outer_act_id": outer_act_id,
|
||||
"is_use_outer_act_id": 0,
|
||||
"scene": "undefined",
|
||||
}
|
||||
b_act_id_text = str(
|
||||
payload.get("bind_act_id") or config_info.get("bind_act_id") or ""
|
||||
).strip()
|
||||
return {
|
||||
"bind_gid": "",
|
||||
"b_act_id": HuyaBatchRunnerCore._to_int(b_act_id_text),
|
||||
"gid": 0,
|
||||
# 旧协议最初不传 outerActId;需要旧路径的地方按原逻辑显式补默认值。
|
||||
"outer_act_id": "",
|
||||
"is_use_outer_act_id": 1,
|
||||
"scene": "",
|
||||
}
|
||||
|
||||
def _resolve_bind_status(
|
||||
self,
|
||||
client: Any,
|
||||
@@ -110,16 +145,20 @@ class BindMixin:
|
||||
*,
|
||||
outer_act_id: str = "",
|
||||
timeout: float | None = None,
|
||||
gid: int = 0,
|
||||
is_use_outer_act_id: int = 1,
|
||||
scene: str = "",
|
||||
):
|
||||
"""按活动页逻辑解析绑定状态,优先返回含角色的状态。"""
|
||||
probe_kwargs: dict[str, Any] = {
|
||||
"uid": uid,
|
||||
"cookie": cookie,
|
||||
"b_act_id": b_act_id_int,
|
||||
"is_use_outer_act_id": 1,
|
||||
"gid": gid,
|
||||
"outer_act_id": outer_act_id,
|
||||
"is_use_outer_act_id": is_use_outer_act_id,
|
||||
"scene": scene,
|
||||
}
|
||||
if outer_act_id:
|
||||
probe_kwargs["outer_act_id"] = outer_act_id
|
||||
if timeout is not None:
|
||||
probe_kwargs["timeout"] = timeout
|
||||
outer_status = client.check_user_bind_game_account(**probe_kwargs)
|
||||
@@ -135,10 +174,16 @@ class BindMixin:
|
||||
|
||||
chosen_status = outer_status
|
||||
account_data = outer_status.accountData
|
||||
should_check_inner = not self._has_bind_role(outer_status) and bool(
|
||||
account_data.isNeedActCheck
|
||||
or not account_data.isBindAcount
|
||||
or not account_data.isBindRole
|
||||
# 最新抓包协议只用外层查询(gid + outerActId)。旧的内层兜底会带上
|
||||
# gid=0/outerActId=空,被服务端判 501「参数错误」,仅在旧协议下保留。
|
||||
should_check_inner = (
|
||||
not gid
|
||||
and not self._has_bind_role(outer_status)
|
||||
and bool(
|
||||
account_data.isNeedActCheck
|
||||
or not account_data.isBindAcount
|
||||
or not account_data.isBindRole
|
||||
)
|
||||
)
|
||||
if should_check_inner:
|
||||
inner_status = client.check_user_bind_game_account(
|
||||
@@ -162,6 +207,9 @@ class BindMixin:
|
||||
cookie: str,
|
||||
b_act_id_int: int,
|
||||
outer_act_id: str = "",
|
||||
gid: int = 0,
|
||||
is_use_outer_act_id: int = 1,
|
||||
scene: str = "",
|
||||
):
|
||||
"""用外部单协作的新 CK 探针查角色。
|
||||
|
||||
@@ -177,6 +225,9 @@ class BindMixin:
|
||||
b_act_id_int,
|
||||
outer_act_id=outer_act_id or HUYA_DEFAULT_OUTER_ACT_ID,
|
||||
timeout=HUYA_CK_PROBE_TIMEOUT_SECONDS,
|
||||
gid=gid,
|
||||
is_use_outer_act_id=is_use_outer_act_id,
|
||||
scene=scene,
|
||||
)
|
||||
|
||||
def _apply_role_to_account(self, account: HuyaAccount, bind_status, status: str):
|
||||
@@ -209,6 +260,11 @@ class BindMixin:
|
||||
cookie: str,
|
||||
b_act_id_int: int,
|
||||
result: dict,
|
||||
*,
|
||||
gid: int = 0,
|
||||
outer_act_id: str = "",
|
||||
is_use_outer_act_id: int = 1,
|
||||
scene: str = "",
|
||||
) -> tuple[str, dict]:
|
||||
"""生成二维码后轮询扫码状态与角色同步,直到识别到角色、超时或停止。"""
|
||||
deadline = time.monotonic() + HUYA_BIND_ROLE_POLL_SECONDS
|
||||
@@ -258,6 +314,10 @@ class BindMixin:
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=outer_act_id,
|
||||
gid=gid,
|
||||
is_use_outer_act_id=is_use_outer_act_id,
|
||||
scene=scene,
|
||||
)
|
||||
if bind_status is None:
|
||||
continue
|
||||
@@ -328,20 +388,12 @@ class BindMixin:
|
||||
account_info: dict,
|
||||
config_info: dict,
|
||||
):
|
||||
b_act_id = str(
|
||||
self.payload.get("bind_act_id") or config_info.get("bind_act_id") or ""
|
||||
).strip()
|
||||
if not b_act_id:
|
||||
protocol = self._bind_protocol(config_info, self.payload)
|
||||
b_act_id_int = protocol["b_act_id"]
|
||||
if not protocol["bind_gid"] and not b_act_id_int:
|
||||
self._mark_task(worker_db, task, "failed", "请先配置虎牙绑定 bActId")
|
||||
return
|
||||
|
||||
b_act_id_int = self._to_int(b_act_id)
|
||||
if not b_act_id_int:
|
||||
self._mark_task(
|
||||
worker_db, task, "failed", f"虎牙绑定 bActId 无效: {b_act_id}"
|
||||
)
|
||||
return
|
||||
|
||||
uid = self._resolve_uid(account_info)
|
||||
if not uid:
|
||||
self._mark_task(worker_db, task, "failed", "无法从账号或 Cookie 解析 yyuid")
|
||||
@@ -358,6 +410,10 @@ class BindMixin:
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
gid=protocol["gid"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if bind_status is None:
|
||||
self._mark_task(worker_db, task, "error", "虎牙绑定状态接口无响应")
|
||||
@@ -383,6 +439,8 @@ class BindMixin:
|
||||
available_at = change_state["change_available_at"]
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
**role_info,
|
||||
**change_state,
|
||||
"bind_status": bind_status.to_dict(),
|
||||
@@ -400,6 +458,8 @@ class BindMixin:
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id=b_act_id_int,
|
||||
gid=protocol["gid"],
|
||||
outer_act_id=int(protocol["outer_act_id"] or 0),
|
||||
game_auth_scene=bind_status.gameAuthScene,
|
||||
)
|
||||
if live_link is None:
|
||||
@@ -450,6 +510,8 @@ class BindMixin:
|
||||
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"mini_qrcode_image": mini_qrcode["mini_qrcode_image"],
|
||||
"qrcode_token": mini_qrcode.get("qrcode_token") or "",
|
||||
**bind_query_result,
|
||||
@@ -483,6 +545,10 @@ class BindMixin:
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
result=result,
|
||||
gid=protocol["gid"],
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if role_name:
|
||||
self._mark_task(
|
||||
@@ -514,20 +580,12 @@ class BindMixin:
|
||||
account_info: dict,
|
||||
config_info: dict,
|
||||
):
|
||||
b_act_id = str(
|
||||
self.payload.get("bind_act_id") or config_info.get("bind_act_id") or ""
|
||||
).strip()
|
||||
if not b_act_id:
|
||||
protocol = self._bind_protocol(config_info, self.payload)
|
||||
b_act_id_int = protocol["b_act_id"]
|
||||
if not protocol["bind_gid"] and not b_act_id_int:
|
||||
self._mark_task(worker_db, task, "failed", "请先配置虎牙绑定 bActId")
|
||||
return
|
||||
|
||||
b_act_id_int = self._to_int(b_act_id)
|
||||
if not b_act_id_int:
|
||||
self._mark_task(
|
||||
worker_db, task, "failed", f"虎牙绑定 bActId 无效: {b_act_id}"
|
||||
)
|
||||
return
|
||||
|
||||
uid = self._resolve_uid(account_info)
|
||||
if not uid:
|
||||
self._mark_task(worker_db, task, "failed", "无法从账号或 Cookie 解析 yyuid")
|
||||
@@ -538,16 +596,14 @@ class BindMixin:
|
||||
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
|
||||
return
|
||||
|
||||
outer_act_id = str(
|
||||
self.payload.get("outer_act_id")
|
||||
or config_info.get("outer_act_id")
|
||||
or HUYA_DEFAULT_OUTER_ACT_ID
|
||||
).strip()
|
||||
bind_status, bind_query_result = self._probe_bind_status(
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=outer_act_id,
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
gid=protocol["gid"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if bind_status is None:
|
||||
# 新探针没有回包 = 这份 CK 已经不认了,和外部单协作的判定一致。
|
||||
@@ -560,6 +616,8 @@ class BindMixin:
|
||||
"虎牙角色信息接口无响应(CK 已失效,请重新登录或重新导入 Cookie)",
|
||||
{
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"ck_expired": True,
|
||||
"ck_expired_reason": "角色信息接口无响应",
|
||||
},
|
||||
@@ -572,7 +630,12 @@ class BindMixin:
|
||||
task,
|
||||
"failed",
|
||||
bind_status.msg or f"虎牙角色信息查询失败: {bind_status.status}",
|
||||
{"bind_act_id": b_act_id_int, **bind_query_result},
|
||||
{
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
**bind_query_result,
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
@@ -580,6 +643,8 @@ class BindMixin:
|
||||
change_state = self._bind_change_state(bind_status)
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
**role_info,
|
||||
**change_state,
|
||||
**bind_query_result,
|
||||
@@ -604,20 +669,12 @@ class BindMixin:
|
||||
account_info: dict,
|
||||
config_info: dict,
|
||||
):
|
||||
b_act_id = str(
|
||||
self.payload.get("bind_act_id") or config_info.get("bind_act_id") or ""
|
||||
).strip()
|
||||
if not b_act_id:
|
||||
protocol = self._bind_protocol(config_info, self.payload)
|
||||
b_act_id_int = protocol["b_act_id"]
|
||||
if not protocol["bind_gid"] and not b_act_id_int:
|
||||
self._mark_task(worker_db, task, "failed", "请先配置虎牙绑定 bActId")
|
||||
return
|
||||
|
||||
b_act_id_int = self._to_int(b_act_id)
|
||||
if not b_act_id_int:
|
||||
self._mark_task(
|
||||
worker_db, task, "failed", f"虎牙绑定 bActId 无效: {b_act_id}"
|
||||
)
|
||||
return
|
||||
|
||||
uid = self._resolve_uid(account_info)
|
||||
if not uid:
|
||||
self._mark_task(worker_db, task, "failed", "无法从账号或 Cookie 解析 yyuid")
|
||||
@@ -634,6 +691,10 @@ class BindMixin:
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
gid=protocol["gid"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if role_status is None:
|
||||
self._mark_task(worker_db, task, "error", "虎牙绑定角色查询接口无响应")
|
||||
@@ -653,6 +714,8 @@ class BindMixin:
|
||||
if not role_name:
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"bind_confirmed": False,
|
||||
**role_query_result,
|
||||
}
|
||||
@@ -669,6 +732,8 @@ class BindMixin:
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id=b_act_id_int,
|
||||
gid=protocol["gid"],
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
)
|
||||
if confirm_resp is None:
|
||||
self._mark_task(worker_db, task, "error", "虎牙确认绑定接口无响应")
|
||||
@@ -676,6 +741,8 @@ class BindMixin:
|
||||
if confirm_resp.status != 200:
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"bind_confirmed": False,
|
||||
"confirm_result": confirm_resp.to_dict(),
|
||||
"before_bind_status": role_status.to_dict(),
|
||||
@@ -695,10 +762,16 @@ class BindMixin:
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
gid=protocol["gid"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if refreshed_status is None:
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"bind_confirmed": True,
|
||||
"confirm_result": confirm_resp.to_dict(),
|
||||
"before_bind_status": role_status.to_dict(),
|
||||
@@ -713,6 +786,8 @@ class BindMixin:
|
||||
if refreshed_status.status != 200:
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"bind_confirmed": True,
|
||||
"confirm_result": confirm_resp.to_dict(),
|
||||
"before_bind_status": role_status.to_dict(),
|
||||
@@ -739,6 +814,8 @@ class BindMixin:
|
||||
)
|
||||
result = {
|
||||
"bind_act_id": b_act_id_int,
|
||||
"bind_gid": protocol["bind_gid"],
|
||||
"gid": protocol["gid"],
|
||||
"bind_confirmed": True,
|
||||
"refreshed_is_bound": refreshed_confirmed,
|
||||
"confirm_result": confirm_resp.to_dict(),
|
||||
|
||||
@@ -228,7 +228,11 @@ class HuyaBatchRunnerCore:
|
||||
def _format_local_time(timestamp: int) -> str:
|
||||
if not timestamp:
|
||||
return ""
|
||||
return datetime.fromtimestamp(timestamp, UTC).strftime("%Y-%m-%d %H:%M:%S")
|
||||
return (
|
||||
datetime.fromtimestamp(timestamp, UTC)
|
||||
.astimezone()
|
||||
.strftime("%Y-%m-%d %H:%M:%S")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse_scheduled_time(value) -> datetime | None:
|
||||
|
||||
@@ -285,23 +285,20 @@ class EliteMixin:
|
||||
role_name = ""
|
||||
|
||||
# ---- 角色绑定 / CK 有效性(先做,失效就不空跑后面两个接口) ----
|
||||
b_act_id_int = self._to_int(
|
||||
self.payload.get("bind_act_id") or config_info.get("bind_act_id")
|
||||
)
|
||||
if not b_act_id_int:
|
||||
protocol = self._bind_protocol(config_info, self.payload)
|
||||
b_act_id_int = protocol["b_act_id"]
|
||||
if not protocol["bind_gid"] and not b_act_id_int:
|
||||
failures.append("未配置绑定 bActId")
|
||||
result["ck_valid"] = False
|
||||
else:
|
||||
outer_act_id = str(
|
||||
self.payload.get("outer_act_id")
|
||||
or config_info.get("outer_act_id")
|
||||
or ""
|
||||
).strip()
|
||||
bind_status, bind_query_result = self._probe_bind_status(
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=outer_act_id,
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
gid=protocol["gid"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if bind_status is None:
|
||||
account.status = "ck_expired"
|
||||
|
||||
@@ -10,7 +10,6 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from core.huya.wss_client import POINTS_REDEEM_GOODS_NUM
|
||||
|
||||
from ..huya_defaults import HUYA_DEFAULT_OUTER_ACT_ID
|
||||
from ..models import HuyaAccount, HuyaGoodsSnapshot, HuyaTask
|
||||
|
||||
# 积分查询超时:HTTP 通道正常几百毫秒,10 秒足够;失败时别让整批任务长时间挂住。
|
||||
@@ -123,20 +122,17 @@ class GoodsMixin:
|
||||
|
||||
# ---- 先验 CK:没有回包就立即判失效,不再空跑积分与旧接口 ----
|
||||
ck_valid = False
|
||||
b_act_id_int = self._to_int(
|
||||
self.payload.get("bind_act_id") or config_info.get("bind_act_id")
|
||||
)
|
||||
if b_act_id_int:
|
||||
outer_act_id = str(
|
||||
self.payload.get("outer_act_id")
|
||||
or config_info.get("outer_act_id")
|
||||
or HUYA_DEFAULT_OUTER_ACT_ID
|
||||
).strip()
|
||||
protocol = self._bind_protocol(config_info, self.payload)
|
||||
b_act_id_int = protocol["b_act_id"]
|
||||
if protocol["bind_gid"] or b_act_id_int:
|
||||
bind_status, _bind_query_result = self._probe_bind_status(
|
||||
uid=uid,
|
||||
cookie=cookie,
|
||||
b_act_id_int=b_act_id_int,
|
||||
outer_act_id=outer_act_id,
|
||||
outer_act_id=protocol["outer_act_id"],
|
||||
gid=protocol["gid"],
|
||||
is_use_outer_act_id=protocol["is_use_outer_act_id"],
|
||||
scene=protocol["scene"],
|
||||
)
|
||||
if bind_status is None:
|
||||
account.status = "ck_expired"
|
||||
|
||||
Reference in New Issue
Block a user