fix(multiple-subtitles): [PKG-MULTI-SUB-07] preserve inline timestamps and caption text

This commit is contained in:
Harvey Zhao committed 2026-09-13 11:50:50 +08:00
1 parent da64aae267
commit 7f226ff822
24 files changed
+8660 -132

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,49 @@
# PKG-MULTI-SUB-07 内嵌时间戳与显示层修复
九份历史实现已复现 `<00:02.000>` 被包装成字符串并输出 `<NaN:NaN.NaN>`。
本次保留数字 TimestampNode,处理顶层与嵌套节点,在有效的 VTT class 节点中承载
时间戳。解析树仍不可变,重复选择/reset 不积累包装;文本、标签和轨序的原回归保留。
私有 WrappedNode 现在与 CueNode 一样要求数字时间戳,编译负例从 8 项增为 9 项。
## 原生与自定义字幕层
直接输出有效时间戳后,Chromium 中的发布/候选核心都把 `<00:02.000>` 显示成文字。
这不是测试超时或资源加载失败,最初两个失败断言及截图/trace 已保留。
因此新增 caption.ts,在既有 subtitleAfterUpdate 事件后处理插件生成的专用标记。
- 原生 WebVTT 中的 `<c.artplayer-multiple-subtitles-timestamp>` 是合法 class 节点,
其中的数字时间戳仍解析为 processing instruction,cue.text 不被显示层修改。
- HTML 不会把 `<c.class>` 与 `</c>` 配对,后面的字幕可能成为该元素的子节点。
直接删除标记曾导致后文丢失;已通过真实浏览器复现并修正为移除前导时间指令、
将其余子节点移回父层。对应失败报告保留,最终断言检查前后文字。
- 不对整段文字做时间戳正则删除。仅处理专用标记中的前导指令,普通用户文字和
原有 `.art-subtitle-<name>` CSS 钩子保留。public cue.text 修改产生的字面量标签
有真实浏览器回归,清空/reset 后正常恢复原字幕。
- 注册的监听器由当前 lifetime 管理,失败/销毁时移除;已有资源测试改为检查所有
监听器集合为空。没有增加新公开选项、返回值或事件,不改变逐 cue 显示策略。
## 验证范围
纯测试覆盖开始/中间/末尾、多个毫秒时间戳、Unicode、嵌套标签、冻结树、重复选择
和重新解析有效 VTT;历史时间戳失败仍保持,不将候选修复覆盖进旧预期。
原生场景检查开头/中间/末尾三个 processing instruction、前后文字、红色样式、
字面量标签保留、清空/reset,以及原有 SRT、销毁/HTTP/Blob/视频切源场景。
通过源码/main/legacy 与发布/候选核心,在 Chromium/Firefox/Windows WebKit 重跑。
具体结果、编译器和输入指纹见[验证](../baselines/multiple-subtitles-timestamps.json)。
最终三入口各 37 项回归通过,本包 267 项通过;原生各 36 项,共 108 项通过,
原生 processing instruction 精确为 00:00:01.250、00:00:02.000、00:00:03.500。
完整 CI 2337 项通过(1987 单元、14 工程、336 基线),严格生产 TS 353 文件。
状态更新后 9 项元数据测试通过。显式 lint 无错误/警告,全量 lint 保留既有生成声明警告。
## 独立发现与后续边界
给字面量场景提供正常 `&lt;...&gt;` 输入时,vendor 生成了 `<;...>;`。九份历史实现
又复现 `&lt;`、`&gt;`、`&amp;` 的多余分号,新增 MULTI-SUB-ENTITY-01,由 05 处置。
本任务不改 vendor;最终字面量显示测试通过公开 cue.text 修改隔离显示层,明确不代表
该实体解码缺陷已修复。额外分号的初始六个浏览器失败记录保留。
04 的公开类型、完整旧核心/实体设备、实体解码、全部样式/编辑器和安装消费者仍待
后续任务。正常构建更新三个产物及 docs 副本;无新依赖、公开声明和版本变更。
本任务独立本地提交,不推送、不发布。回退恢复原 NaN 输出并移除显示监听器;
已发布失败基线及新发现记录仍可追溯。
+3 -2
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 223 项,范围 22 个包及工作区/示例。
状态:todo 89 / doing 14 / blocked 0 / done 120 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 88 / doing 14 / blocked 0 / done 121 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -220,7 +220,7 @@
| PKG-MULTI-SUB-02 | artplayer-plugin-multiple-subtitles<br>建立特有行为与错误测试 | PKG-MULTI-SUB-01, ENG-03, ENG-05 | VTT/SRT/ASS、编码/重叠 cue/排序/空轨/失败与切换 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
| PKG-MULTI-SUB-03 | artplayer-plugin-multiple-subtitles<br>整理内部职责与资源 | PKG-MULTI-SUB-02, CORE-15 | 解析与合并/获取/渲染分离,过期请求及对象 URL 清理 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
| PKG-MULTI-SUB-04 | artplayer-plugin-multiple-subtitles<br>迁移自有源码和公开类型 | PKG-MULTI-SUB-03, ENG-04, ENG-06, CORE-07 | 准确 parser/cue/tree/result 类型与真实异步形状 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | doing |
| PKG-MULTI-SUB-07 | artplayer-plugin-multiple-subtitles<br>修复字幕内嵌时间戳序列化 | PKG-MULTI-SUB-03 | 保留数字时间戳节点、修正无效 NaN 输出、明确旧/新字幕输出差异 | 旧九份实现可复现,候选有效内嵌时间戳及文字/CSS/原生字幕通过,公开工厂与选择接口不变 | H | todo |
| PKG-MULTI-SUB-07 | artplayer-plugin-multiple-subtitles<br>修复字幕内嵌时间戳序列化 | PKG-MULTI-SUB-03 | 保留数字时间戳节点、修正无效 NaN 输出、明确旧/新字幕输出差异 | 旧九份实现可复现,候选有效内嵌时间戳及文字/CSS/原生字幕通过,公开工厂与选择接口不变 | H | done |
| PKG-MULTI-SUB-05 | artplayer-plugin-multiple-subtitles<br>验证新旧核心和组合 | PKG-MULTI-SUB-04, CORE-22, PKG-MULTI-SUB-07 | 与核心字幕/偏移/全屏组合,旧名称调用不变 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-MULTI-SUB-06 | artplayer-plugin-multiple-subtitles<br>验证分发并同步文档 | PKG-MULTI-SUB-05, ENG-07 | multiple.subtitles.js、parser 来源许可及打包边界 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
@@ -516,6 +516,7 @@
- PKG-MULTI-SUB-02: [记录](baselines/multiple-subtitles-failures.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-02-failures.md)
- PKG-MULTI-SUB-03: [记录](baselines/multiple-subtitles-resources.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-03-resources.md)
- PKG-MULTI-SUB-04: [记录](baselines/multiple-subtitles-runtime-types.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-04-runtime-types.md)
- PKG-MULTI-SUB-07: [记录](baselines/multiple-subtitles-timestamps.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md)
- PKG-ADS-01: [记录](baselines/ads-release.json) [记录](baselines/ads-contract.md) [记录](baselines/ads-contract-validation.json) [记录](changes/2026-09-12-PKG-ADS-01-contract.md) [记录](scripts/ads-contract.test.mjs)
- PKG-ADS-02: [记录](changes/2026-09-12-PKG-ADS-02-tests.md) [记录](ads-validation.md) [记录](baselines/ads-validation.json)
- PKG-ADS-03: [记录](changes/2026-09-12-PKG-ADS-03-lifecycle.md) [记录](ads-validation.md) [记录](baselines/ads-lifecycle-validation.json)
+16
View File
@@ -1,5 +1,21 @@
# 进度与证据
## PKG-MULTI-SUB-07 内嵌时间戳与显示修复完成
修复数字时间戳被文本包装成 NaN;合法 VTT class 标记保留原生 processing instruction,
caption.ts 在既有事件后只展开专用标记,保留后续节点及用户文字,销毁移除监听。
覆盖顶层/嵌套、开始/中间/末尾、多个毫秒时间戳、冻结树和重复选择;私有类型不再
允许字符串时间戳。源码/main/legacy 各 37 项通过,本包 267 项通过,双 TS 编译器各
9 个负例准确拒绝。三入口原生各 36 项共 108 项通过,原生时间精确为 1.250/2.000/3.500 秒。
最初裸标签可见、删除标记丢后文及 vendor 实体分号问题均保留了实际失败报告。
时间戳修复后完整 CI 2337 项通过(1987 单元、14 工程、336 基线),严格生产 TS 353 文件。
正常构建/ESM 入口通过,dist/docs 副本一致;公开声明、依赖、版本和 vendor 源码未改。
TIMESTAMP 风险关闭;九份历史实体分号问题新增 ENTITY 风险,归 05 独立修复。
见[变更](changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md)和[验证](baselines/multiple-subtitles-timestamps.json)。
223 项:121 done、14 doing、88 todo;198 项风险。独立本地提交,不推送、不发布。
下一步继续 MULTI-SUB-04 公开声明/异步及旧模块消费者兼容;实体解码和完整设备组合仍待 05。
## PKG-MULTI-SUB-04 严格运行时 TS 检查点(doing)
五个自有模块迁为 TS,新增明确的 Option/Promise Result/Track/host/lifetime 类型;
+2 -1
View File
@@ -200,4 +200,5 @@
| MULTI-SUB-EXPORT-01 | open / 已复现 | Older CommonJS default objects conflict with export-assignment declarations; latest exports a direct factory | PKG-MULTI-SUB-04, PKG-MULTI-SUB-06 |
| MULTI-SUB-HTTP-01 | resolved / 已复现 | HTTP error responses with parseable bodies are installed as subtitles | PKG-MULTI-SUB-03, PKG-MULTI-SUB-05 |
| MULTI-SUB-HOST-01 | resolved / 已复现 | Subtitle init rejections are ignored and failed installation or URL replacement leaks or invalidates resources | PKG-MULTI-SUB-03, PKG-MULTI-SUB-05 |
| MULTI-SUB-TIMESTAMP-01 | open / 已复现 | Text wrappers replace numeric inline cue timestamps and serialize NaN times | PKG-MULTI-SUB-07, PKG-MULTI-SUB-05 |
| MULTI-SUB-TIMESTAMP-01 | resolved / 已复现 | Text wrappers replace numeric inline cue timestamps and serialize NaN times | PKG-MULTI-SUB-07, PKG-MULTI-SUB-05 |
| MULTI-SUB-ENTITY-01 | open / 已复现 | Vendored cue entity decoding retains semicolons after lt, gt and amp entities | PKG-MULTI-SUB-05 |
+31 -3
View File
@@ -4403,7 +4403,7 @@
"id": "MULTI-SUB-TIMESTAMP-01",
"title": "Text wrappers replace numeric inline cue timestamps and serialize NaN times",
"confirmation": "reproduced",
"status": "open",
"status": "resolved",
"owners": [
"PKG-MULTI-SUB-07",
"PKG-MULTI-SUB-05"
@@ -4411,10 +4411,38 @@
"evidence": [
"refactor/baselines/multiple-subtitles-runtime-types.json",
"refactor/changes/2026-09-13-PKG-MULTI-SUB-04-runtime-types.md",
"test/multiple-subtitles-failures.test.js"
"test/multiple-subtitles-failures.test.js",
"refactor/baselines/multiple-subtitles-timestamps.json",
"refactor/changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md",
"test/multiple-subtitles-merge.test.js",
"test/browser/multiple-subtitles-lifecycle.spec.js"
],
"compatibleResolution": "Preserve numeric timestamp nodes while retaining subtitle text, track wrappers and selection contracts; record the intentional repair of invalid legacy output.",
"closureCriteria": "Valid inline timestamps and surrounding text survive serialization and native subtitle playback; frozen historical failure remains reproducible and ordinary markup regressions pass."
"closureCriteria": "Valid inline timestamps and surrounding text survive serialization and native subtitle playback; frozen historical failure remains reproducible and ordinary markup regressions pass.",
"resolutionEvidence": [
"refactor/baselines/multiple-subtitles-timestamps.json",
"refactor/changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md",
"test/multiple-subtitles-merge.test.js",
"test/browser/multiple-subtitles-lifecycle.spec.js",
"packages/artplayer-plugin-multiple-subtitles/src/caption.ts"
],
"resolutionRationale": "Numeric timestamp nodes serialize inside valid VTT class markers, preserve native processing instructions, and are unwrapped only in the custom caption DOM without deleting subsequent text. Source/main/legacy tests, frozen-tree and timestamp cases, strict negative fixtures, and 108 native cases across both core fixtures pass. Public cue edits verify literal text preservation independently of the unresolved vendor entity bug."
},
{
"id": "MULTI-SUB-ENTITY-01",
"title": "Vendored cue entity decoding retains semicolons after lt, gt and amp entities",
"confirmation": "reproduced",
"status": "open",
"owners": [
"PKG-MULTI-SUB-05"
],
"evidence": [
"test/multiple-subtitles-failures.test.js",
"refactor/baselines/multiple-subtitles-timestamps.json",
"refactor/changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md"
],
"compatibleResolution": "Independently fix valid named-entity decoding, documenting the vendor patch and preserving provenance checks and ordinary cue behavior.",
"closureCriteria": "Nine historical implementations reproduce the defect; candidate entity/markup regressions and real subtitle display pass, with vendor adaptation and provenance documentation updated."
}
]
}
@@ -32,6 +32,6 @@ for (const compiler of [ts, runtimeCompat]) {
}
assert.deepEqual(diagnostics(false), [])
const rejected = diagnostics(true)
assert.equal(rejected.length, 8, JSON.stringify(rejected))
assert.equal(rejected.length, 9, JSON.stringify(rejected))
})
}
+5 -2
View File
@@ -2338,11 +2338,14 @@
"dependsOn": [
"PKG-MULTI-SUB-03"
],
"status": "todo",
"status": "done",
"risk": "H",
"deliverable": "保留数字时间戳节点、修正无效 NaN 输出、明确旧/新字幕输出差异",
"acceptance": "旧九份实现可复现,候选有效内嵌时间戳及文字/CSS/原生字幕通过,公开工厂与选择接口不变",
"evidence": []
"evidence": [
"baselines/multiple-subtitles-timestamps.json",
"changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md"
]
},
{
"id": "PKG-MULTI-SUB-05",