zijunchiang
|
4576a89f9a
|
按 HAR 抓包对齐原版协议: 补 api.php 取配置 + 识别业务码 403 + 按试用配额限源
依据用户提供的 HAR(e.ac19.cn, Reqable): 原版客户端是三步
1) POST /api.php action=get_config&device_id=<mac> (表单 + Dalvik UA)
2) GET /i.php 参数与 App 完全一致
3) GET /music/do.php 参数与 App 完全一致, 返回真源 CDN 地址
发现并修复三处差异:
1. 我们从未调 api.php(原版取址前必调)
→ KtvJsBridge.rawCleanPost(): 干净 POST + Content-Type 表单 + Dalvik UA
(UA 由本机 Build.VERSION.RELEASE/MODEL/ID 拼出, 与 HAR 同形态)
→ SongUrlResolver.ensureConfig(): 缓存 30 分钟, 桥不可用则跳过
→ SongApiClient 注入 POST 通道
2. 风控拒绝的真实形态是 HTTP 200 + 业务码 403
{"code":403,"msg":"请求被拒绝:检测到异常行为"} —— 不是 HTTP 403
→ i.php / do.php 两处业务码 403 都置 sawForbidden(诊断不再误判为"没有地址")
3. 无视试用配额: api.php 给出 trial_times=2 / trial_duration=5
→ 一次取址最多尝试 trial_times 个源(原先 9 个源全扫会把额度瞬间打光)
请求头分工与 HAR 一致: i.php/do.php 只有 Host+Accept 的干净 GET;
仅 api.php 带表单 Content-Type 与 Dalvik UA。
日志: 远程一条 SOURCE-CONFIG trial_enabled=… trial_times=…; 原始 JSON/卡密提示只写本地。
本机实测: api.php 返回与 HAR 相同配置; do.php 返回 code=403 检测到异常行为
(本出口 IP 处于风控/未授权: network_verification=true + 卡密机制, 额度按 IP 计)。
版本号按规则 3: 1.5.8(40) → 1.5.9(41); 按要求未打包
验证: compileReleaseKotlin + 单元测试(9 例全过)
|
2026-10-08 03:56:59 +08:00 |
|
zijunchiang
|
745a180258
|
精简远程日志: 每次事件一条汇总, 细节只留本地
- MiliLog 新增只写本地通道 local/localWarn/localError
(队列改为 Entry(local, remote), remote 为 null 即只写本地、跳过 HTTP)
- 本地日志文件改为纯文本 yyyy-MM-dd HH:mm:ss.SSS LEVEL text, 单行上限 4000
(远程仍按 900 截断) —— 本地是"详细记录", 要人能直接读
- 逐源/逐次日志全部改本地:
· SongUrlResolver: i.php/do.php 异常、token 失败、do.php code、HTTP 4xx/5xx、
响应非 JSON、冷却跳过、403 提示、广告示例 URL
· KtvJsBridge: JS 控制台转发(量最大)、单次 HTTP-<status>、NET-ERR
- 结果: 每次取址远程恰好一条
成功 NATIVE-SONG 取址成功… / 失败 NATIVE-SONG 全部源失败… / 全广告 SOURCE-BLOCKED…
(改前 9 个源逐个上报, 一次取址 9+ 条)
- 保留: JS-BRIDGE…(状态变化)、点歌失败…(每首一行)、SONG-AD…(广告拦截) 仍上报远程
- AGENTS: 写日志约定新增第 5 条(远程=结论、本地=过程), JS 日志规则改为只进本地
版本号按规则 3: 1.5.7(39) → 1.5.8(40); 按要求未打包
验证: compileReleaseKotlin + 单元测试(9 例全过)
|
2026-10-08 03:42:03 +08:00 |
|
zijunchiang
|
97ca1ae28e
|
V1.5.5: 加入源 a.ktv8.my;"所有源失效"改为明确弹窗提示
一、加入歌曲源 a.ktv8.my(置于 gz.ac16.vip 之后)
实测(代理修复后,DNS 直连真实 IP 20~42ms):
- 真实 IP 154.219.102.181 —— 与 w345.my **同一台服务器**(同一后台的兄弟入口);
- GET / → 200(917B,主机面板默认占位页);
- i.php → 200,170B,与其它 5 个入口响应**逐字节一致**:
code=200 / msg=ok / ordertype=0 / end_date=2026-10-05 14:58:21 / retry=5 / heart_time=5400,token 正常下发;
- 自身媒体路径 /<编号>.ts 与 /ad_files/my_ad_video.ts 均 404(138B,与 e.ac19.cn 的 404 逐字节相同)
→ 它不托管广告媒体;
- ⚠️ do.php 取址行为未能定性: 测试期间本机出口 IP(与门店设备同一个 188.253.112.231)
的配额被反复探测耗尽,表现为"成功一两次后长时间静默丢包"(与代码里记录的
trial_times:2 × trial_duration:5 吻合)。故置于次位,由运行时升降序自动调整。
KTV_BRIDGE_API 10 → 11(ktv_api.js 两处标记 + KtvJsBridge 两处校验)。
二、"所有源都取不到地址"给出明确提示
新增 Eac19WindowGuard.onAllFailed ← noteAllSourcesFailed(),由 SongUrlResolver.resolve()
在**本轮彻底失败**时调用(403 / 只返回广告 / 网络异常都算),弹窗文案:
「远程源已全部失效,等待新版本修复」
- 与既有的 onBlocked(风控 403 → "换公网 IP")常常同时触发,因此在 onBlocked 处理器里
用 lastAllFailedAt() 做 60 秒去重,不会同时弹两个框;两者均 15 分钟节流。
- 以前这里只有一句"无法生成下载地址"的 toast,用户看起来像界面没反应。
版本 1.5.4(36) → 1.5.5(37);签名证书不变。测试 9 例全通过。
|
2026-10-07 07:53:48 +08:00 |
|
zijunchiang
|
c1fd0fa319
|
V1.5.4: 新增可用源 gz.ac16.vip;修复"点歌失败不入下载列表";下载列表删除按状态区分
一、新增歌曲源 gz.ac16.vip(置于源列表首位)
实测(DoH 取真实 IP 154.222.26.244,绕开本机网关 fake-IP 干扰):
- i.php: HTTP 200,下发 token,end_date=2027-10-05(比现用镜像源的 2026-10-05 更晚);
- music/do.php: 对 7303235/7200188/8614960 分别返回各自不同的真源地址
(http://txog.ktvsky.com/.../<编号>.ts?token=... / http://download.origjoy.com/.../<编号>.ts?sign=...),
文件名均等于点歌编号;
- 这些地址能真实下载:HTTP 206 video/MP2T,逐曲内容各不相同,
TS 流同步字节按 188 字节对齐(41/43 包同步);
- 对照:其余 7 个入口对每首歌(含不存在的编号)统一返回同一段
https://wb66.cn/f/d/7b7c9/10188555.ts(广告/测试资源),主源 w.w345.my/i.php 直接 403。
因此把 gz.ac16.vip 加入源列表:ktv_api.js 的 CONFIG.HOSTS 与
SongUrlResolver.DEFAULT_HOSTS 各一处(均置于首位)。
⚠️ 边界:该域名**自己**的 /<编号>.ts 永远是同一段广告,所以它继续留在
AdVideoFilter.AD_HOSTS(媒体层拦截);广告黑名单只作用于"返回地址的 host",
不作用于"取址入口的 host",两者不可混淆,否则会误杀唯一可用源。
KTV_BRIDGE_API 9 → 10(ktv_api.js 两处标记 + KtvJsBridge 两处校验),保证设备热更新到新脚本。
二、修复"点歌失败时歌曲不出现在下载列表"
根因:DownloadTask 只在 onDownloadStart 里创建,所以"取址失败(无法生成下载地址)"这类
还没真正开始下载的失败**不会留下任何记录**,下载列表里什么都没有。
修复:downloadSong() 在**发起下载之前**就登记任务(状态「排队中」),
失败时由既有回调就地改成「失败:原因」,条目保留在列表里,可看原因、可重试、可清理。
三、下载列表删除功能(按状态区分语义)
- 有本地文件 → 「删除文件」(confirmDeleteLocalFile,同时清掉下载记录);
- 失败/进行中(无文件)→ 「移出下载列表」(confirmRemoveDownloadEntry):
只删记录 + stateDatabase.removeDownload,**绝不动任何歌曲文件**
(历史上"顺手清缓存"删光公放曲库的教训见 AGENTS);
- 「更多」菜单在下载列表内额外提供「移出列表」;
- SongListAdapter 的「更多」图标由装饰改为**可点/可聚焦**(遥控器可达,不再只能长按)。
版本 1.5.3(35) → 1.5.4(36);签名证书不变。测试 9 例全通过。
|
2026-10-04 00:04:20 +08:00 |
|
zijunchiang
|
96bad3bd68
|
V1.5.3: 远程日志不再静默失效(+本地日志文件);补 403 受限识别
现场两个问题分别定位:
一、"歌曲源全部失效" —— 已确认是**源站对该出口 IP 的授权/风控**,非客户端可修
- 实测(本机与设备同一出口 188.253.112.231):
· 主源 http://w.w345.my/i.php → **HTTP 403 Forbidden**(nginx 拦截页);
· 镜像源(desktok.top / mm.kk456.top / w.w345.my:66 / z.w345.my / b.sktv.top / w345.my)
返回 200,但对**每一首歌(含不存在的编号 1111111/9999999)都返回同一个广告/测试资源**
https://wb66.cn/f/d/7b7c9/10188555.ts;
· 换全新随机设备身份(mac/sn)结果完全相同 → 限制在**出口 IP** 层面,与设备无关;
· 7 host × ls=1~3 × (720/1080 × h265 0/1) 全组合探测:0 个真源;
· 旧的试用领取接口 api.php 已 **404**,App 无法自行领取窗口。
- 结论:源站侧无有效授权(i.php 的 ordertype=0、mwsLogin 的 license_box_count=0 /
license_duration=0 均指向此)。**需更换公网 IP 或与歌曲源服务方确认续订**。
我们拒绝这些地址是正确行为(否则就是 1.4.10 修过的"广告被当成歌曲播放")。
二、"手动更新数据库后远程日志失效" —— 数据库没问题,日志客户端有隐患,两者都已处理
- 实测新曲库 day=261003(md5 300AFD957BF332F02C17ED94A9F4E4CF,431,530,367 字节,
解压 1.01GB、69.5 万首): 用 App 的**真实 SQL**(SONG_SELECT/推荐/中文搜索/拼音搜索/
歌手检索/歌单/语种/歌手列表)逐条跑通 → **结构完全兼容,更新曲库不会破坏 App**。
- 日志侧修复(原来确实可能"静默失效"):
· MiliLog.init 改为**可重复调用并自动重启发送线程**(旧实现 `if (started.getAndSet(true)) return`,
线程一旦退出就永久不再发送且无任何迹象);
· sendLoop 整体加 catch(Throwable) 兜底,任何异常都不允许发送线程退出;
· 新增**本地日志文件** <存储根>/logs/ktv.log(>1MB 滚动为 .prev),
远程日志不可用时现场可直接取文件;启动打 APP-INIT 行给出路径;
· MiliLog.init 提前到 KtvApplication.onCreate,早于 MainActivity,早期崩溃也有日志。
- 补 403 识别: KtvJsBridge 的 403 判定从仅 /music/do.php 扩展到 /i.php 也认
(主源 i.php 就是 403);SongUrlResolver 记录本轮是否见过 403,全部失败且见过 403 时
同样走 Eac19WindowGuard 提示换 IP。
AdVideoFilter: 仅保留高区分度标记 wb66,去掉过于宽松的 demo(避免误伤真源 URL 里的随机 token)。
版本 1.5.2(34) → 1.5.3(35);签名证书不变。测试 9 例全通过。
|
2026-10-03 21:03:07 +08:00 |
|
zijunchiang
|
3b75717c81
|
V1.5.2: 识别"源站只发广告/测试资源"的新受限形态(歌曲源全部失效的真因)
用户报"歌曲源全部失效"。逐层实测结论:**不是代码 bug,是源站对该出口 IP 的授权窗口失效**。
实测证据(本机与设备同一出口 IP 188.253.112.231,设备 LAN 192.168.100.177/.83、本机 .203):
- i.php 仍认证通过: code=200 / end_date=2026-10-05 / ordertype=0 / retry=5;
- do.php 对**每一首歌**(包括不存在的编号 1111111、9999999)都返回**同一个**资源
https://wb66.cn/f/d/7b7c9/10188555.ts —— 而 wb66 正是代码里早就标注的广告/测试资源域名;
- 换全新随机设备身份(mac/sn)结果相同 → 限制记在**出口 IP** 上,与设备无关;
- 7 个 host × ls=1~3 × (720/1080, h265 0/1) 全组合探测:0 个返回真源;
- mwsLogin 返回 authorized:true,但 license_box_count=0 / license_duration=0(无有效授权额度)。
即状态从"能用"变成了"只发广告"(此前同一身份能拿到 txog.ktvsky.com / download.origjoy.com 的真源)。
我们拒绝广告地址本身是**正确**的(否则就是 1.4.10 修过的"广告被当成歌曲播放"),
所以用户看到的"全部失效"其实是"源站不再给真源 + 我们拒绝广告"的叠加结果。
修复(可操作化,避免用户只看到一句"无法生成下载地址"):
- SongUrlResolver 统计"全部源只返回不可信地址"这一形态,识别为授权窗口失效:
· 打 SOURCE-BLOCKED 日志(含示例 url,便于远程取证);
· 调用 Eac19WindowGuard.noteRiskBlocked() → 弹「歌曲源临时受限」提示,
明确告知"额度记在出口 IP 上、换设备无效",引导重启光猫/路由器更换公网 IP;
· 进入 3 分钟冷却(BLOCKED_COOLDOWN_MS):期间快速失败,避免继续冲击源站把限流拖更久;
拿到真源立即解除冷却。
- AdVideoFilter 的广告特征补上 wb66 / demo(与 JS 的 isDemoUrl 对齐,两条取址路径判定一致)。
- 提示文案补充"或对每首歌只返回广告/测试资源"这一新表现。
- 新增回归测试:用实测 URL https://wb66.cn/f/d/7b7c9/10188555.ts 锁住拦截行为。
- Eac19WindowGuard 文档补充两种受限形态。
现场恢复办法:更换公网出口 IP(重启光猫/路由器重拨)。已下载歌曲不受影响,可正常播放。
版本 1.5.1(33) → 1.5.2(34);签名证书不变。测试 9 例全通过。
|
2026-10-03 20:10:57 +08:00 |
|
zijunchiang
|
669766ba60
|
V1.4.10: 修复广告过滤失效(gz.ac16.vip 广告被当成歌曲下载播放)
现场事故(新设备 SM-S9180 / Android 16,WebView 正常 → 走 JS 取址):
277 JS [KtvApi] URL OK: 7303235 ls=1 via http://w.w345.my
278 点歌编号=7303235 标题=情歌(HD) 请求源=http://w.w345.my 状态=成功 urlHost=gz.ac16.vip
279 PLAY id=7303235 title=情歌(HD) src=local
即 gz.ac16.vip 的广告视频被当成歌曲下载、缓存并播放。
三处漏洞叠加:
1. ktv_api.js 的 isDemoUrl 不认识广告域名;且"ts 文件名与编号比对"用的是
/\/(\d+)\.ts/,只匹配纯数字名 —— my_ad_video.ts 这类非数字名字直接放行;
2. SongOkDownloadManager.buildDownloadUrl 的**成功分支完全没有广告校验**
(AdVideoFilter.isAdVideo 全项目只在"缓存地址"与"原生解析"两处被调用);
3. SongApiClient.fetchFromDb 只做 isLikelyDemoUrl(纯 IP / r2.dev),挡不住广告域名。
且**内容校验挡不住广告**: 该广告通过 SongFileValidator(≥6MB/≥60s/TS 包完整),
被 isDownloaded() 一直复用,广告会反复播。
修复(单一闸门,全链路把关):
- AdVideoFilter 新增 isTrustedSongUrl(url, musicno):非 http(s)、命中广告特征
(路径 /ad_files/、my_ad_video、**域名 *.ac16.vip**)、或 URL 里 .ts 文件名不等于
点歌编号 → 一律不可信。真源恒为 /<musicno>.ts(已实测 txog.ktvsky.com 与
download.origjoy.com 两个 CDN 域共 6 首全部相符)。
- 该闸门接入全部出入口: JS isDemoUrl(同步加固 + KTV_BRIDGE_API 8→9)、
SongUrlResolver.isValidSongUrl、SongApiClient.fetchFromDb、
以及最终兜底 SongOkDownloadManager.buildDownloadUrl(成功/缓存两条分支)。
- 判定不可信时**同时删除已落盘的歌曲文件**(purgeCachedSongFile),
否则 isDownloaded() 会一直复用那个广告文件。
- 新增 SongOkDownloadManager.purgeLegacySongCacheOnce(): 升级后一次性清理历史遗留的
可疑歌曲缓存(marker: filesDir/song_cache_purged_v1)。只是让歌曲重新下载,不动用户数据。
- 新增回归测试 AdVideoFilterTest(6 例,用日志里的真实 URL 形态,含两个真源 CDN 域);
该测试当场抓到本修复自身的一个 bug:正则把扩展名也捕获进去导致真源被误杀,已修正。
版本 1.4.9(29) 到 1.4.10(30);签名证书不变。
|
2026-09-26 21:17:04 +08:00 |
|
zijunchiang
|
906fa210e4
|
V1.4.8: 按现场日志复盘优化取址等待与远程日志(含 15 秒白等修复)
依据用户提供的 1.4.7 现场日志(21 行,5 次点歌全部成功)复盘出四点:
1. 【行为,最大】每次点歌白等 15 秒。
日志里每首歌前都有一条「JS-BRIDGE 15s 未就绪」,紧跟着「NATIVE-SONG 取址成功 用时=3xx~7xxms」——
即取址本身只要 0.3~0.7 秒,但用户从按下点歌到开始下载要等 15.7 秒。
原因: 桥一旦不可用,SongApiClient 每次都仍等满 15 秒。
修复: KtvJsBridge 新增「已判定不可用」状态(markUnavailable/isUnavailable),
首次判定后后续点歌直接走原生通道;桥万一恢复(热更新重载成功)自动清除该状态。
2. 【日志去噪】持久状态只记一次。
原来「15s 未就绪」按每次点歌一条 WARN 输出,一天几百条且无新增信息。
现在只在状态首次变化时记一条 ERROR。
3. 【可定位】补上"为什么不可用"。
旧日志里没有任何 KtvApi 未导出/WebView 初始化失败的行,说明 init 回调根本没触发。
KtvJsBridge.init 增加 20 秒看门狗: onPageFinished 未回调时明确上报
「初始化超时:onPageFinished 未回调或 KtvApi 未导出」;
init 异常与 KtvApi 未导出也统一收敛到 markUnavailable。
4. 【上下文完整】启动关键行不再有 undefined。
旧日志的 STORAGE 行 serverip/clientip/user/traceid 全是 undefined(记在设备上下文之前),
而且 AppPaths.storageFacts() 会真实建目录、写探针、读 /proc/mounts —— 却跑在主线程。
现在把 STORAGE 移入 reportDeviceBootInfo() 的后台线程、在 refreshLogDeviceContext()
与 MiliLog.awaitServerIp() 之后上报: 上下文完整且不再阻塞主线程。
5. 【新增状态样本】每 6 小时一条 HEALTH(版本/在线/可用空间/曲库是否存在及大小/根目录)。
日志此前只有事件没有状态样本,无法排查"随时间变化"的问题(空间变少、曲库丢失、长期离线)。
6. 【字段一致】「请求源=」不再为空: 走原生兜底时 JS 的 reportSongResult 不会触发,
现在 SongUrlResolver 记录 lastHost,SongApiClient.lastSongSourceHost() 依次回退。
AGENTS.md 增补「写日志的五条约定」(只记一次/上下文完整/不做重活/可自我定位/状态样本+事件)。
版本 1.4.7(27) 到 1.4.8(28);签名证书不变。ktv_api.js 未改动,KTV_BRIDGE_API 仍为 8。
|
2026-09-26 20:38:52 +08:00 |
|
zijunchiang
|
1687f87eca
|
V1.4.7: 新增原生取址兜底 —— 修复 WebView 不可用的老盒子无法点歌
证据(用户导出的 1.4.6 远程日志):
- 两条失败记录只有 Kotlin 侧那一行
「点歌编号=... 详情=无法生成下载地址」,
而 JS ...(本版新加的 console 桥)、RAW-ERR、NET-ERR、点歌失败 一条都没有。
- 即 JS 侧从未执行 —— 隐藏 WebView 在这台盒子上从未就绪
(每条失败前正好有约 15s 的「等桥就绪」超时,时间吻合)。
- 于是 SongApiClient 只能回退 DB 的 cloud_url,取不到就报「无法生成下载地址」。
根因: 取址完全依赖 WebView 里的 ktv_api.js;GMUI2.0/Android 5.1.1 上
WebView 不可用(无法导出 window.KtvApi),桥永远 not ready。
修复:
- 新增 SongUrlResolver: 用 Kotlin 复刻 ktv_api.js 的协议
(GET <host>/i.php 取 token → GET <host>/music/do.php 取地址),
镜像多源排序(失败源沉底)与 isDemoUrl 校验(wb66/demo/纯IP/r2.dev/ts编号不一致)。
- 走与 JS 完全相同的裸 Socket「干净请求」通道(KtvJsBridge.rawCleanGet),
请求特征一致故风控表现一致,且不依赖 WebView 是否就绪。
- SongApiClient.getSongDownloadUrl 三处回退点改为:
桥未就绪 / JS 未取到地址 / 主线程调用 → 先走原生解析,再回退 DB。
- 补齐桥的生命周期可观测性: WebView 初始化失败、KtvApi 未导出、
15s 未就绪 均写入远程日志(以前只在 logcat,这就是本轮一开始没有线索的原因)。
已用 App 的真实身份( mac=800b510bf4fd / sn=2d7bb4a7d7f7 / VER=2.0 )
从本机复现协议: i.php 200 → do.php code=200 且返回
http://txog.ktvsky.com/.../480p/7303235.ts (与点歌编号一致),
证明参数顺序与签名算法正确。
版本 1.4.6(26) 到 1.4.7(27);签名证书不变。ktv_api.js 未改动,KTV_BRIDGE_API 仍为 8。
|
2026-09-26 17:08:38 +08:00 |
|