type: 收窄斗鱼商城与小店执行器类型
This commit is contained in:
@@ -3,16 +3,35 @@
|
||||
from __future__ import annotations
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, TYPE_CHECKING, cast
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from core.douyu import DouyuActivityClient, DouyuActivityError
|
||||
from ..models import Account, DouyuTask, DouyuXpdGoodsSnapshot
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .douyu_runner import DouyuBatchRunner
|
||||
|
||||
DOUYU_XPD_BIND_POLL_SECONDS = 300
|
||||
DOUYU_XPD_BIND_POLL_INTERVAL = 5
|
||||
|
||||
|
||||
class XpdMixin:
|
||||
"""和平小店域:绑定、商品、余额、碎片与兑换。"""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
_stop: Any
|
||||
|
||||
@staticmethod
|
||||
def _to_int(value: Any) -> int | None: ...
|
||||
|
||||
def _client(self, cookie: str) -> DouyuActivityClient: ...
|
||||
def _task_payload(self, task: DouyuTask) -> dict: ...
|
||||
def _upsert_xpd_goods(self, db: Session, goods: list[dict]) -> None: ...
|
||||
def _push_log(self, level: str, message: str) -> None: ...
|
||||
def _mark_task(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
def _update_task_progress(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
|
||||
def _xpd_role_context(self, client: DouyuActivityClient, config: dict) -> dict:
|
||||
"""获取小店 H5 参数 + 绑定角色信息,小店任务共用。"""
|
||||
embed = client.xpd_embed_query(
|
||||
@@ -43,8 +62,12 @@ class XpdMixin:
|
||||
return 2
|
||||
return account.xpd_area_id or 1
|
||||
|
||||
def _apply_xpd_role_to_account(self, account: Account, role: dict, area_id: int) -> None:
|
||||
account.xpd_game_name = str(role.get("role_name") or "") or account.xpd_game_name
|
||||
def _apply_xpd_role_to_account(
|
||||
self, account: Account, role: dict, area_id: int
|
||||
) -> None:
|
||||
account.xpd_game_name = (
|
||||
str(role.get("role_name") or "") or account.xpd_game_name
|
||||
)
|
||||
account.xpd_openid = str(role.get("game_open_id") or "") or account.xpd_openid
|
||||
account.xpd_role_id = str(role.get("role_id") or "") or account.xpd_role_id
|
||||
account.xpd_plat_id = self._to_int(role.get("plat_id"))
|
||||
@@ -71,7 +94,11 @@ class XpdMixin:
|
||||
account.xpd_bind_status = "xpd_bound"
|
||||
db.commit()
|
||||
role_text = str(role.get("role_name") or "-")
|
||||
channel = "微信" if role.get("type") == "wx" else ("手Q" if role.get("type") == "qq" else str(role.get("type") or "-"))
|
||||
channel = (
|
||||
"微信"
|
||||
if role.get("type") == "wx"
|
||||
else ("手Q" if role.get("type") == "qq" else str(role.get("type") or "-"))
|
||||
)
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
@@ -126,7 +153,9 @@ class XpdMixin:
|
||||
return
|
||||
if state == "pending":
|
||||
role_text = str(result.get("role_name") or "-")
|
||||
self._mark_task(db, task, "success", f"已识别角色: {role_text},待确认绑定", result)
|
||||
self._mark_task(
|
||||
db, task, "success", f"已识别角色: {role_text},待确认绑定", result
|
||||
)
|
||||
return
|
||||
self._mark_task(
|
||||
db,
|
||||
@@ -162,9 +191,13 @@ class XpdMixin:
|
||||
result["bind_polling"] = True
|
||||
role_name = str(info.get("role_name") or "")
|
||||
bound_now = bool(info.get("bind_role"))
|
||||
changed = before_bound and bool(role_name) and role_name != before_role_name
|
||||
changed = (
|
||||
before_bound and bool(role_name) and role_name != before_role_name
|
||||
)
|
||||
if (not before_bound and bound_now and role_name) or changed:
|
||||
result.update({key: value for key, value in info.items() if key != "raw"})
|
||||
result.update(
|
||||
{key: value for key, value in info.items() if key != "raw"}
|
||||
)
|
||||
result["bind_polling"] = False
|
||||
result["xpd_pending_confirm"] = True
|
||||
return "pending"
|
||||
@@ -211,14 +244,18 @@ class XpdMixin:
|
||||
account.xpd_bind_status = "xpd_not_bound"
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
self._mark_task(db, task, "failed", "尚未检测到小店绑定角色,请先扫码绑定", result)
|
||||
self._mark_task(
|
||||
db, task, "failed", "尚未检测到小店绑定角色,请先扫码绑定", result
|
||||
)
|
||||
return
|
||||
# 优先用完整角色信息回写(与查询角色一致),失败时回退 bindInfo 角色名
|
||||
try:
|
||||
ctx = self._xpd_role_context(client, config)
|
||||
role = ctx["role"]
|
||||
if role.get("role_id"):
|
||||
self._apply_xpd_role_to_account(account, role, self._xpd_area_id(role, account))
|
||||
self._apply_xpd_role_to_account(
|
||||
account, role, self._xpd_area_id(role, account)
|
||||
)
|
||||
else:
|
||||
account.xpd_game_name = role_name
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
@@ -375,7 +412,9 @@ class XpdMixin:
|
||||
except Exception:
|
||||
pass
|
||||
if not openid or not roleid:
|
||||
self._mark_task(db, task, "failed", "未获取到小店绑定角色,请先生成二维码扫码绑定")
|
||||
self._mark_task(
|
||||
db, task, "failed", "未获取到小店绑定角色,请先生成二维码扫码绑定"
|
||||
)
|
||||
return
|
||||
result = client.xpd_fragments(
|
||||
embed_query=embed_query,
|
||||
@@ -440,7 +479,9 @@ class XpdMixin:
|
||||
):
|
||||
"""兑换和平小店商品,使用本次签发的道聚城短时授权。"""
|
||||
payload = self._task_payload(task)
|
||||
commodity_id = str(payload.get("commodity_id") or payload.get("commodityId") or "").strip()
|
||||
commodity_id = str(
|
||||
payload.get("commodity_id") or payload.get("commodityId") or ""
|
||||
).strip()
|
||||
if not commodity_id:
|
||||
self._mark_task(db, task, "failed", "请选择小店商品")
|
||||
return
|
||||
@@ -462,7 +503,12 @@ class XpdMixin:
|
||||
self._mark_task(db, task, "failed", "未找到小店商品快照,请先刷新商品列表")
|
||||
return
|
||||
goods_snapshot = goods.raw if isinstance(goods.raw, dict) else {}
|
||||
goods_raw = goods_snapshot.get("raw") if isinstance(goods_snapshot.get("raw"), dict) else goods_snapshot
|
||||
nested_raw = goods_snapshot.get("raw")
|
||||
goods_raw = (
|
||||
cast(dict[str, Any], nested_raw)
|
||||
if isinstance(nested_raw, dict)
|
||||
else cast(dict[str, Any], goods_snapshot)
|
||||
)
|
||||
price_key = "iPrice" if pay_type == 1 else "iJb2Price"
|
||||
price = self._to_int(goods_raw.get(price_key))
|
||||
if price is None:
|
||||
@@ -489,11 +535,15 @@ class XpdMixin:
|
||||
rid=str(config["xpd_rid"]),
|
||||
)
|
||||
if role.get("role_id"):
|
||||
self._apply_xpd_role_to_account(account, role, self._xpd_area_id(role, account))
|
||||
self._apply_xpd_role_to_account(
|
||||
account, role, self._xpd_area_id(role, account)
|
||||
)
|
||||
except DouyuActivityError as exc:
|
||||
self._push_log("warning", f"小店兑换前刷新角色失败,使用已保存角色: {exc}")
|
||||
if not role.get("role_id") and not account.xpd_role_id:
|
||||
self._mark_task(db, task, "failed", "未获取到小店绑定角色,请先生成二维码扫码绑定")
|
||||
self._mark_task(
|
||||
db, task, "failed", "未获取到小店绑定角色,请先生成二维码扫码绑定"
|
||||
)
|
||||
return
|
||||
|
||||
result = client.xpd_exchange_goods(
|
||||
@@ -516,13 +566,25 @@ class XpdMixin:
|
||||
|
||||
currency = "点券" if pay_type == 1 else "扭蛋碎片"
|
||||
display_role = role.get("role_name") or account.xpd_game_name or ""
|
||||
channel = "微信" if (role.get("type") == "wx" or account.xpd_area_id == 1) else "手Q"
|
||||
result.update({
|
||||
"goods": {**goods_raw, "commodityName": goods.name or ""},
|
||||
"game_name": display_role,
|
||||
"game_channel": channel,
|
||||
"account_name": account.nickname or account.username or account.uid or f"#{account.id}",
|
||||
"currency": currency,
|
||||
})
|
||||
self._mark_task(db, task, "success", f"兑换小店商品成功: {goods.name or commodity_id}({price}{currency})", result)
|
||||
|
||||
channel = (
|
||||
"微信" if (role.get("type") == "wx" or account.xpd_area_id == 1) else "手Q"
|
||||
)
|
||||
result.update(
|
||||
{
|
||||
"goods": {**goods_raw, "commodityName": goods.name or ""},
|
||||
"game_name": display_role,
|
||||
"game_channel": channel,
|
||||
"account_name": account.nickname
|
||||
or account.username
|
||||
or account.uid
|
||||
or f"#{account.id}",
|
||||
"currency": currency,
|
||||
}
|
||||
)
|
||||
self._mark_task(
|
||||
db,
|
||||
task,
|
||||
"success",
|
||||
f"兑换小店商品成功: {goods.name or commodity_id}({price}{currency})",
|
||||
result,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user