点歌延迟优化:终态失败不退避 + 上游 i.php token 缓存 + 后台预热 + 分阶段耗时日志(V1.6.3/46,未发布)
This commit is contained in:
@@ -195,10 +195,12 @@ $BT/apksigner verify 目标名.apk
|
||||
|
||||
### 版本号
|
||||
|
||||
- `app/build.gradle`:`versionName "1.6.2"` / `versionCode 45`
|
||||
- `app/build.gradle`:`versionName "1.6.3"` / `versionCode 46`
|
||||
(`1.5.5`/`37` 已发布;`1.5.6` = 更新源加 Gitee、`1.5.7` = 删除「歌曲源临时受限」弹窗、`1.5.8` = 精简远程日志、`1.5.9` = 按 HAR 对齐原版协议、`1.5.10` = 源列表只留 zk.ktv1.top:6677、`1.5.11`(命名越界,已改) / `1.6.0` = whoami 心跳/设备身份/点歌推送/带 query 的地址闸门 + 并入 selfhost-source 支线、
|
||||
`1.6.1`/`44` = App 接入自建源(自建源优先 / App 令牌 / 媒体允许清单 / 推送默认目标)、
|
||||
`1.6.2`/`45` = **取址反转成"官方源优先、自建源兜底" + 只有官方源成功才上报**(含 6 条隐患修复与死代码清理),以上 1.5.6~1.6.2 均尚未发布。18~21 曾被本机临时诊断包占用)
|
||||
`1.6.2`/`45` = **取址反转成"官方源优先、自建源兜底" + 只有官方源成功才上报**(含 6 条隐患修复与死代码清理)、
|
||||
`1.6.3`/`46` = **点歌延迟优化**(终态失败不退避 / 上游 i.php token 缓存 / 后台预热 / 分阶段耗时日志),
|
||||
以上 1.5.6~1.6.3 均尚未发布。18~21 曾被本机临时诊断包占用)
|
||||
- App 内显示统一用纯版本号(不加 `(versionCode)` 括号)
|
||||
- ⚠️ **本机 `/tmp` 是 tmpfs,单测必须绕开它**:`/tmp`(5.6G tmpfs)长期被"已删除但仍被打开"的
|
||||
文件占满,单测写临时文件会抛 `IOException: 超出磁盘配额`(EDQUOT),**看起来像测试失败**。
|
||||
@@ -354,6 +356,34 @@ $BT/apksigner verify 目标名.apk
|
||||
`SongUrlResolver.sawForbidden` 同口径)。
|
||||
6. `KTV_BRIDGE_API` 由 14 → **15**(`ktv_api.js` 两处 + `KtvJsBridge` 两处校验;
|
||||
本次同时把 JS 的取址结果用 `android.onSongSource(requestId, host)` 带回命中的源)。
|
||||
- **⚠️ 点歌延迟优化(2026-10-15,V1.6.3/46)**:用户实测"点歌后 3~5 秒才发出取址请求"。
|
||||
根因是**关键路径上排了一串与"点哪首歌"无关的一次性开销**,其中最狠的一条是 JS 里
|
||||
**终态失败也固定 `sleep(3000)` 再重试一次**(官方源按出口 IP 限流后,每首歌都要白等 3 秒)。
|
||||
约定(改动这几处时必须同时守住):
|
||||
1. **首次请求零等待,退避只用于"还值得再试一次"的失败**:`ktv_api.js` 的
|
||||
`isTerminalFailure(httpStatus, code)`(HTTP 4xx / 业务码 403 / 404)→ **不退避、不重试**,
|
||||
直接 `demoteSource` 换下一个源;只有广告/错号资源、HTTP 5xx、异常才退避
|
||||
`RETRY_BACKOFF_MS`(800ms,原 3000ms)重试一次。`KTV_BRIDGE_API` 15 → **16**。
|
||||
2. **上游 `/i.php` token 按 host 缓存**:`SourceTokenCache`(纯 JVM,有单测),
|
||||
TTL 取源站响应里的 **`heart_time`**(实测 5400 秒),拿不到用 90 分钟安全默认;
|
||||
**同一 host 单飞**(同时只发一次),失败 30 秒短冷却。原生兜底 `SongUrlResolver` 必须走它
|
||||
—— 以前每首歌、每个源都重打一次 `/i.php`。
|
||||
3. **App 令牌(`/token`)按 host 单飞**:`AppTokenSession` 的网络 I/O 只在**本 host 的门闩**里做
|
||||
(以前在全局锁里,一个慢源会把其它源的取令牌一起卡住)。
|
||||
4. **预热 `SourcePreheat`(纯逻辑 `Preheat`)**:App 启动 / JS 桥就绪 / 进入点歌列表 / 回前台 /
|
||||
网络恢复时调用 `SourcePreheat.kick(reason)`,在**专用守护线程**(不占 io 池)里预热
|
||||
① JS 会话(`window.api` + 各源 `/i.php`)② 原生 `api.php` 配置 ③ 各源 `/i.php`(TTL 缓存)
|
||||
④ DNS+TCP(+TLS)(按 host 60 秒节流)⑤ 各源 `/token`。
|
||||
硬约束:**不阻塞 UI**、**同一时刻只跑一轮**、同一 reason 20 秒节流、**失败只写 `MiliLog.local`**。
|
||||
5. **`api.php` 不再走取址关键路径**:`SongUrlResolver.resolveSourced` 只用**已预热到**的配置;
|
||||
请求由 `preheatConfig()` 在后台做(失败仍进 30 分钟负缓存)。
|
||||
6. **分阶段耗时日志**:`SongFetchTrace`(纯 JVM)以点歌编号为键记 `FETCH-TIME 编号=… 阶段=… 自点歌=…ms`,
|
||||
**只写本地**(`MiliLog.local`);JS 侧同格式由 `_timing()` 输出(桥把点歌时刻注入
|
||||
`window.api.__orderAt`,因此量的是"点歌→该阶段"而不是"JS 开始跑之后")。
|
||||
⚠️ 新增阶段日志必须继续走本地,不要上远程(AGENTS「过程写本地」)。
|
||||
7. **`KtvJsBridge.getSongUrl` 的配置注入与 `window.api` 构造收敛到一处**
|
||||
(`apiBootstrapJs`,取址与预热共用):以前预热要再抄一份,必然漂移。
|
||||
取址路径上读设置只允许**一次** `KtvStore().load()`(`sourceConfigForJs()`)。
|
||||
- **⚠️ 原版协议对齐(2026-10-08,依据 HAR 抓包实测)**:抓包(Reqable,`e.ac19.cn`)显示原版客户端是**三步**:
|
||||
1. **`POST /api.php`**:`Content-Type: application/x-www-form-urlencoded`,
|
||||
body `action=get_config&device_id=<mac>`,UA
|
||||
@@ -421,7 +451,7 @@ $BT/apksigner verify 目标名.apk
|
||||
旧实现在 `#fragment` 上会**整条文件名规则失效(漏放广告)**,拿整串搜 `wb66`/`demo`
|
||||
又会误杀 query 里的签名串("地址不可信"的隐蔽来源)。裸 IP / `pub-*.r2.dev/ss/`
|
||||
也已收进这道闸门 —— 四条路径不再各判一套。JS 侧同步改(`splitUrl()`),
|
||||
`KTV_BRIDGE_API` 已升到 **15**;回归用例见 `AdVideoFilterTest`(带 query/fragment 的
|
||||
`KTV_BRIDGE_API` 已升到 **16**(15 = 带 query 的地址闸门,16 = 点歌延迟优化);回归用例见 `AdVideoFilterTest`(带 query/fragment 的
|
||||
真源放行、广告仍拒)与服务端 `tests/test_basic.py::TestQueryStringGate`;
|
||||
3. **内容校验挡不住广告**:广告视频能通过 `SongFileValidator`(≥6MB / ≥60s / TS 包完整),
|
||||
所以"取址即校验"是唯一有效防线。一旦判定地址不可信,必须**同时删除已落盘的歌曲文件**
|
||||
|
||||
Reference in New Issue
Block a user