Commit Graph
131 Commits
Author SHA1 Message Date
yml2213 7aaaeebe2b fix(automation): 修正调度口径——作业每 5 分钟跑一轮,interval_seconds 只是单行重检间隔
P1a 把两个「间隔」混成了一个:next_run_at 用的是 job.interval_seconds,于是
作业 6 小时才跑一轮、每轮 200 条 = 800 条/天,全库 12,881 条要 16 天才能过
一遍 —— 等于没巡检,与规划里「账号 6 小时内被查一次」的目标差了两个数量级。

按规划原意修正:
- TICK_SECONDS 60 → 300:作业每个 tick(5 分钟)跑一轮;
- next_run_at 改为 finished + TICK_SECONDS,不再用 interval_seconds;
- interval_seconds 只作为「同一行多久重新检测」的选行 cutoff(选行逻辑本来就
  是这么用的,无需改);
- 容量口径随之更新:5 分钟一轮 × 200 条 = 40 条/分钟 ≥ 需要的 36 条/分钟,
  冷启动约 5.4 小时覆盖全库,稳态每轮一百多条;
- 前端标签由「巡检周期(小时)」改为「单账号重检间隔(小时)」,说明文案写清
  「每 5 分钟跑一轮」,避免运维误以为是作业周期。

同步更新规划文档 §7.2/§7.3(含两个间隔不能混的说明)与附录 C 的三段上线
步骤(立即跑一次 → 每轮 50 观察 → 每轮 200 启用)。
2026-10-02 19:54:31 +08:00
yml2213 f745a61df1 feat(automation): CK 自动巡检(P1a),只检测不改 CK
后台原本靠人工逐批点「CK 检测」发现失效账号,1.2 万个账号根本盯不过来。
P1a 把「哪些账号失效了」自动化:自动挑久未检测的账号、调现成检测接口、
把结果写回 ck_check_*。**本作业不替换任何 CK**,重登仍由人工点,符合规划里
「先做只读/只提示,确认无误再做自动动作」的渐进上线原则。

实现:
- 迁移 20261002_0037:automation_jobs / automation_runs 两张表,
  login_tasks 加 relogin_attempts / relogin_next_at / relogin_last_error
  (为 P1b 备好),accounts 加 auto_managed(特殊账号不参与自动化);
- services/automation/scheduler.py:进程内调度线程,60s tick,状态全部落库
  (重启不丢调度进度、不重复跑轮);AUTOMATION_ENABLED 默认关闭,作业开关
  也默认关闭;ensure_jobs 只补缺失行、不覆盖运维改过的配置;
  作业异常只记 failed,不拖垮调度线程;单容器 --workers 1,无需分布式锁;
- services/automation/jobs/ck_health.py:选行口径与人工检测一致
  (cookie_holding_filter:持有 CK 且无在途尝试),叠加久未检测、
  auto_managed、batch_size,按 ck_checked_at 升序(最久没查的优先);
  只写 ck_check_status / ck_check_result / ck_checked_at;
- routers/automation.py:GET /jobs、PATCH /jobs/{key}、POST /jobs/{key}/run、
  GET /runs;新增权限点 automation:view(运营可看)与 automation:manage
  (仅超管),改配置与手动触发都写审计;
- 顺带补 POST /api/login/batch 的审计(此前批次是谁发起、多少账号无据可查);
- 前端 /automation 页:作业卡片(开关/周期/单轮条数/并发)、运行历史、
  「立即跑一次」;总开关未打开、调度线程未运行时给明确提示。

验证:
- 22 条新测试覆盖调度器行为(只跑到点的、异常不抛出、下轮时间、配置不被重置)、
  选行条件(在途尝试/auto_managed/间隔/batch_size)、接口与权限,其中一条
  专门断言巡检后 cookie/status/message/attempt_status 一字未动;
- 全量 257 条通过;前端 tsc 与构建通过;
- 端到端用 3 个真实账号跑真实斗鱼接口:巡检结果与直接调 check_douyu_cookie
  逐条一致(3/3 valid),CK 与尝试状态全程未变。

顺带修掉一处会炸生产的坑:DB 时间列读出来是 naive UTC,直接与
datetime.now(UTC) 比较会 TypeError,现统一走 _as_utc() 补时区。
2026-10-02 19:47:41 +08:00
yml2213 99db772ddd feat(douyu): 精英宝典支持查询开通状态,开通前先校验且不再误判到账
线上两个问题:工作台看不到账号有没有开通精英宝典;点开通时二维码会「闪一下
就变小」——大图弹窗 2~4 秒后自动关闭,只剩列表里 56px 的小二维码。

根因:
- getUserInfo 的 manualType/expireTime 才是开通状态的权威口径,但只有兑换
  流程用过一次,没有任务类型对外暴露;前端只看积分列,而「开通后积分花完」
  和「从未开通」都是 0 分,区分不了(实测 13456 manualType=1/score=0);
- 开通前不查状态,且到账判定写成「积分 >= 300」:账上本来就有 680 分的账号
  在出码后第一轮轮询就被判成功,前端按 paymentArrived 自动关掉了弹窗。

改动:
- 新增任务类型 query_elite_status:查 manualType/manualScore/expireTime 并
  落库到 accounts.elite_opened / elite_expire_time(迁移 20261001_0036),
  精英工作台加查询按钮与「宝典状态」列(已开通+到期 / 未开通);
- create_elite_qr 开通前先查状态:已开通直接判成功、不再生成支付码(方案 A),
  既消除二维码闪现,也避免给已开通账号开出真实支付单;
- 到账判定改为「积分比开通前增长」,基线用与轮询同源的 credit/balance 取,
  取不到基线才退回旧口径;
- 支付弹窗不再自动关闭:到账/失败/停止都在弹窗里给结论 + 手动关闭;列表小
  二维码在任务进终态后隐藏。

新增 9 条测试覆盖上述行为,回退 runner 时其中 8 条失败。
2026-10-01 19:08:25 +08:00
yml2213 6a25097412 fix(douyu): 替换 CK 是最后一步,只有登录成功才写回记录
上一版把可见性改成「记录里还有 CK」,账号不会再消失,但根因还在:批次启动
时就把复用的成功记录改成 pending(旧 CK 仍在),停止或失败后没人恢复状态,
记录一直显示成一次没完成的登录。

按「替换 CK 是最后一步」把两者拆开:

- login_tasks 新增 attempt_status / attempt_message / attempt_batch_id /
  attempt_at,批次只写 attempt_*,status/cookie/message 只在登录成功时更新;
- _begin_attempt 只登记尝试,_mark_attempt_failed 只记录失败(已有 CK 的记录
  原样不动),_write_login_success 是唯一替换旧 CK 的入口;
- 停止批次、代理不可用、登录异常、进程重启清理全部改为收敛 attempt_*,
  因此停止一个批次不可能再让账号失去 CK;
- 复用的记录改用「持有 CK 的记录」,不再创建第二条记录,失败记录在无 CK 时
  才复用;
- 登录任务列表/统计按 attempt_* 展示「这次登录怎么样了」,批次筛选同时匹配
  attempt_batch_id;CK 操作页的重登状态也从 attempt_* 映射;
- 迁移 20261001_0035 归一存量数据:持有 CK 的记录 status 统一为 success、
  历史状态搬进 attempt_*,无 CK 且卡在 pending/running 的收敛为 failed。

新增测试:批次失败/停止不碰旧 CK、成功后替换 CK、列表展示尝试状态、
迁移存量数据归一。
2026-10-01 18:29:49 +08:00
yml2213 64c399617a fix(douyu): 账号只要还持有 CK 就不再从工作台消失
线上事故:分配给客服的账号(如「远行者103」)在斗鱼工作台与 CK 列表里
查不到,只有账号管理里还能搜到。原因是可见性判定写成了
LoginTask.status == "success",而按设计保留旧 CK 的三种状态都不再是
success:

- 普通登录批次启动时会把复用的成功记录置为 pending/running(旧 CK 保留),
  批次被停止或失败后一直停在 pending,账号永久消失;
- CK 重登失败置为 relogin_failed(旧 CK 保留),账号从工作台消失;
- 普通登录失败置为 failed(复用记录的旧 CK 未清空),同样消失。

线上现状:12545 个账号持有 CK,但只有 11703 个能出现在工作台,842 个
(644 重登失败 + 176 排队中 + …)对客服和管理员都不可见。

改动:
- douyu_service 新增 cookie_holding_filter()/latest_cookie_login_task(),
  以「记录里还留着 Cookie」作为唯一判据,并抽出 LOGIN_IN_FLIGHT_STATUSES
  与 cookie_operable_filter() 供检测/重登入口复用;
- 斗鱼工作台账号列表、任务账号校验、账号管理 has_cookie 筛选、分配校验与
  概览、CK 管理/操作列表、首页 CK 统计统一改用该判据;
- 工作台取 CK 从 latest_success_login_task 换成 latest_cookie_login_task,
  保证重登失败/排队中的账号仍能被任务正常执行;
- 新增 cleanup_orphan_login_tasks():进程重启后把遗留的 pending/running
  收敛为 failed 并保留旧 CK,避免页面永久显示排队中。

新增回归测试覆盖上述状态下的可见性、可执行性与启动清理。
2026-10-01 18:18:02 +08:00
yml2213 4518b726ac feat(huya): 浏览器兑换三目标直达并收窄扩展注入范围
- 操作列改为「直播间 / 精英宝典 / 电竞宝典」三个直达按钮,点哪个就按哪个目标写入登录态并打开,去掉弹窗内选择
- 新增 services/huya_exchange_targets.py 统一三个目标地址,接口支持可选 body {"target": "..."}(不传=精英宝典)
- 扩展内容脚本从 <all_urls> 收窄到后台站点白名单,service worker 校验 sender.tab.url,拒绝其它来源的注入
- 注入改为 Cookie 写完后回执(ok/written/failed/error),前端按回执提示成功或失败,不再静默
- 扩展图标兜底改用 world:'MAIN' 读取;一个 Cookie 都没写成功时不打开目标页
- 兑换材料签发写审计 huya:exchange:kit(含账号与目标)
- 控制台脚本增加 huya.com 域校验与 Secure,与扩展路径保持一致
- 修复兑换记录轮询的跨账号串扰与卸载后 setState;兑换请求加 epoch 防止过期结果覆盖弹窗
- 新增 tests/test_huya_browser_exchange.py(13 项)并同步 docs/HUYA_BROWSER_EXCHANGE.md
2026-09-11 10:31:46 +08:00
yml2213andCursor e81119117f feat(huya): 多选登录改单线程队列并拆分路由与工作台
默认同时只登一个号,失败两次跳下一个,号间留间隔,结束后可一键重试失败账号。
顺带拆分虎牙路由与斗鱼工作台页面,并补齐 raw_cookie 重建入口。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 11:31:50 +08:00
yml2213 cbc7f7c9c5 fix(huya): 优化账号密码导入交互并将导入类型严格限制为四段格式
- 交互优化:将账号标签选择器移至弹窗顶部,避免下拉列表向下展开时遮挡底部的'确定'/'导入'按钮
- 格式限制:严格限制仅允许'账号----密码----手机号----接码链接'四段格式导入
- 前后端校验:前端逐行校验格式并提示具体错误行号,后端限制 require_four_segments=True 兜底
2026-09-06 14:00:24 +08:00
yml2213 d3005478a9 feat(huya): 支持四段式账号导入接码及旋转/文本点选多级验证码闭环过验
- 账号导入:支持'账号----密码----手机号----接码链接'四段式解析与持久化存储
- 旋转验证码 (rotate_auth / xz):逆向分析官方协议,基于圆周边界采样互相关算法秒级计算旋转还原角度
- 文本点选验证码 (dx_auth):内置成语与古诗名句语料,支持题干菜名提取与古诗/成语挖空正则求解及小图动态合成
- 短信二次验证 (sms_auth2):结合 sms_url 自动轮询接码链接并 Hex 编码提交官方过验
- 前端交互:增加接码标签、在线查询短信验证码、一键自动短信登录与测试接码链接功能
- 回归测试:新增旋转验证、短信接码流与文本点选测试用例(173 passed)
2026-09-06 13:56:44 +08:00
yml2213 8309072120 统一推送前Python代码格式 2026-09-05 19:25:46 +08:00
yml2213 61eb434138 双份cookie存储:raw_cookie 保存App原始凭据,与网页运行ck分离
网页运行ck(cookie列)含本地随机生成的网页设备字段,若被风控标记
无法还原纯净登录凭据;新增 raw_cookie 保存16字段App原始态,供
设备态重建/审计/复核登录有效性。

- HuyaAccount 加 raw_cookie 列(alembic 0034,MySQL TEXT nullable)
- HuyaLoginResult 加 raw_cookie 字段;App登录链补齐前快照原始凭据
- upsert_huya_cookie 支持双写;app-password-login 路由透传 raw_cookie
- 存量行 raw_cookie 为 NULL(老账号无快照),新登录自动填充
2026-09-01 23:15:20 +08:00
yml2213 727c32a5f5 接入匿名设备态协议补齐Cookie字段并放宽保存 2026-09-01 19:29:56 +08:00
yml2213 48c37bb8d7 虎牙网页Cookie来源驱动合并与WSS传输门禁 2026-09-01 19:17:32 +08:00
yml2213 26514b332d 完成虎牙宝典WSS绑定与快照隔离重构 2026-09-01 12:40:22 +08:00
yml2213 90ce72fa15 隔离虎牙宝典批量任务WSS会话 2026-09-01 12:25:03 +08:00
yml2213 2fca1210bb 切换虎牙宝典活动任务到WSS会话 2026-09-01 12:23:43 +08:00
yml2213 aab84e0fb5 切换虎牙宝典开通任务到WSS会话 2026-09-01 12:20:58 +08:00
yml2213 eb065a7c77 接入虎牙精英宝典最新商城前置流程 2026-09-01 11:42:52 +08:00
yml2213 684e16a07a 重构虎牙精英宝典协议与支付状态链路 2026-09-01 11:31:15 +08:00
yml2213 955ba45488 虎牙精英宝典 2026-08-31 19:34:59 +08:00
yml2213 09ab80e062 完成 Ruff 全量清理 2026-08-31 10:55:44 +08:00
yml2213 b58c6b4357 执行 Ruff 安全自动修复 2026-08-31 10:28:14 +08:00
yml2213 47e19ed7b2 style: 统一 Ruff 代码格式 2026-08-30 21:04:52 +08:00
yml2213 c891ac982e type: 收敛测试 schemas 与协议层类型 2026-08-30 20:35:08 +08:00
yml2213 9a5066cae8 type: 收窄斗鱼手册与送礼执行器类型 2026-08-30 20:00:09 +08:00
yml2213 38fd809ca4 type: 收窄斗鱼鱼翅充值执行器类型 2026-08-30 19:58:43 +08:00
yml2213 2622e016b5 type: 收窄斗鱼商城与小店执行器类型 2026-08-30 19:57:37 +08:00
yml2213 d400db987e type: 收窄商城与斗鱼绑定执行器类型 2026-08-30 19:55:08 +08:00
yml2213 0efd84a281 type: 收窄虎牙绑定与充值执行器类型 2026-08-30 19:52:49 +08:00
yml2213 3b3a4bebcb feat(douyu): 代理写读分离 — 仅兑换/锁单/支付/开通/充值/送礼走代理
此前代理配置页开启后所有斗鱼任务(含查积分/刷列表等只读任务)统一走代理:
- API 模式每任务 fetch 新代理, 查询任务白白消耗代理额度
- 查询任务失败面被代理抖动放大, 但查询本不怕 IP 频控

新策略 (DOUYU_PROXY_TASK_TYPES 白名单):
- 写操作/消耗类: lock/pay/exchange_goods, exchange_esports/xpd_goods,
  create_elite/esports/gold_qr, donate_* 走代理 (静态模式或 API 每任务新代理)
- 读操作类: query_*/refresh_*/get_*_bind_qr 等始终直连, 不消耗额度
- 判型用批次 task_type (同批次同类型, 与任务一致); 总开关仍为代理配置页

测试: 新增读任务直连/白名单覆盖断言, 三模式行为断言保留, 101 单测通过
2026-08-30 11:28:10 +08:00
yml2213 b9eb944d2f refactor(huya): runner 按功能域拆分 Mixin
huya_runner.py (1664行) → core/bind/goods/recharge 四个 Mixin + 入口聚合:
- huya_runner_core.py: 批次状态/日志/任务落库/注册表 + 共用常量 sourceId
- huya_runner_bind.py: 绑定状态机/扫码确认绑定/轮询
- huya_runner_goods.py: 积分/兑换记录/商品刷新/兑换
- huya_runner_recharge.py: 充值商品/下单/到账轮询
- 对外 API 不变 (HuyaBatchRunner/huya_batch_registry), routers 零改动
- pyflakes 全净 (含 TYPE_CHECKING 注解/跨域常量导入修复), 99 单测通过
2026-08-30 11:25:35 +08:00
yml2213 9f743e50a6 fix(douyu): 补齐拆分后支付轮询常量导入 + 代理三模式断言测试
- douyu_runner_manual/gold: 导入 core 的 DOUYU_PAYMENT_POLL_* 常量
  (之前仅在 douyu_runner.py 单文件内可见, 拆分后到账轮询会 NameError)
- 新增 tests/test_douyu_runner_proxy.py: 静态/API/关闭三模式 + 降级直连 +
  activity_client session 级 proxies, 兑现 8fe9fdf 提交说明中的行为断言
2026-08-30 11:25:35 +08:00
yml2213 8fe9fdfd8b feat(douyu): 斗鱼任务接入代理 — 应对兑换 IP 频控 (精英手册火爆)
配置源 = 代理配置页 (与 CK 检测/虎牙注册同款), 开关在代理配置页:
- 静态模式: 手填 http/https → 全任务同一代理
- API 模式: 每任务取新代理 (ProxyFetcher, 白名单同步, 1.5s 间隔限速),
  失败降级直连并推送告警
- DouyuActivityClient 支持 proxies (session 级, 覆盖全部请求点;
  trust_env=False 维持不变, 不受环境变量影响)

按拆分后新结构落在 douyu_runner_core.py; 触及精英手册/和平小店/电竞等
全部斗鱼任务出网。三种模式行为断言 + 94 单测通过
2026-08-30 11:19:15 +08:00
yml2213 39b202bc3f refactor(douyu): runner 按功能域拆分 Mixin + 精英手册兑换对齐真机流程 (HAR 审核通过)
拆分: douyu_runner.py (-3186行) → core/bind/manual/gold/donate/goods/xpd 七个
Mixin + 入口聚合类, douyu_batch_registry 供 routers 重导出

精英手册兑换对齐 HAR 抓包 (activity_client +379 行):
- csrf 复用 Cookie 值不再每次 generateCsrf (HAR 实测全程零 csrf 请求),
  仅服务端报 csrf 错误时 force_refresh 重试一次
- pay Referer 补 roomId 对齐浏览器
- 新增手册链路接口: elite_user_info/storedetail/pre_exchange check+confirm/
  subscribe/batch_limit/赠品兑换/自动转换
- resolve_exchange_plan: 浏览器兑换按钮状态机路由 (normal/subscribe/
  pre_exchange/wait/blocked)
- 兑换执行: 人类节奏抖动 → 锁单(火爆重试1次) → 支付分级退避
  (频控 30/60/90s 4次上限, 普错 2/5/10/20s 5次上限, 300s 锁单期 15s 余量,
  可中断睡眠)

测试: 新增 17 项 (csrf 复用语义/状态机路由/Referer), 全量 94 通过;
未夹带代理改动
2026-08-30 11:05:18 +08:00
yml2213 6e17a575dd Revert "fix(douyu): 精英宝典兑换等斗鱼任务接入代理 — 此前全部裸连"
This reverts commit a05ae245bf.
2026-08-30 10:26:17 +08:00
yml2213 a05ae245bf fix(douyu): 精英宝典兑换等斗鱼任务接入代理 — 此前全部裸连
问题: DouyuBatchRunner/_client 创建的 DouyuActivityClient 无 proxies,
trust_env=False 下斗鱼任务(精英宝典兑换/和平小店/电竞/送礼等全部 45 个
请求点)直连本机出口 IP, 代理配置页形同虚设。

- activity_client: __init__ 支持 proxies (session 级, 一次覆盖全部请求)
- douyu_runner: 装载全局代理配置 (与 CK 检测/虎牙注册同源 代理配置页):
  · 静态模式: 配置页手填 http/https → 全任务同一代理
  · API 模式: 每任务从代理 API 取新代理 (ProxyFetcher, 含白名单同步,
    1.5s 最小间隔防打爆), 失败降级直连并推送告警日志
- 验证: 77 单测 OK; 三种模式(静态/API/关闭)行为断言通过
2026-08-30 10:25:16 +08:00
yml2213 22aa485536 fix(web): 审核回归 — 5 项修复 (渠道写入丢失/斗鱼WS生命周期/归属校验/恢复订阅/画像key稳定)
B1 routers/huya.py: 批量 Web 登录 login_channel/status 回填在 helper 内部 commit
   之后赋值且未再提交 → 丢失; 补 db.commit() 并统一 status=active
B2 routers/login.py + services/login_service.py: 斗鱼登录 WS 断线即 pop 批次,
   刷新后无法重连订阅 → 对齐虎牙模式 (BatchRegistry.mark_finished, 仅结束后清理)
B3 routers/login.py: WS 增加批次归属校验 (非 view_all 仅可订阅自建批次)
S1 LoginTasksPage: effectiveBatchId 从任务列表推导活跃批次, 刷新后停止按钮/
   日志订阅自动恢复
S4 services/huya_service.py: username 仅在为空时回填, 防止 udb_passport 覆盖
   登录名导致一号一设备绑定 key 漂移

验证: 77 后端单测 OK; tsc + vite build OK
2026-08-29 18:20:27 +08:00
yml2213 6ded82ac8b fix(douyu): reject invalid activity cookies 2026-08-28 15:51:59 +08:00
yml2213 9ee4e49a50 feat(douyu): support elite handbook lock orders 2026-08-28 14:06:11 +08:00
yml2213 bf2f78aa70 优化客服CK重登流程 2026-08-14 14:43:21 +08:00
yml2213 7fe6228901 增加充值审计日志 2026-08-14 11:52:30 +08:00
yml2213 e2a45b7893 优化斗鱼充值日志与配置 2026-08-14 11:27:53 +08:00
yml2213 0bf69c1240 优化斗鱼充值 2026-08-13 21:43:27 +08:00
yml2213 902e669614 功能: 接入鱼翅供应商直充渠道 2026-08-13 21:11:20 +08:00
yml2213 cf3fe68de3 功能: 按用户同步斗鱼工作台 2026-08-13 15:47:07 +08:00
yml2213 4c978b923b qq 登录修复 2026-08-12 19:45:15 +08:00
yml2213 5074faf9f6 优化了部分支付宝界面 2026-08-12 19:12:22 +08:00
yml2213 d19c0902f2 初步增加, 扫码登录成功 2026-08-12 16:22:55 +08:00
yml2213 ba35ac5c0d fix: preserve xpd role platform in wallet queries 2026-08-09 10:06:57 +08:00
yml2213 8b7ff770e2 fix: preserve xpd purchase records in task results 2026-08-08 21:56:39 +08:00