Files
live-hub-py/web/backend/migrations/versions/20261015_0053_huya_elite_open.py
T
yml2213 73536d62c8 feat(huya): 工作台补手机号/精英宝典列与一键查询
- 手机号列:外部 CK 的 `----手机号` 本来就落在 huya_accounts.game_phone,
  列表一直没展示;现在单独成列,并纳入搜索
- 精英宝典列:显示「已开通/未开通/未查询」+ 开通时间 + 有效期
  · 开通状态 = 积分中心 getRedeemNeedGoods 的 tag5(真机对照网页:1=已开通,
    0=未开通,此时 tag7 会列出开通套餐),拿不准时为 NULL(显示「未查询」)
  · 开通时间 = revenueWebUI.queryUserOrderList 里已支付的宝典订单 pay_time
    (按 SPU 白名单 + 订单名含「精英宝典」识别,未支付订单不计,取最近一次)
  · 有效期 = PlayMallUI.queryAllocation 页面配置的本赛季节点 tag10/tag11
    (2026-10-15 抓包:精英宝典福利季丨Q4,2026-10-09 ~ 2026-12-31 23:59:59),
    不写死索引,递归找带 tag10/tag11 的节点
- 新任务 query_all「一键查询」:勾选账号一次跑完角色绑定 + 宝典开通 + 积分,
  按部分失败如实汇总(某个接口挂了不影响其它结论),并把宝典状态写回账号
- 迁移 20261015_0053:huya_accounts 新增 elite_opened / elite_open_time /
  elite_expire_time(时间存 Unix 秒,与斗鱼 elite_expire_time 同约定)
- 开通商品按页面「赠送指定礼物得积分」那一排对齐成 6 款(去掉页面已不用的
  旧版精英宝典 hy-5879340),列表接口只返回账号级快照并按 spu 去重
- 建 WSS 会话失败(积分中心端点静默不回包)时回退 HTTP cdnws,
  不再让整批任务判失败
- 列表列宽改按比例分配,避免宽屏下被拉出奇怪的宽度;最近操作不再重复状态
- 新增 tests/test_huya_elite_query.py(10 条);同步迁移头版本断言

真机验证:#65 已开通(10-13 20:41:45,有效期 12-31)、#70 新开通
(10-15 16:37:37)判定与订单/网页一致
2026-10-15 16:53:30 +08:00

80 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""虎牙精英宝典开通状态:`huya_accounts` 新增 elite_opened / elite_open_time / elite_expire_time
工作台列表要能直接看到「这个号开没开宝典、什么时候开的、有效期到什么时候」,
但现在只有一个 `points` 列:开通后把积分花完和从没开通,在界面上长得一模一样。
真机(2026-10-15 两份抓包 + 真机对照网页)核对的来源:
* 开通状态 —— 积分中心 ``shopMiddleUI.getRedeemNeedGoods`` 的 ``tag5``:
``1`` = 已开通(网页显示「已开通精英宝典」),``0`` = 未开通(网页显示
「获取积分需先开通精英宝典」,``tag7`` 还会列出开通套餐)。
* 开通时间 —— ``revenueWebUI.queryUserOrderList`` 里已支付的宝典订单,取最近一次。
* 有效期 —— ``PlayMallUI.queryAllocation`` 响应里的赛季节点(``tag10``/``tag11``
是本赛季起止毫秒时间戳):2026-10-15 抓包为「精英宝典福利季丨Q4」,
即 2026-10-09 ~ 2026-12-31 23:59:59;认不出赛季结构时留空。
两列时间都存 **Unix 秒**(Integer 放不下毫秒时间戳,且与斗鱼 `elite_expire_time`
同一约定)。
历史值不回填:以前没查过宝典状态的账号是 NULL(界面显示「未查询」),
下次「一键查询」会补上 —— 不回填才不会把「没查过」伪装成「未开通」。
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
revision: str = "20261015_0053"
down_revision: str | None = "20261008_0052"
branch_labels: str | None = None
depends_on: str | None = None
TABLE = "huya_accounts"
COLUMNS = (
(
"elite_opened",
sa.Boolean(),
"精英宝典是否已开通(积分中心 getRedeemNeedGoods 的 tag5;NULL=未查询)",
),
(
"elite_open_time",
sa.Integer(),
"最近一次宝典订单的支付时间(Unix 秒)",
),
(
"elite_expire_time",
sa.Integer(),
"宝典有效期(Unix 秒):积分中心本赛季结束时间;认不出赛季时留空",
),
)
def _column_exists(name: str) -> bool:
"""可安全重跑(应用启动时会自动跑迁移)。"""
conn = op.get_bind()
count = conn.execute(
sa.text(
"SELECT COUNT(*) FROM information_schema.columns "
"WHERE table_schema = DATABASE() "
"AND table_name = :table AND column_name = :name"
),
{"table": TABLE, "name": name},
).scalar()
return bool(count)
def upgrade() -> None:
for name, column_type, comment in COLUMNS:
if not _column_exists(name):
op.add_column(
TABLE,
sa.Column(name, column_type, nullable=True, comment=comment),
)
def downgrade() -> None:
for name, _column_type, _comment in COLUMNS:
if _column_exists(name):
op.drop_column(TABLE, name)