From 570600d2f6ffd580a890e0b87dfa9843bf8dd8d0 Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Thu, 10 Sep 2026 17:56:31 +0800 Subject: [PATCH] docs(refactor): [DOC-05] establish refactor docs and per-task commits --- AGENTS.md | 18 + refactor/README.md | 54 + refactor/ai-workflow.md | 68 + .../changes/2026-09-10-DOC-05-task-commits.md | 33 + refactor/changes/TEMPLATE.md | 45 + refactor/compatibility.md | 58 + refactor/core-design.md | 52 + refactor/decisions.md | 40 + refactor/package-inventory.json | 954 +++++ refactor/packages.md | 65 + refactor/plan.md | 372 ++ refactor/progress.md | 61 + refactor/quality-contract.md | 68 + refactor/roadmap.md | 45 + refactor/scripts/plan.mjs | 122 + refactor/tasks.json | 3347 +++++++++++++++++ refactor/testing.md | 66 + refactor/toolchain-release.md | 56 + 18 files changed, 5524 insertions(+) create mode 100644 refactor/README.md create mode 100644 refactor/ai-workflow.md create mode 100644 refactor/changes/2026-09-10-DOC-05-task-commits.md create mode 100644 refactor/changes/TEMPLATE.md create mode 100644 refactor/compatibility.md create mode 100644 refactor/core-design.md create mode 100644 refactor/decisions.md create mode 100644 refactor/package-inventory.json create mode 100644 refactor/packages.md create mode 100644 refactor/plan.md create mode 100644 refactor/progress.md create mode 100644 refactor/quality-contract.md create mode 100644 refactor/roadmap.md create mode 100644 refactor/scripts/plan.mjs create mode 100644 refactor/tasks.json create mode 100644 refactor/testing.md create mode 100644 refactor/toolchain-release.md diff --git a/AGENTS.md b/AGENTS.md index 61b64c56a..c60215e9c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,23 @@ # AGENTS.md +## Compatibility Refactor + +The compatibility modernization plan is maintained in [refactor/README.md](refactor/README.md). +For refactor work, read its compatibility contract, task plan, and progress log before editing. +Use `refactor/tasks.json` as the task status source and regenerate the readable plan with +`node refactor/scripts/plan.mjs --write`; validate it with `node refactor/scripts/plan.mjs --check`. +Preserve existing public APIs, event behavior, types, DOM/CSS hooks, and distribution entrypoints. +The planned TypeScript migration permits incremental JS/TS coexistence; it does not authorize +changing consumer APIs or treating planned validation as completed validation. +Apply [refactor/quality-contract.md](refactor/quality-contract.md) to every implementation task: +the user authorizes improving unreasonable internals while preserving old public contracts. +Refactor responsibilities and dependencies alongside TypeScript migration, add meaningful +risk-based tests, and update package architecture/maintenance documentation in the same change. +The user requires one separate local Git commit for each completed refactor task. +Include the task ID in the commit subject and include its implementation, tests, documentation, +and status updates together. Verify the commit before starting the next task. Do not bundle +multiple newly completed tasks or include unrelated work. This does not authorize pushing or publishing. + ## Project Summary ArtPlayer is a monorepo for a modern HTML5 video player and its ecosystem packages. diff --git a/refactor/README.md b/refactor/README.md new file mode 100644 index 000000000..830c8638f --- /dev/null +++ b/refactor/README.md @@ -0,0 +1,54 @@ +# ArtPlayer 兼容性重构 + +本目录是核心、插件、proxy、工具和开发流程重构的长期工作记录。目标是让实现、类型、测试和构建更易维护,同时让已有用户继续使用原来的接口。 + +## 基线与范围 + +- 创建日期:2026-09-10。 +- 工作分支:`codex/compatible-modernization`。 +- 起点:`master`,`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。 +- 清点范围:22 个 workspace 包,包括核心、16 个插件、2 个 proxy、2 个工具、1 个文档站;另含 React/Vue 示例、浏览器 demo、构建和发布脚本。 +- 当前完成的是计划与文档基础设施,生产代码重构尚未开始。提交以任务 ID 对应的 Git 历史为准;本地提交不代表已推送或发布。 +- 本目录位于仓库根目录,避免被 `docs/` 的站点部署流程直接作为产品文档发布。 + +## 从哪里开始 + +| 文档 | 用途 | +| --- | --- | +| [完整执行计划表](plan.md) | 每一步的固定 ID、依赖、具体交付物、验收条件、风险及状态 | +| [全项目质量要求](quality-contract.md) | 用户确认的自主改造范围、文件拆分、AI 维护文档和有效测试的共同验收条件 | +| [阶段路线](roadmap.md) | 执行顺序、里程碑、范围和阶段出口 | +| [兼容性契约](compatibility.md) | 不可静默改变的接口、行为、类型、样式与包分发约定 | +| [核心设计](core-design.md) | 核心各模块的目标职责、迁移方式和生命周期设计 | +| [包迁移规范](packages.md) | 全生态统一流程、组合矩阵及包特有风险 | +| [测试与验收](testing.md) | 测试层次、浏览器/消费者矩阵、证据和回归门槛 | +| [工具链与发布](toolchain-release.md) | TypeScript、Bun、构建、版本管理和发布回退 | +| [AI 协作流程](ai-workflow.md) | AI 接续工作、任务边界、验证、记录和交接模板 | +| [架构决策](decisions.md) | 已选方向、待验证方案及被拒绝方案 | +| [进度与证据](progress.md) | 本次会话结果、阻塞、下一步;不重复维护每个任务状态 | +| [变更记录模板](changes/TEMPLATE.md) | 每次行为/类型/结构变化的详细记录 | +| [任务数据](tasks.json) | 任务状态和依赖的唯一数据来源 | +| [包基线](package-inventory.json) | 包版本、入口、声明、源码清单及对应 demo 的初始快照 | + +## 维护规则 + +1. 任务状态只修改 `tasks.json`;运行 `node refactor/scripts/plan.mjs --write` 更新计划表。 +2. 运行 `node refactor/scripts/plan.mjs --check` 检查任务 ID、依赖环、包覆盖、完成证据、本地文档链接和生成表同步。它检查链接文件存在,不验证网页可用性或 Markdown 标题锚点。 +3. 开始前选择一个依赖已完成的任务。拆分任务时保留旧 ID 的历史,不复用 ID。 +4. 有实现变更时,在 `changes/` 创建记录,补充基线、测试证据、兼容差异和回退方式,再将任务标为完成。 +5. 当前源码、已发布包、声明和文档有冲突时,先登记差异;不得把其中任何一个自动当作全部用户行为的唯一依据。 +6. 修改架构方向时更新决策记录;完成会话时更新 `progress.md` 的下一步。 +7. `package-inventory.json` 是初始基线,保留不覆盖。未来新增/删除包需独立记录范围变更,并扩展校验器识别新基线。 +8. 每完成一个任务,立即单独提交一个本地 commit,提交信息包含任务 ID;对应实现、测试、文档、任务状态和生成表同次提交。确认提交成功后再开始下一任务,不累计多个已完成任务后统一提交。 + +## 状态和风险 + +- `todo`:尚未开始;`doing`:执行中;`blocked`:有明确阻塞;`done`:有验收证据;`deferred`:明确延期并登记影响。 +- 风险 `L/M/H` 分别表示低、中、高兼容风险,不是工期。高风险步骤必须先有行为基线和回归用例。 +- 不给所有任务承诺日历工期。先完成一个小插件试点,再按实际实现、浏览器验证和审查成本估算批次;AI 生成速度不等于验证速度。 + +## 重构完成的定义 + +完整计划内任务都有结论,22 个包均有迁移及兼容证据,旧调用样例无需修改即可通过,发布包与目标浏览器验证通过,已知差异有处理结论,文档、源码、声明和构建产物保持一致。外部 SDK、真机或旧版本验证缺失时,明确保留阻塞,不能用 mock 通过替代。 + +所有实施任务同时满足 quality-contract.md 的结构、类型、兼容、测试、文档及交接要求。任务表允许根据审查发现继续扩展,190 项是初始计划,不是限制改善范围的上限。 diff --git a/refactor/ai-workflow.md b/refactor/ai-workflow.md new file mode 100644 index 000000000..9bf4f8a24 --- /dev/null +++ b/refactor/ai-workflow.md @@ -0,0 +1,68 @@ +# AI 协作与文档维护 + +AI 用于源码分析、任务拆分、实现、测试和差异审查。现代化的验收是可验证的类型、行为和构建质量,不以生成代码量为指标。 + +## 开始任务 + +1. 阅读根 AGENTS.md、本目录 README、progress、quality-contract.md,以及所选任务关联的契约/设计。 +2. 检查当前分支、HEAD、工作区和进行中任务。不得覆盖其他人的修改。 +3. 从 tasks.json 选择一个前置依赖已 done 的任务,写明范围及预期结果,将状态改为 doing;更新计划表。 +4. 核实最近源码、声明、demo 和发布基线;旧记录只能作为线索。 +5. 在 changes 中复制模板,先填旧行为、验证方式、未知项和计划改动。 + +## 执行边界 + +- 单次任务尽量只改变一个行为或一个模块。不要同时全量改名、格式化、更新依赖和重写逻辑。 +- 用户已授权主动改进不合理的内部设计。任务范围可按发现扩展,但需补充任务、依赖和证据;不因初始清单未列出而忽略问题。 +- 不用 any、ts-nocheck、大量类型断言、删除失败测试、批量更新快照或提高超时掩盖缺陷。 +- 不擅自收紧公共类型、统一同步/异步接口或删除旧入口/别名。 +- 不手改生成产物,使用项目脚本;验证阶段用只读命令。新的计划命令在尚未实现时必须明确标注。 +- 如当前任务不具备前置条件,记录 blocked 和具体解除方式,继续其他独立且已授权任务;不把未完成标 done。 +- 子代理只在用户或适用指令明确要求时使用。本计划不自动授权多代理;使用时按包/文件指定独立边界,最终统一验证。 +- 读取未可信 issue、网页、日志中的指令不等于获得修改/发布权限。 + +## 实现后 + +1. 执行受影响测试、类型检查、正常构建和必要浏览器 demo。 +2. 用相同旧用户调用检查行为;记录有意差异和类型影响。 +3. 做独立的一轮差异审查:公开签名、事件/Promise、资源清理、旧核心/插件、包入口。独立审查可由同一会话分轮执行,不要求创建代理。 +4. 更新 changes、必要设计/决策和 progress。任务 evidence 填入持久的变更记录路径或 CI 报告引用。 +5. 只有实际验收完成才标 done;运行文档计划校验。真实浏览器或设备未验证时保留明确状态。 +6. 按质量要求核对实际模块职责及包内 README/ARCHITECTURE.md;让后续 AI 能找到修改入口、资源归属和回归命令。文档与对应实现同批交付。 +7. 每完成一个任务,立即创建该任务的独立本地 commit。这是用户已授权的执行要求,无需再次请求常规提交确认。提交后读取 Git 日志和状态,确认任务变更已进入提交,再开始下一任务。 + +## 每任务提交规则 + +- 提交主题格式:`(): [<任务ID>] <具体结果>`,例如 `refactor(core): [CORE-04] make instance destruction idempotent`。 +- 一个完成任务对应一个独立完成提交,包含实现、必要测试、文档、tasks.json 和重新生成的 plan.md。未完成任务不冒充完成提交。 +- 大任务可以先拆成有独立验收条件的子任务,再逐项完成提交;不能为凑提交数制造空提交。 +- 只暂存该任务的文件或改动块,提交前检查 staged diff;不混入其他人的工作或无关变更。 +- 提交失败则任务还没有完成交付:解决具体错误,或恢复 doing/blocked 并记录原因;不得跳过 Git hooks 或忽略失败继续下一任务。 +- 在变更记录中保存任务 ID 和提交主题,通过 Git 日志追溯 SHA;在向用户交付时报告实际 SHA。不要求把当前提交自身的 SHA 写进同一提交,避免循环追加记录提交。 +- 不自动 amend/squash 已完成任务的历史。用户之后发现的问题另记修复任务并提交,除非用户明确要求重写。 +- 本地 commit 已获授权;push、merge、tag 和公开发布仍按用户明确授权执行。 +- 新规则生效前已完成但未提交的 DOC-01 至 DOC-04 文档,作为 DOC-05 的初始文档基线一次入库,记录真实情况,不伪造之前存在的提交。 + +## 后续任务提示模板 + +```text +执行 refactor/tasks.json 中的 <任务ID>。 +先读取 AGENTS.md、refactor/README.md、progress.md 和关联契约。 +只修改任务范围;保留旧 API、事件、样式、入口及同步/异步行为。 +先复现和建立基线,再实现并验证。记录真实证据、限制和回退方式。 +更新任务状态、计划表和进度,不要把计划中的检查当成已通过。 +任务验收通过后立即创建包含任务 ID 的独立本地 commit,并验证提交成功。 +推送、合并和公开发布按本次会话的授权范围执行。 +``` + +## 文档分工 + +| 信息 | 唯一维护位置 | +| --- | --- | +| 任务状态、依赖、交付物、验收条件 | tasks.json,plan.md 由脚本生成 | +| 初始包清单、版本和入口 | package-inventory.json,新增范围另记决策 | +| 跨任务架构选择 | decisions.md | +| 一次改动的旧/新行为、测试、回退 | changes 下独立文件 | +| 最近结果、环境、阻塞和下一步 | progress.md | + +不要把临时讨论复制成多个相互矛盾的状态表,也不要把计划文档当作持久记忆文件写入用户的全局 memory。 diff --git a/refactor/changes/2026-09-10-DOC-05-task-commits.md b/refactor/changes/2026-09-10-DOC-05-task-commits.md new file mode 100644 index 000000000..17b220ac5 --- /dev/null +++ b/refactor/changes/2026-09-10-DOC-05-task-commits.md @@ -0,0 +1,33 @@ +# DOC-05 文档初始化与每任务独立提交 + +- 日期:2026-09-10。 +- 分支:`codex/compatible-modernization`。 +- 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。 +- 提交主题:`docs(refactor): [DOC-05] establish refactor docs and per-task commits`。 +- 关联决策:ADR-007、ADR-013、ADR-014。 + +## 问题与变化 + +此前已创建分支和规划文件,但没有规定每任务完成后必须提交。用户明确补充:每完成一个任务就创建一个 commit。 + +现在根 AGENTS.md、README、AI 流程、质量验收和变更模板都要求:任务通过验收后,包含任务 ID 的独立提交同时保存实现、测试、文档和状态;核实提交成功后才能开始下一任务。失败不能当作已完成交付。推送和发布未被这项授权涵盖。 + +DOC-01 至 DOC-04 在新规则前已经完成,文件尚未进入 Git。本次 DOC-05 将这些已有文档作为初始基线一并入库;不伪造更早的独立提交。之后新增完成的任务各自提交。 + +## 范围与兼容 + +仅 AGENTS.md 与 refactor/。没有修改生产代码、公开声明、依赖或构建产物。新增任务规则不改变浏览器用户的行为。 + +## 验证与追溯 + +- `node refactor/scripts/plan.mjs --write`:生成 191 项计划。 +- `node refactor/scripts/plan.mjs --check`:检查任务、依赖、22 包、链接与生成同步。 +- `node --check refactor/scripts/plan.mjs`:语法检查。 +- `git diff --cached --check`:提交内容格式检查。 +- 提交后使用 `git log -1 --format='%h %s'` 与 `git status --short` 核对实际提交和工作区。 + +SHA 通过上述提交主题在 Git 历史中追溯;在同一提交中写自身 SHA 会导致循环修改,因此不在这里预填。生产测试不适用于本次纯文档初始化,前期诊断仍单独列在 progress.md。 + +## 回退与下一步 + +必要时独立回退本次文档提交,不影响生产实现。下一项为 BASE-01,必须在 DOC-05 本地提交成功后开始。 diff --git a/refactor/changes/TEMPLATE.md b/refactor/changes/TEMPLATE.md new file mode 100644 index 000000000..55a93e8cf --- /dev/null +++ b/refactor/changes/TEMPLATE.md @@ -0,0 +1,45 @@ +# <任务 ID> <变更主题> + +## 范围 + +- 日期、分支、基线 SHA、关联任务: +- 修改模块、受影响包和消费者: +- 关联兼容契约和 ADR: +- 完成提交主题(包含任务 ID;SHA 通过 Git 日志查找): + +## 旧行为与证据 + +源码、声明、发布包和文档分别记录;提供最小用户调用或复现步骤。标明已复现与待验证。 + +## 改动与理由 + +记录最终方案、内部职责变化、资源所有者、错误/取消/事件语义。必要时解释放弃的备选方案。 + +## 兼容评估 + +| 范围 | 原行为 | 新行为 | 兼容结论/例外 | +| --- | --- | --- | --- | +| JS API | 待填 | 待填 | 待填 | +| TypeScript | 待填 | 待填 | 待填 | +| 事件/Promise/生命周期 | 待填 | 待填 | 待填 | +| DOM/CSS/插件集成 | 待填 | 待填 | 待填 | +| 发布入口和资源 | 待填 | 待填 | 待填 | + +## 验证 + +| 命令/用例 | 环境与产物 SHA | 结果 | 持久报告/证据 | +| --- | --- | --- | --- | +| 待填 | 待填 | 未运行 | 待填 | + +记录失败、跳过、真实浏览器/设备未验证项,不把没有运行的检查写成通过。 + +## 发布与回退 + +版本影响、兼容别名/适配、依赖范围、回退提交/旧版本、是否需要重新生成产物。 + +## 结论与后续 + +是否满足本任务验收、阻塞、后续任务 ID、文档更新。按实际证据更新 tasks.json,模板自身不能作为完成证据。 +验收后将本任务的实现、测试、文档和状态单独提交,核实实际 SHA;提交失败时不能报告交付完成。 + +同时对照 quality-contract.md,记录职责拆分、已处理的不合理设计、包内实现地图、风险对应测试和后续 AI 修改入口。无法适用的项目说明原因,不机械打勾。 diff --git a/refactor/compatibility.md b/refactor/compatibility.md new file mode 100644 index 000000000..1ef656ef5 --- /dev/null +++ b/refactor/compatibility.md @@ -0,0 +1,58 @@ +# 兼容性契约 + +兼容目标是已有合法用法继续工作,包括 JS 调用、TS 编译、事件时序、插件集成、页面样式和分发方式。不能仅比较公开方法名。 + +## 基线来源 + +BASE 阶段必须同时采集:本分支起点源码、实际 npm 已发布 tarball、CDN/script 用法、官方 demo、历史声明及可获取的代表性第三方插件。当前 package.json 的版本不等于已验证的 npm 内容。历史支持窗口在 BASE-01 中按已有声明、文档、使用情况决定,不在计划中虚构“所有历史版本都支持”。 + +| 编号 | 契约 | 必测内容 | +| --- | --- | --- | +| API-01 | 构造与配置 | `new Artplayer(option, ready)`、默认值、合并方式、container、useSSR、调用 this | +| API-02 | 属性与方法 | 可读/可写、同步返回值、Promise 结果和拒绝、可抽取方法的绑定行为 | +| API-03 | 属性描述符 | 实例自身属性与原型属性、enumerable/configurable/writable、getter/setter、静态字段 | +| API-04 | 事件 | 名称、参数、调用上下文、订阅顺序、once/off、重复触发、重入和异常传播 | +| API-05 | 生命周期 | ready/restart/destroy、销毁顺序、removeHtml、互斥、重复销毁、初始化失败 | +| API-06 | 插件注册 | 工厂及返回函数、同步/异步结果、注册名称、重名行为、静态 icons/version 等已有属性 | +| API-07 | 生态集成 | template/controls/setting/layers/contextmenu/events/utils、动态实例扩展、proxy | +| API-08 | DOM/CSS | 模板节点、CSS 类名与变量、全屏/PiP 后节点归属、样式注入时机、用户覆盖样式 | +| API-09 | 包分发 | main/module/exports/types/typesVersions、UMD/AMD/global/require/ESM、legacy、i18n 子路径、历史文件名 | +| API-10 | 浏览器能力 | 保留当前目标语法和能力降级;语法 es2015 不等于补齐所有浏览器 API | +| API-11 | TypeScript | 默认与命名导出、参数推导、模块扩展、第三方消费、已声明的最低 TS 版本 | +| API-12 | 持久状态与协议 | storage key/数据格式、跨窗消息、媒体 URL 语义、worker 消息、公开回调 | + +## 差异的处理规则 + +| 情况 | 处理 | +| --- | --- | +| 内部重排、无可观察变化 | 原样保留契约,增加回归测试 | +| 已公开且正在使用的功能 | 兼容门面转发,保持入口、返回值和时序;不能要求所有调用方改代码 | +| 源码与声明不一致 | 分别记录运行时和 TS 用户影响,先加精确重载或扩展类型;无法兼容时标为待决,不能静默收紧 | +| 文档描述了未实现的行为 | 核实发布包和使用样例,独立修复或明确记录;不把错误描述当作重构任务直接实现 | +| 明确缺陷 | 建立复现、比较旧行为、记录修正差异和发布级别,避免为通过差分测试而永久保留缺陷 | +| 无法验证的历史路径 | 标记缺证据及影响,不能计入兼容通过 | + +## 核心特殊边界 + +- `plugins.add` 不能简单统一成 async;同步插件的同步可见性、返回结果需要保留。 +- `play()` 的拒绝不能被公共接口静默吞掉;内部触发播放与外部调用分开验证。 +- 保持 `switchUrl` 与 `switchQuality` 的播放位置和恢复行为。并发切源的取消/过期策略先用决策记录明确;新增拒绝可能造成未处理异常。 +- 保持 `Artplayer.instances`、公开静态常量、`Emitter`、`utils`、默认导入时样式和 global 副作用。 +- 核心 Emitter 不直接替换为 EventTarget;链式返回、ctx 和 once/off 语义不同。 +- 原生 video 与 canvas shim 的内部类型可以分开,但不能强制所有用户把 `art.video` 调用改为新接口。 +- 不因类型严格化删除插件扩展字段,也不通过全局 `[key: string]: any` 掩盖全部类型问题。 + +## 新旧版本组合 + +| 核心 | 插件 | 要求 | +| --- | --- | --- | +| 发布基线 | 发布基线 | 基线用例可运行,记录历史缺陷 | +| 重构核心 | 未改旧插件 | 主要兼容门槛,所有本仓库旧插件与代表性第三方插件验证 | +| 旧支持范围核心 | 重构插件 | 保留原支持范围,或在插件内部使用能力检测与 fallback;不得意外依赖新核心方法 | +| 重构核心 | 重构插件 | 完整功能、组合、清理及类型验证 | + +任何内部共享能力如果被插件运行时使用,必须证明旧核心可用;否则放在插件内部或提供兼容实现。不能为减少源码重复悄悄增加消费者安装依赖或最低核心版本。 + +## 变更登记 + +每项差异使用 `changes/YYYY-MM-DD-任务ID-主题.md`,写明 API 编号、旧/新示例、受影响消费者、测试、发布策略和回退方式。未经评估的公开接口差异阻止任务完成;需要用户选择的产品行为在 progress 中明确列出。 diff --git a/refactor/core-design.md b/refactor/core-design.md new file mode 100644 index 000000000..c2d71e667 --- /dev/null +++ b/refactor/core-design.md @@ -0,0 +1,52 @@ +# 核心目标设计 + +这里是迁移方向,不是已经实现的目录或接口。实际路径调整需随实现更新。核心仍是 `packages/artplayer`,对外仍是 Artplayer 类和既有实例/静态接口。 + +## 现状证据 + +- [入口](../packages/artplayer/src/index.js)顺序构造所有子系统;[player](../packages/artplayer/src/player/index.js)通过 mixin 将属性安装到 art。 +- [Component](../packages/artplayer/src/utils/component.js)负责控件缓存、DOM 和监听器;[Setting](../packages/artplayer/src/setting/index.js)还有独立的树、渲染和更新语义。 +- [Events](../packages/artplayer/src/events/index.js)集中管理一部分 DOM 监听器,但定时器、异步请求和内部 Emitter 订阅仍由各模块管理。 +- [声明](../packages/artplayer/types/artplayer.d.ts)与源码独立维护;[build-ts](../scripts/build-ts.js)进行文本拼接。 + +## 目标职责 + +| 领域 | 现有文件范围 | 目标与迁移方式 | +| --- | --- | --- | +| 公共门面 | src/index.js、player/*Mix.js | 保留原签名和属性描述符;委托内部服务,不一次性换继承结构 | +| 配置 | option、scheme、config、默认值 | 区分用户输入与归一化配置;保持默认值、合并语义和错误时机 | +| 生命周期 | constructor、destroy、Events、各模块清理 | 实例资源作用域与操作资源作用域,清理恰好一次、可重入、失败后继续释放 | +| 内部事件 | utils/emitter.js | typed event map、未知事件兼容扩展、原调用顺序和 ctx | +| 媒体能力 | template、proxy、player | 内部精确的能力接口与原生视频类型分离;公共 video 兼容层保留 | +| 播放流程 | play/pause/toggle/seek/url/switch/eventInit | 媒体状态、操作身份、加载恢复与 UI 响应分离 | +| UI 注册 | utils/component、control、layer、contextmenu | 保留 name/cache/update/remove;明确 DOM 和绑定的归属 | +| 设置面板 | setting/index.js | 分开树整理、选择状态、渲染、布局、绑定;共享能共享的逻辑,不强行统一返回类型 | +| 字幕 | subtitle.js、utils/subtitle.js | 获取、解析、track/DOM 渲染、取消和对象 URL 回收分开 | +| 显示模式 | fullscreen/fullscreenWeb/pip/mini/auto* | 显式恢复位置和样式,保持互斥顺序、用户手势与移动端语义 | +| 输入 | events、hotkey | 鼠标/触控/键盘/焦点归属清晰,跨 document 重新绑定和清理 | +| 内置功能 | plugins/*、info/notice/loading/mask | 逐项登记定时器和订阅,不能因内部插件迁移改变默认启用条件 | +| 资源 | i18n、icons、style、libs | 保持子路径、图标键、CSS 类和样式注入;记录 vendored 依赖来源 | + +## 生命周期设计约束 + +1. 分离实例作用域和单次切源/请求作用域;结束一次请求不能销毁整个实例。 +2. 资源登记函数返回内部清理句柄,不要求旧插件接入新接口。 +3. 销毁中的重入、重复销毁和单项清理异常要有专门测试。 +4. ready、destroy 的原触发时机和监听器可见状态先捕获基线。不能为统一清理把所有 Emitter 订阅先清空。 +5. 等待中的请求通过取消或 generation token 隔离过期结果;其 Promise 结算方式需要行为决策。 +6. 初始化失败只释放已创建资源,避免 DOM 和 instances 半初始化残留。 +7. ES2015 产物的语法目标和实际 AbortController 等能力支持分别验证;必要时使用内部 fallback,不默认增加全局 polyfill。 + +## TypeScript 迁移原则 + +- 使用 allowJs 建立过渡,迁移完成的生产模块启用 strict;禁止靠整文件 ts-nocheck 或无边界 any 达标。 +- 内部优先使用所需能力的精确接口,不把所有参数都简单标为 Artplayer。 +- 公共自定义配置、事件、插件结果允许明确的泛型/模块扩展,保留旧 JS 用法。 +- DOM、Node、worker、AudioWorklet 和媒体 shim 类型分域;不要让 monorepo 的全部 @types 自动污染核心。 +- 内部字段采用不发出多余运行时代码的声明方式。重新安排 class field 初始化会影响构造顺序和属性行为,需测试。 +- 公开声明生成时隐藏内部模块,不改变既有类型入口;ESM/CJS 两种类型消费者分别检查。 +- 第三方复制文件允许暂保留 JS,但必须有来源、许可证和包内类型适配,不计为自有源码 TS 迁移遗漏。 + +## 性能范围 + +先测初始化耗时、控件交互、播放帧期间的工作、重复挂载/销毁后的资源、弹幕和 proxy 的帧调度。记录同设备同媒体的多次采样。只有结果支持时才减少 DOM 读写、合并帧更新、限频持久化、改进算法或延迟加载;不以改成 TS 或 Bun 本身作为浏览器性能优化证据。 diff --git a/refactor/decisions.md b/refactor/decisions.md new file mode 100644 index 000000000..4370ed080 --- /dev/null +++ b/refactor/decisions.md @@ -0,0 +1,40 @@ +# 决策记录 + +状态:采用方向 / 待验证 / 已拒绝 / 已替代。采用方向不代表实现完成,技术细节可由后续证据修订。 + +| ID | 状态 | 决策 | 原因与约束 | +| --- | --- | --- | --- | +| ADR-001 | 采用方向 | 保留公共 Artplayer 门面、渐进替换内部 | 大量旧用户及插件;属性/事件/分发均是契约 | +| ADR-002 | 采用方向 | 自有核心、插件、proxy、工具逐步 TS 化 | 消除实现/声明漂移;JS/TS 过渡,公开类型兼容 | +| ADR-003 | 采用方向 | 先测试、生命周期,再大范围模块调整 | 已有销毁与切源风险;不能仅靠改写语言获得可靠性 | +| ADR-004 | 待验证 | Bun 先用于依赖管理和脚本入口 | 需要固定版本、干净安装和完整包验证;不替换 Node 测试语义 | +| ADR-005 | 采用方向 | 保留 Vite/Rollup 的既有分发能力 | UMD/AMD/legacy、Less/SVG/worker 兼容成本明确 | +| ADR-006 | 采用方向 | 每包独立任务和版本,公共共享依赖谨慎增加 | 支持旧核心配新插件;不强制生态同步升级 | +| ADR-007 | 采用方向 | 机器任务表 + 可读生成表 + 每次变更记录 | 支持 AI 接续、依赖检查和证据追溯 | +| ADR-008 | 待验证 | 内部资源作用域和操作身份隔离 | 清理/取消语义待基线测试,不能先决定新增 Promise 拒绝 | +| ADR-009 | 待验证 | 精确公共类型的兼容扩展策略 | 错误声明修正也可能破坏现有 TS 用户;逐项记录 | +| ADR-010 | 采用方向 | AI 改善工程,不默认给播放器加入远程 AI 能力 | 避免增加运行依赖、网络请求、成本和用户行为变化 | +| ADR-011 | 采用方向 | vendored 代码维持独立来源和许可 | TS 迁移限自有逻辑,第三方更新独立验证 | +| ADR-012 | 已拒绝 | 一次性重写核心并同时更换包管理器、bundler、测试框架 | 变量过多,难以定位回归和回退 | +| ADR-013 | 采用方向 | 用户授权在旧接口兼容前提下主动改善全部不合理内部设计 | 2026-09-10 明确要求:TS 迁移伴随清晰拆分、充分有效测试、持续文档和 AI 接续能力;任务清单可按证据扩展 | +| ADR-014 | 采用方向 | 每完成一个任务立即创建独立本地 commit | 用户明确要求;实现/测试/文档/状态同次提交,主题带任务 ID,核实成功后再开始下一任务;不等同推送授权 | + +## 开始实现前需补齐的决定 + +1. 支持的历史核心/插件版本、TS 最低版本与浏览器能力矩阵,由 BASE-01/ENG-01 登记证据。 +2. 连续切源、销毁中 Promise 的结果与错误策略,由 CORE-04/CORE-09 的变更记录明确。 +3. 真机与外部 SDK 验证环境、负责者和缺失检查的发布处理,由 ENG-05/REL-03 明确。 +4. 公共类型发现历史错误且无法完全兼容时的版本策略,由 CORE-07 和 REL-01 明确。 + +## 新决策模板 + +```text +ID / 日期 / 关联任务: +状态: +问题与源码/测试证据: +选择及备选方案: +为何选择: +公开 API、类型、包分发影响: +验证方法与回退: +替代的旧决策: +``` diff --git a/refactor/package-inventory.json b/refactor/package-inventory.json new file mode 100644 index 000000000..efe7a8167 --- /dev/null +++ b/refactor/package-inventory.json @@ -0,0 +1,954 @@ +{ + "schemaVersion": 1, + "date": "2026-09-10", + "baselineCommit": "40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f", + "note": "Checkout snapshot, not a verified npm release baseline. Preserve this initial snapshot.", + "packages": [ + { + "name": "artplayer", + "version": "5.4.1", + "kind": "core", + "manifest": "packages/artplayer/package.json", + "entry": "packages/artplayer/src/index.js", + "main": "./dist/artplayer.js", + "module": "./dist/artplayer.mjs", + "exports": { + ".": { + "types": "./types/artplayer.d.ts", + "import": "./dist/artplayer.mjs", + "require": "./dist/artplayer.js" + }, + "./legacy": { + "types": "./types/artplayer.d.ts", + "import": "./dist/artplayer.legacy.js", + "require": "./dist/artplayer.legacy.js" + }, + "./i18n/*": { + "types": "./types/i18n.d.ts", + "import": "./dist/i18n/*.mjs", + "require": "./dist/i18n/*.js" + } + }, + "types": "./types/artplayer.d.ts", + "typesVersions": { + "*": { + "i18n/*": [ + "types/i18n.d.ts" + ], + "legacy": [ + "types/artplayer.d.ts" + ] + } + }, + "legacy": "./dist/artplayer.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer/src/config/index.js", + "packages/artplayer/src/contextmenu/aspectRatio.js", + "packages/artplayer/src/contextmenu/close.js", + "packages/artplayer/src/contextmenu/flip.js", + "packages/artplayer/src/contextmenu/index.js", + "packages/artplayer/src/contextmenu/info.js", + "packages/artplayer/src/contextmenu/playbackRate.js", + "packages/artplayer/src/contextmenu/version.js", + "packages/artplayer/src/control/airplay.js", + "packages/artplayer/src/control/fullscreen.js", + "packages/artplayer/src/control/fullscreenWeb.js", + "packages/artplayer/src/control/index.js", + "packages/artplayer/src/control/pip.js", + "packages/artplayer/src/control/playAndPause.js", + "packages/artplayer/src/control/progress.js", + "packages/artplayer/src/control/screenshot.js", + "packages/artplayer/src/control/setting.js", + "packages/artplayer/src/control/time.js", + "packages/artplayer/src/control/volume.js", + "packages/artplayer/src/events/clickInit.js", + "packages/artplayer/src/events/gestureInit.js", + "packages/artplayer/src/events/globalInit.js", + "packages/artplayer/src/events/hoverInit.js", + "packages/artplayer/src/events/index.js", + "packages/artplayer/src/events/moveInit.js", + "packages/artplayer/src/events/resizeInit.js", + "packages/artplayer/src/events/updateInit.js", + "packages/artplayer/src/events/viewInit.js", + "packages/artplayer/src/hotkey.js", + "packages/artplayer/src/i18n/ar.js", + "packages/artplayer/src/i18n/cs.js", + "packages/artplayer/src/i18n/es.js", + "packages/artplayer/src/i18n/fa.js", + "packages/artplayer/src/i18n/fr.js", + "packages/artplayer/src/i18n/id.js", + "packages/artplayer/src/i18n/index.js", + "packages/artplayer/src/i18n/pl.js", + "packages/artplayer/src/i18n/ru.js", + "packages/artplayer/src/i18n/tr.js", + "packages/artplayer/src/i18n/vi.js", + "packages/artplayer/src/i18n/zh-cn.js", + "packages/artplayer/src/i18n/zh-tw.js", + "packages/artplayer/src/icons/index.js", + "packages/artplayer/src/index.js", + "packages/artplayer/src/info.js", + "packages/artplayer/src/layer.js", + "packages/artplayer/src/libs/screenfull.js", + "packages/artplayer/src/loading.js", + "packages/artplayer/src/mask.js", + "packages/artplayer/src/notice.js", + "packages/artplayer/src/player/airplayMix.js", + "packages/artplayer/src/player/aspectRatioMix.js", + "packages/artplayer/src/player/attrMix.js", + "packages/artplayer/src/player/autoHeightMix.js", + "packages/artplayer/src/player/autoSizeMix.js", + "packages/artplayer/src/player/cssVarMix.js", + "packages/artplayer/src/player/currentTimeMix.js", + "packages/artplayer/src/player/durationMix.js", + "packages/artplayer/src/player/eventInit.js", + "packages/artplayer/src/player/flipMix.js", + "packages/artplayer/src/player/fullscreenMix.js", + "packages/artplayer/src/player/fullscreenWebMix.js", + "packages/artplayer/src/player/index.js", + "packages/artplayer/src/player/loadedMix.js", + "packages/artplayer/src/player/miniMix.js", + "packages/artplayer/src/player/optionInit.js", + "packages/artplayer/src/player/pauseMix.js", + "packages/artplayer/src/player/pipMix.js", + "packages/artplayer/src/player/playMix.js", + "packages/artplayer/src/player/playbackRateMix.js", + "packages/artplayer/src/player/playedMix.js", + "packages/artplayer/src/player/playingMix.js", + "packages/artplayer/src/player/posterMix.js", + "packages/artplayer/src/player/qualityMix.js", + "packages/artplayer/src/player/rectMix.js", + "packages/artplayer/src/player/screenshotMix.js", + "packages/artplayer/src/player/seekMix.js", + "packages/artplayer/src/player/stateMix.js", + "packages/artplayer/src/player/subtitleOffsetMix.js", + "packages/artplayer/src/player/switchMix.js", + "packages/artplayer/src/player/themeMix.js", + "packages/artplayer/src/player/thumbnailsMix.js", + "packages/artplayer/src/player/toggleMix.js", + "packages/artplayer/src/player/typeMix.js", + "packages/artplayer/src/player/urlMix.js", + "packages/artplayer/src/player/volumeMix.js", + "packages/artplayer/src/plugins/autoOrientation.js", + "packages/artplayer/src/plugins/autoPlayback.js", + "packages/artplayer/src/plugins/fastForward.js", + "packages/artplayer/src/plugins/index.js", + "packages/artplayer/src/plugins/lock.js", + "packages/artplayer/src/plugins/miniProgressBar.js", + "packages/artplayer/src/scheme/index.js", + "packages/artplayer/src/setting/aspectRatio.js", + "packages/artplayer/src/setting/flip.js", + "packages/artplayer/src/setting/index.js", + "packages/artplayer/src/setting/playbackRate.js", + "packages/artplayer/src/setting/subtitleOffset.js", + "packages/artplayer/src/storage.js", + "packages/artplayer/src/subtitle.js", + "packages/artplayer/src/template.js", + "packages/artplayer/src/utils/compatibility.js", + "packages/artplayer/src/utils/component.js", + "packages/artplayer/src/utils/dom.js", + "packages/artplayer/src/utils/emitter.js", + "packages/artplayer/src/utils/error.js", + "packages/artplayer/src/utils/file.js", + "packages/artplayer/src/utils/format.js", + "packages/artplayer/src/utils/index.js", + "packages/artplayer/src/utils/property.js", + "packages/artplayer/src/utils/subtitle.js", + "packages/artplayer/src/utils/time.js" + ], + "typeFiles": [ + "packages/artplayer/types/artplayer.d.ts", + "packages/artplayer/types/component.d.ts", + "packages/artplayer/types/config.d.ts", + "packages/artplayer/types/cssVar.d.ts", + "packages/artplayer/types/events.d.ts", + "packages/artplayer/types/i18n.d.ts", + "packages/artplayer/types/icons.d.ts", + "packages/artplayer/types/option.d.ts", + "packages/artplayer/types/player.d.ts", + "packages/artplayer/types/quality.d.ts", + "packages/artplayer/types/setting.d.ts", + "packages/artplayer/types/subtitle.d.ts", + "packages/artplayer/types/template.d.ts", + "packages/artplayer/types/utils.d.ts" + ], + "examples": [ + "docs/assets/example/index.js", + "docs/assets/example/mobile.js", + "docs/assets/example/setting.test.js", + "docs/assets/example/hls.js", + "docs/assets/example/dash.js", + "docs/assets/example/flv.js", + "docs/assets/example/mpegts.js", + "docs/assets/example/webtorrent.js", + "docs/assets/example/thumbnail.js" + ], + "dependencies": { + "option-validator": "^2.0.6" + }, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-ads", + "version": "2.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-ads/package.json", + "entry": "packages/artplayer-plugin-ads/src/index.js", + "main": "./dist/artplayer-plugin-ads.js", + "module": "./dist/artplayer-plugin-ads.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-ads.d.ts", + "import": "./dist/artplayer-plugin-ads.mjs", + "require": "./dist/artplayer-plugin-ads.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-ads.d.ts", + "import": "./dist/artplayer-plugin-ads.legacy.js", + "require": "./dist/artplayer-plugin-ads.legacy.js" + } + }, + "types": "./types/artplayer-plugin-ads.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-ads.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-ads/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-ads/types/artplayer-plugin-ads.d.ts" + ], + "examples": [ + "docs/assets/example/ads.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-ambilight", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-ambilight/package.json", + "entry": "packages/artplayer-plugin-ambilight/src/index.js", + "main": "./dist/artplayer-plugin-ambilight.js", + "module": "./dist/artplayer-plugin-ambilight.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-ambilight.d.ts", + "import": "./dist/artplayer-plugin-ambilight.mjs", + "require": "./dist/artplayer-plugin-ambilight.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-ambilight.d.ts", + "import": "./dist/artplayer-plugin-ambilight.legacy.js", + "require": "./dist/artplayer-plugin-ambilight.legacy.js" + } + }, + "types": "./types/artplayer-plugin-ambilight.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-ambilight.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-ambilight/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-ambilight/types/artplayer-plugin-ambilight.d.ts" + ], + "examples": [ + "docs/assets/example/ambilight.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-asr", + "version": "2.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-asr/package.json", + "entry": "packages/artplayer-plugin-asr/src/index.js", + "main": "./dist/artplayer-plugin-asr.js", + "module": "./dist/artplayer-plugin-asr.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-asr.d.ts", + "import": "./dist/artplayer-plugin-asr.mjs", + "require": "./dist/artplayer-plugin-asr.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-asr.d.ts", + "import": "./dist/artplayer-plugin-asr.legacy.js", + "require": "./dist/artplayer-plugin-asr.legacy.js" + } + }, + "types": "./types/artplayer-plugin-asr.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-asr.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-asr/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-asr/types/artplayer-plugin-asr.d.ts" + ], + "examples": [ + "docs/assets/example/asr.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-audio-track", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-audio-track/package.json", + "entry": "packages/artplayer-plugin-audio-track/src/index.js", + "main": "dist/artplayer-plugin-audio-track.js", + "module": "./dist/artplayer-plugin-audio-track.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-audio-track.d.ts", + "import": "./dist/artplayer-plugin-audio-track.mjs", + "require": "./dist/artplayer-plugin-audio-track.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-audio-track.d.ts", + "import": "./dist/artplayer-plugin-audio-track.legacy.js", + "require": "./dist/artplayer-plugin-audio-track.legacy.js" + } + }, + "types": "types/artplayer-plugin-audio-track.d.ts", + "typesVersions": null, + "legacy": "dist/artplayer-plugin-audio-track.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-audio-track/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-audio-track/types/artplayer-plugin-audio-track.d.ts" + ], + "examples": [ + "docs/assets/example/audio.track.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-auto-thumbnail", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-auto-thumbnail/package.json", + "entry": "packages/artplayer-plugin-auto-thumbnail/src/index.js", + "main": "./dist/artplayer-plugin-auto-thumbnail.js", + "module": "./dist/artplayer-plugin-auto-thumbnail.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", + "import": "./dist/artplayer-plugin-auto-thumbnail.mjs", + "require": "./dist/artplayer-plugin-auto-thumbnail.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", + "import": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", + "require": "./dist/artplayer-plugin-auto-thumbnail.legacy.js" + } + }, + "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-auto-thumbnail/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-auto-thumbnail/types/artplayer-plugin-auto-thumbnail.d.ts" + ], + "examples": [ + "docs/assets/example/auto.thumbnail.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-chapter", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-chapter/package.json", + "entry": "packages/artplayer-plugin-chapter/src/index.js", + "main": "./dist/artplayer-plugin-chapter.js", + "module": "./dist/artplayer-plugin-chapter.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-chapter.d.ts", + "import": "./dist/artplayer-plugin-chapter.mjs", + "require": "./dist/artplayer-plugin-chapter.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-chapter.d.ts", + "import": "./dist/artplayer-plugin-chapter.legacy.js", + "require": "./dist/artplayer-plugin-chapter.legacy.js" + } + }, + "types": "./types/artplayer-plugin-chapter.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-chapter.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-chapter/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-chapter/types/artplayer-plugin-chapter.d.ts" + ], + "examples": [ + "docs/assets/example/chapter.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-chromecast", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-chromecast/package.json", + "entry": "packages/artplayer-plugin-chromecast/src/index.js", + "main": "./dist/artplayer-plugin-chromecast.js", + "module": "./dist/artplayer-plugin-chromecast.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-chromecast.d.ts", + "import": "./dist/artplayer-plugin-chromecast.mjs", + "require": "./dist/artplayer-plugin-chromecast.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-chromecast.d.ts", + "import": "./dist/artplayer-plugin-chromecast.legacy.js", + "require": "./dist/artplayer-plugin-chromecast.legacy.js" + } + }, + "types": "./types/artplayer-plugin-chromecast.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-chromecast.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-chromecast/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-chromecast/types/artplayer-plugin-chromecast.d.ts" + ], + "examples": [ + "docs/assets/example/chromecast.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-danmuku", + "version": "5.3.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-danmuku/package.json", + "entry": "packages/artplayer-plugin-danmuku/src/index.js", + "main": "./dist/artplayer-plugin-danmuku.js", + "module": "./dist/artplayer-plugin-danmuku.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-danmuku.d.ts", + "import": "./dist/artplayer-plugin-danmuku.mjs", + "require": "./dist/artplayer-plugin-danmuku.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-danmuku.d.ts", + "import": "./dist/artplayer-plugin-danmuku.legacy.js", + "require": "./dist/artplayer-plugin-danmuku.legacy.js" + } + }, + "types": "./types/artplayer-plugin-danmuku.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-danmuku.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-danmuku/src/bilibili.js", + "packages/artplayer-plugin-danmuku/src/danmuku.js", + "packages/artplayer-plugin-danmuku/src/heatmap.js", + "packages/artplayer-plugin-danmuku/src/index.js", + "packages/artplayer-plugin-danmuku/src/setting.js", + "packages/artplayer-plugin-danmuku/src/worker.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-danmuku/types/artplayer-plugin-danmuku.d.ts" + ], + "examples": [ + "docs/assets/example/danmuku.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-danmuku-mask", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-danmuku-mask/package.json", + "entry": "packages/artplayer-plugin-danmuku-mask/src/index.js", + "main": "./dist/artplayer-plugin-danmuku-mask.js", + "module": "./dist/artplayer-plugin-danmuku-mask.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-danmuku-mask.d.ts", + "import": "./dist/artplayer-plugin-danmuku-mask.mjs", + "require": "./dist/artplayer-plugin-danmuku-mask.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-danmuku-mask.d.ts", + "import": "./dist/artplayer-plugin-danmuku-mask.legacy.js", + "require": "./dist/artplayer-plugin-danmuku-mask.legacy.js" + } + }, + "types": "./types/artplayer-plugin-danmuku-mask.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-danmuku-mask.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-danmuku-mask/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-danmuku-mask/types/artplayer-plugin-danmuku-mask.d.ts" + ], + "examples": [ + "docs/assets/example/danmuku.mask.js" + ], + "dependencies": { + "@mediapipe/selfie_segmentation": "^0.1.1675465747", + "@tensorflow-models/body-segmentation": "^1.0.2", + "@tensorflow/tfjs-backend-cpu": "^4.21.0", + "@tensorflow/tfjs-backend-webgl": "^4.21.0", + "@tensorflow/tfjs-converter": "^4.21.0", + "@tensorflow/tfjs-core": "^4.21.0" + }, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-dash-control", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-dash-control/package.json", + "entry": "packages/artplayer-plugin-dash-control/src/index.js", + "main": "./dist/artplayer-plugin-dash-control.js", + "module": "./dist/artplayer-plugin-dash-control.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-dash-control.d.ts", + "import": "./dist/artplayer-plugin-dash-control.mjs", + "require": "./dist/artplayer-plugin-dash-control.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-dash-control.d.ts", + "import": "./dist/artplayer-plugin-dash-control.legacy.js", + "require": "./dist/artplayer-plugin-dash-control.legacy.js" + } + }, + "types": "./types/artplayer-plugin-dash-control.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-dash-control.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-dash-control/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts" + ], + "examples": [ + "docs/assets/example/dash.control.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-document-pip", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-document-pip/package.json", + "entry": "packages/artplayer-plugin-document-pip/src/index.js", + "main": "./dist/artplayer-plugin-document-pip.js", + "module": "./dist/artplayer-plugin-document-pip.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-document-pip.d.ts", + "import": "./dist/artplayer-plugin-document-pip.mjs", + "require": "./dist/artplayer-plugin-document-pip.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-document-pip.d.ts", + "import": "./dist/artplayer-plugin-document-pip.legacy.js", + "require": "./dist/artplayer-plugin-document-pip.legacy.js" + } + }, + "types": "./types/artplayer-plugin-document-pip.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-document-pip.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-document-pip/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts" + ], + "examples": [ + "docs/assets/example/document.pip.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-hls-control", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-hls-control/package.json", + "entry": "packages/artplayer-plugin-hls-control/src/index.js", + "main": "./dist/artplayer-plugin-hls-control.js", + "module": "./dist/artplayer-plugin-hls-control.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-hls-control.d.ts", + "import": "./dist/artplayer-plugin-hls-control.mjs", + "require": "./dist/artplayer-plugin-hls-control.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-hls-control.d.ts", + "import": "./dist/artplayer-plugin-hls-control.legacy.js", + "require": "./dist/artplayer-plugin-hls-control.legacy.js" + } + }, + "types": "./types/artplayer-plugin-hls-control.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-hls-control.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-hls-control/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-hls-control/types/artplayer-plugin-hls-control.d.ts" + ], + "examples": [ + "docs/assets/example/hls.control.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-jassub", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-jassub/package.json", + "entry": "packages/artplayer-plugin-jassub/src/index.js", + "main": "dist/artplayer-plugin-jassub.js", + "module": "./dist/artplayer-plugin-jassub.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-jassub.d.ts", + "import": "./dist/artplayer-plugin-jassub.mjs", + "require": "./dist/artplayer-plugin-jassub.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-jassub.d.ts", + "import": "./dist/artplayer-plugin-jassub.legacy.js", + "require": "./dist/artplayer-plugin-jassub.legacy.js" + } + }, + "types": "types/artplayer-plugin-jassub.d.ts", + "typesVersions": null, + "legacy": "dist/artplayer-plugin-jassub.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-jassub/src/index.js", + "packages/artplayer-plugin-jassub/src/jassub.es.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-jassub/types/artplayer-plugin-jassub.d.ts" + ], + "examples": [ + "docs/assets/example/jassub.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-multiple-subtitles", + "version": "1.2.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-multiple-subtitles/package.json", + "entry": "packages/artplayer-plugin-multiple-subtitles/src/index.js", + "main": "./dist/artplayer-plugin-multiple-subtitles.js", + "module": "./dist/artplayer-plugin-multiple-subtitles.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-multiple-subtitles.d.ts", + "import": "./dist/artplayer-plugin-multiple-subtitles.mjs", + "require": "./dist/artplayer-plugin-multiple-subtitles.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-multiple-subtitles.d.ts", + "import": "./dist/artplayer-plugin-multiple-subtitles.legacy.js", + "require": "./dist/artplayer-plugin-multiple-subtitles.legacy.js" + } + }, + "types": "./types/artplayer-plugin-multiple-subtitles.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-multiple-subtitles.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-multiple-subtitles/src/index.js", + "packages/artplayer-plugin-multiple-subtitles/src/parser.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-multiple-subtitles/types/artplayer-plugin-multiple-subtitles.d.ts" + ], + "examples": [ + "docs/assets/example/multiple.subtitles.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-vast", + "version": "1.2.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-vast/package.json", + "entry": "packages/artplayer-plugin-vast/src/index.js", + "main": "./dist/artplayer-plugin-vast.js", + "module": "./dist/artplayer-plugin-vast.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-vast.d.ts", + "import": "./dist/artplayer-plugin-vast.mjs", + "require": "./dist/artplayer-plugin-vast.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-vast.d.ts", + "import": "./dist/artplayer-plugin-vast.legacy.js", + "require": "./dist/artplayer-plugin-vast.legacy.js" + } + }, + "types": "./types/artplayer-plugin-vast.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-vast.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-vast/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-vast/types/artplayer-plugin-vast.d.ts" + ], + "examples": [ + "docs/assets/example/vast.js" + ], + "dependencies": { + "@glomex/vast-ima-player": "^1.21.2" + }, + "peerDependencies": {} + }, + { + "name": "artplayer-plugin-vtt-thumbnail", + "version": "1.1.0", + "kind": "plugin", + "manifest": "packages/artplayer-plugin-vtt-thumbnail/package.json", + "entry": "packages/artplayer-plugin-vtt-thumbnail/src/index.js", + "main": "./dist/artplayer-plugin-vtt-thumbnail.js", + "module": "./dist/artplayer-plugin-vtt-thumbnail.mjs", + "exports": { + ".": { + "types": "./types/artplayer-plugin-vtt-thumbnail.d.ts", + "import": "./dist/artplayer-plugin-vtt-thumbnail.mjs", + "require": "./dist/artplayer-plugin-vtt-thumbnail.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-vtt-thumbnail.d.ts", + "import": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js", + "require": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js" + } + }, + "types": "./types/artplayer-plugin-vtt-thumbnail.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-plugin-vtt-thumbnail/src/getVttArray.js", + "packages/artplayer-plugin-vtt-thumbnail/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-plugin-vtt-thumbnail/types/artplayer-plugin-vtt-thumbnail.d.ts" + ], + "examples": [ + "docs/assets/example/vtt.thumbnail.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-proxy-canvas", + "version": "1.1.0", + "kind": "proxy", + "manifest": "packages/artplayer-proxy-canvas/package.json", + "entry": "packages/artplayer-proxy-canvas/src/index.js", + "main": "./dist/artplayer-proxy-canvas.js", + "module": "./dist/artplayer-proxy-canvas.mjs", + "exports": { + ".": { + "types": "./types/artplayer-proxy-canvas.d.ts", + "import": "./dist/artplayer-proxy-canvas.mjs", + "require": "./dist/artplayer-proxy-canvas.js" + }, + "./legacy": { + "types": "./types/artplayer-proxy-canvas.d.ts", + "import": "./dist/artplayer-proxy-canvas.legacy.js", + "require": "./dist/artplayer-proxy-canvas.legacy.js" + } + }, + "types": "./types/artplayer-proxy-canvas.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-proxy-canvas.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-proxy-canvas/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-proxy-canvas/types/artplayer-proxy-canvas.d.ts" + ], + "examples": [ + "docs/assets/example/canvas.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-proxy-mediabunny", + "version": "1.2.0", + "kind": "proxy", + "manifest": "packages/artplayer-proxy-mediabunny/package.json", + "entry": "packages/artplayer-proxy-mediabunny/src/index.js", + "main": "./dist/artplayer-proxy-mediabunny.js", + "module": "./dist/artplayer-proxy-mediabunny.mjs", + "exports": { + ".": { + "types": "./types/artplayer-proxy-mediabunny.d.ts", + "import": "./dist/artplayer-proxy-mediabunny.mjs", + "require": "./dist/artplayer-proxy-mediabunny.js" + }, + "./legacy": { + "types": "./types/artplayer-proxy-mediabunny.d.ts", + "import": "./dist/artplayer-proxy-mediabunny.legacy.js", + "require": "./dist/artplayer-proxy-mediabunny.legacy.js" + } + }, + "types": "./types/artplayer-proxy-mediabunny.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-proxy-mediabunny.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-proxy-mediabunny/src/AudioEngine.js", + "packages/artplayer-proxy-mediabunny/src/EventTarget.js", + "packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js", + "packages/artplayer-proxy-mediabunny/src/VideoEngine.js", + "packages/artplayer-proxy-mediabunny/src/VideoShim.js", + "packages/artplayer-proxy-mediabunny/src/index.js", + "packages/artplayer-proxy-mediabunny/src/input.js", + "packages/artplayer-proxy-mediabunny/src/m3u8.js" + ], + "typeFiles": [ + "packages/artplayer-proxy-mediabunny/types/artplayer-proxy-mediabunny.d.ts" + ], + "examples": [ + "docs/assets/example/mediabunny.js" + ], + "dependencies": { + "mediabunny": "^1.43.1" + }, + "peerDependencies": {} + }, + { + "name": "artplayer-tool-iframe", + "version": "1.1.0", + "kind": "tool", + "manifest": "packages/artplayer-tool-iframe/package.json", + "entry": "packages/artplayer-tool-iframe/src/index.js", + "main": "./dist/artplayer-tool-iframe.js", + "module": "./dist/artplayer-tool-iframe.mjs", + "exports": { + ".": { + "types": "./types/artplayer-tool-iframe.d.ts", + "import": "./dist/artplayer-tool-iframe.mjs", + "require": "./dist/artplayer-tool-iframe.js" + }, + "./legacy": { + "types": "./types/artplayer-tool-iframe.d.ts", + "import": "./dist/artplayer-tool-iframe.legacy.js", + "require": "./dist/artplayer-tool-iframe.legacy.js" + } + }, + "types": "./types/artplayer-tool-iframe.d.ts", + "typesVersions": null, + "legacy": "./dist/artplayer-tool-iframe.legacy.js", + "declaredTypesExist": true, + "sourceFiles": [ + "packages/artplayer-tool-iframe/src/index.js" + ], + "typeFiles": [ + "packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.ts" + ], + "examples": [ + "docs/assets/example/iframe.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-tool-thumbnail", + "version": "4.4.0", + "kind": "tool", + "manifest": "packages/artplayer-tool-thumbnail/package.json", + "entry": "packages/artplayer-tool-thumbnail/src/index.js", + "main": null, + "module": "dist/artplayer-tool-thumbnail.esm.js", + "exports": { + "import": "./dist/artplayer-tool-thumbnail.esm.js", + "require": "./dist/artplayer-tool-thumbnail.js", + "default": "./dist/artplayer-tool-thumbnail.js" + }, + "types": "types/artplayer-tool-thumbnail.d.ts", + "typesVersions": null, + "legacy": "dist/artplayer-tool-thumbnail.legacy.js", + "declaredTypesExist": false, + "sourceFiles": [ + "packages/artplayer-tool-thumbnail/src/emitter.js", + "packages/artplayer-tool-thumbnail/src/index.js", + "packages/artplayer-tool-thumbnail/src/utils.js" + ], + "typeFiles": [], + "examples": [ + "docs/assets/example/tool.thumbnail.js" + ], + "dependencies": {}, + "peerDependencies": {} + }, + { + "name": "artplayer-vitepress", + "version": "1.1.0", + "kind": "docs", + "manifest": "packages/artplayer-vitepress/package.json", + "entry": null, + "main": null, + "module": null, + "exports": null, + "types": null, + "typesVersions": null, + "legacy": null, + "declaredTypesExist": null, + "sourceFiles": [], + "typeFiles": [], + "examples": [], + "dependencies": {}, + "peerDependencies": {} + } + ], + "consumerExamples": [ + "example/react.js", + "example/vue.js" + ] +} diff --git a/refactor/packages.md b/refactor/packages.md new file mode 100644 index 000000000..dc3f6b489 --- /dev/null +++ b/refactor/packages.md @@ -0,0 +1,65 @@ +# 全生态迁移规范 + +完整的逐包、逐步骤计划在 [plan.md](plan.md),基线入口和 demo 在 [package-inventory.json](package-inventory.json)。每个包都有独立任务 ID,不用一个“迁移所有插件”的任务代表完成。 + +## 每包六步 + +| 步骤 | 内容 | 交付物 | +| --- | --- | --- | +| 01 契约 | 核对源码、声明、README、真实发布包与 demo | 公开 option/result/events/static/入口及差异表 | +| 02 测试 | 捕获现有可观察行为、边界、资源和错误流程 | 可重复运行的旧行为用例与固定样本 | +| 03 内部整理 | 抽离该包具体职责、补资源归属和过期任务处理 | JS 内部改造及缺陷的独立变更记录 | +| 04 类型迁移 | 自有生产源码 TS 化、声明生成、旧类型兼容 | 严格类型模块和消费者类型测试 | +| 05 集成 | 在最终重构核心、旧支持范围核心、组合场景验证 | 浏览器、旧调用方式和资源清理证据 | +| 06 分发 | 验证 tarball、产物/资源路径、文档与示例 | 分包交付记录、版本/回退建议 | + +复杂包可以把任一步拆成新子任务并保留依赖。每步不要求一次提交解决全部;默认按一个可回退行为边界切分。 + +六步同时受 quality-contract.md 约束:步骤 03 交付清楚的职责与依赖,步骤 04 不能仅改扩展名,步骤 05 验证有风险的真实行为,步骤 06 验收包内实现地图与维护命令。包内架构文档从实现开始同步维护,不能只在最后一步补写。 + +## 各包重点 + +| 包 | 重点与特殊边界 | +| --- | --- | +| artplayer-plugin-chapter | 时间区间、进度条 DOM、hover 与 update;适合作为简单插件试点 | +| artplayer-plugin-ambilight | canvas 取色、RAF、暂停/销毁和跨域画布错误 | +| artplayer-plugin-audio-track | 外部 audio 与主视频的时钟、seek、buffering、倍率、音量和自动播放拒绝 | +| artplayer-plugin-auto-thumbnail | 异步插件、隐藏 video、seek 抽帧、Blob URL、切源后旧任务和取消 | +| artplayer-plugin-vtt-thumbnail | VTT 区间/xywh/相对 URL、预览定位、请求和定时器清理 | +| artplayer-plugin-hls-control | 实际 level/audio track、Auto、过滤和去重、旧 selector 名称、源拓扑变化 | +| artplayer-plugin-dash-control | representation ID、ABR/手动状态、过滤、排序与已有回归用例 | +| artplayer-plugin-multiple-subtitles | VTT/SRT/ASS 合并、排序、同名轨道、onParser、异步返回形状;保留 multipleSubtitles 名称 | +| artplayer-plugin-jassub | 保留 result.instance 和选项透传;worker/WASM/font 路径及销毁,vendored JASSUB 不顺带重写 | +| artplayer-plugin-danmuku | 加载/过滤/调度/轨道/DOM/设置/heatmap/worker 分开;保留 emit/load/config/show/hide/reset/mount 和静态 icons | +| artplayer-plugin-danmuku-mask | 分割模型加载、CPU/WebGL fallback、推理并发、启停竞态和 GPU 资源;不擅自升级模型或改变阈值 | +| artplayer-plugin-asr | AudioContext/Worklet/MediaStream、PCM/WAV 分块、回调背压、停止及字幕;不增加网络 ASR 服务 | +| artplayer-plugin-ads | 源码 html/video/url 与现有声明 source/type 等差异先核实;保留倒计时、跳过及主视频恢复语义 | +| artplayer-plugin-vast | 异步 SDK 加载、callback 上下文、IMA Player 生命周期、广告结束/错误后的内容恢复 | +| artplayer-plugin-chromecast | SDK loader、会话、媒体元数据、重复实例、不可用设备/拒绝;设备检查与 stub 分开 | +| artplayer-plugin-document-pip | DOM 跨 document 移动、样式复制、焦点/键盘/全局事件重绑、窗口关闭/销毁还原 | +| artplayer-proxy-canvas | video-like surface、原 canvas 方法、事件转发、绘帧、回调和 document PiP | +| artplayer-proxy-mediabunny | VideoShim/MediaBunnyEngine/AudioEngine/VideoEngine/input/m3u8/EventTarget 分层;ready 顺序、音画同步、HLS 配对和资源释放 | +| artplayer-tool-thumbnail | 当前声明目标文件不存在;exports/module 指向 .esm.js,统一构建输出 .mjs,先核实已发布包,保持旧路径可用 | +| artplayer-tool-iframe | commit/message/inject 协议、请求 ID、Promise、销毁和 origin/source 边界;历史公开拼写保留,安全修改独立评估 | +| artplayer-vitepress | 中文/英文原始文档、运行示例、声明注入、插件文档、链接与构建;不手改生成目录 | + +以上是代码清点形成的验证重点,不代表已逐一复现缺陷。 + +## 代表性组合 + +| 组合 | 必测场景 | +| --- | --- | +| 核心 + HLS/DASH + chapter/thumbnail | 清晰度/音轨切换、进度状态、Auto、换成无对应轨道的来源 | +| 核心 + danmuku + mask | 暂停、seek、倍速、全屏、模型失败及反复启停 | +| 核心 + multiple-subtitles/JASSUB | cue 时间、偏移、切源、全屏和字幕资源释放 | +| 核心 + audio-track/ASR | 主视频与外部音频、缓冲、AudioContext 生命周期及重复挂载 | +| 核心 + ads/VAST | 广告完成/跳过/失败恢复内容;使用本地 stub 或官方测试资源,避免真实计费跟踪 | +| 核心 + document-pip + canvas/MediaBunny | 节点迁移、ownerDocument、全局事件、关闭后正常播放 | +| 多实例 + 任意可组合插件 | mutex、独立 DOM/样式/资源归属,销毁一实例不影响其他实例 | +| 原生 JS / React / Vue + 旧插件 | 不改用户调用完成挂载、更新、卸载、再次挂载 | + +不是所有插件两两组合都必须支持;BASE 阶段登记已有支持组合,REL 阶段覆盖高风险组合。明确不支持的组合有理由和文档,不能把测试未覆盖等同于不支持。 + +## 资源与依赖 + +大模型、外部 SDK、worker/WASM、字体和视频文件的来源、版本、许可、下载时机和可配置 URL 都要记录。CI 中将确定性 adapter 测试和真实服务/硬件验证分开。升级供应商 SDK 与内部 TS 迁移分开执行,尽量固定一项变量。 diff --git a/refactor/plan.md b/refactor/plan.md new file mode 100644 index 000000000..90d08ac19 --- /dev/null +++ b/refactor/plan.md @@ -0,0 +1,372 @@ +# 完整重构执行计划表 + +> 由 tasks.json 生成。请修改数据后运行 `node refactor/scripts/plan.mjs --write`,不要手改本表。 + +基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 191 项,范围 22 个包及工作区/示例。 + +状态:todo 186 / doing 0 / blocked 0 / done 5 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 + +前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 + +每项实施任务同时适用[全项目质量要求](quality-contract.md):清晰拆分职责和依赖,主动改善不合理设计,以有效测试证明旧接口兼容,并同步维护后续 AI 可接续的包内文档。 + +## 包覆盖索引 + +| 包 | 基线版本 | 任务 | +| --- | --- | --- | +| artplayer | 5.4.1 | CORE-01, CORE-02, CORE-03, CORE-04, CORE-05, CORE-06, CORE-07, CORE-08, CORE-09, CORE-10, CORE-11, CORE-12, CORE-13, CORE-14, CORE-15, CORE-16, CORE-17, CORE-18, CORE-19, CORE-20, CORE-21, CORE-22 | +| artplayer-plugin-ads | 2.1.0 | PKG-ADS-01, PKG-ADS-02, PKG-ADS-03, PKG-ADS-04, PKG-ADS-05, PKG-ADS-06 | +| artplayer-plugin-ambilight | 1.1.0 | PKG-AMBILIGHT-01, PKG-AMBILIGHT-02, PKG-AMBILIGHT-03, PKG-AMBILIGHT-04, PKG-AMBILIGHT-05, PKG-AMBILIGHT-06 | +| artplayer-plugin-asr | 2.1.0 | PKG-ASR-01, PKG-ASR-02, PKG-ASR-03, PKG-ASR-04, PKG-ASR-05, PKG-ASR-06 | +| artplayer-plugin-audio-track | 1.1.0 | PKG-AUDIO-01, PKG-AUDIO-02, PKG-AUDIO-03, PKG-AUDIO-04, PKG-AUDIO-05, PKG-AUDIO-06 | +| artplayer-plugin-auto-thumbnail | 1.1.0 | PKG-AUTO-THUMB-01, PKG-AUTO-THUMB-02, PKG-AUTO-THUMB-03, PKG-AUTO-THUMB-04, PKG-AUTO-THUMB-05, PKG-AUTO-THUMB-06 | +| artplayer-plugin-chapter | 1.1.0 | PKG-CHAPTER-01, PKG-CHAPTER-02, PKG-CHAPTER-03, PKG-CHAPTER-04, PKG-CHAPTER-05, PKG-CHAPTER-06 | +| artplayer-plugin-chromecast | 1.1.0 | PKG-CAST-01, PKG-CAST-02, PKG-CAST-03, PKG-CAST-04, PKG-CAST-05, PKG-CAST-06 | +| artplayer-plugin-danmuku | 5.3.0 | PKG-DANMUKU-01, PKG-DANMUKU-02, PKG-DANMUKU-03, PKG-DANMUKU-04, PKG-DANMUKU-05, PKG-DANMUKU-06, PKG-DANMUKU-07, PKG-DANMUKU-08, PKG-DANMUKU-09 | +| artplayer-plugin-danmuku-mask | 1.1.0 | PKG-MASK-01, PKG-MASK-02, PKG-MASK-03, PKG-MASK-04, PKG-MASK-05, PKG-MASK-06 | +| artplayer-plugin-dash-control | 1.1.0 | PKG-DASH-01, PKG-DASH-02, PKG-DASH-03, PKG-DASH-04, PKG-DASH-05, PKG-DASH-06 | +| artplayer-plugin-document-pip | 1.1.0 | PKG-DPIP-01, PKG-DPIP-02, PKG-DPIP-03, PKG-DPIP-04, PKG-DPIP-05, PKG-DPIP-06 | +| artplayer-plugin-hls-control | 1.1.0 | PKG-HLS-01, PKG-HLS-02, PKG-HLS-03, PKG-HLS-04, PKG-HLS-05, PKG-HLS-06 | +| artplayer-plugin-jassub | 1.1.0 | PKG-JASSUB-01, PKG-JASSUB-02, PKG-JASSUB-03, PKG-JASSUB-04, PKG-JASSUB-05, PKG-JASSUB-06 | +| artplayer-plugin-multiple-subtitles | 1.2.0 | PKG-MULTI-SUB-01, PKG-MULTI-SUB-02, PKG-MULTI-SUB-03, PKG-MULTI-SUB-04, PKG-MULTI-SUB-05, PKG-MULTI-SUB-06 | +| artplayer-plugin-vast | 1.2.0 | PKG-VAST-01, PKG-VAST-02, PKG-VAST-03, PKG-VAST-04, PKG-VAST-05, PKG-VAST-06 | +| artplayer-plugin-vtt-thumbnail | 1.1.0 | PKG-VTT-THUMB-01, PKG-VTT-THUMB-02, PKG-VTT-THUMB-03, PKG-VTT-THUMB-04, PKG-VTT-THUMB-05, PKG-VTT-THUMB-06 | +| artplayer-proxy-canvas | 1.1.0 | PKG-CANVAS-01, PKG-CANVAS-02, PKG-CANVAS-03, PKG-CANVAS-04, PKG-CANVAS-05, PKG-CANVAS-06 | +| artplayer-proxy-mediabunny | 1.2.0 | PKG-MB-01, PKG-MB-02, PKG-MB-03, PKG-MB-04, PKG-MB-05, PKG-MB-06, PKG-MB-07, PKG-MB-08, PKG-MB-09, PKG-MB-10 | +| artplayer-tool-iframe | 1.1.0 | PKG-IFRAME-01, PKG-IFRAME-02, PKG-IFRAME-03, PKG-IFRAME-04, PKG-IFRAME-05, PKG-IFRAME-06 | +| artplayer-tool-thumbnail | 4.4.0 | PKG-TOOL-THUMB-01, PKG-TOOL-THUMB-02, PKG-TOOL-THUMB-03, PKG-TOOL-THUMB-04, PKG-TOOL-THUMB-05, PKG-TOOL-THUMB-06 | +| artplayer-vitepress | 1.1.0 | SITE-01, SITE-02, SITE-03, SITE-04, SITE-05, SITE-06 | + +## 0 规划 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| DOC-01 | workspace
创建兼容重构分支 | - | 独立本地分支和起点 SHA | 分支由干净 master 创建,起点可追溯 | L | done | +| DOC-02 | workspace
清点全部包与消费者 | DOC-01 | package-inventory.json | 22 包及 React/Vue/demo 有明确清单 | L | done | +| DOC-03 | workspace
建立计划、契约、决策和协作记录 | DOC-02 | refactor 文档集与任务数据 | 每包有独立步骤、依赖、交付物和验收条件 | L | done | +| DOC-04 | workspace
验证文档完整性与生成表 | DOC-03 | 计划生成校验工具、AGENTS 入口 | 依赖无环、包覆盖、生成同步、文档链接通过 | L | done | +| DOC-05 | workspace
建立每任务提交规则并提交文档基线 | DOC-04 | 根指令、质量要求、AI 流程、变更记录与初始文档提交 | 文档与计划检查通过,独立 DOC-05 commit 保存本次交付;提交后核实 SHA 和工作区 | L | done | + +## 1 基线 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| BASE-01 | workspace
固定消费者发布基线 | DOC-05 | 各包 npm tarball/integrity、源码 SHA、历史支持矩阵 | 区分源码版本与实际已发布版本,最低核心/TS/浏览器支持有证据 | H | todo | +| BASE-02 | workspace
捕获公共 API 和属性描述符 | BASE-01 | 构造参数/默认值/静态及实例 API 快照 | 真实发布包反射与旧用户调用可重跑,未验证项明确 | H | todo | +| BASE-03 | workspace
捕获事件、异步和生命周期 | BASE-02 | ready/restart/destroy、Promise、切源/插件事件 trace | 成功、失败、重入和多实例有断言,历史缺陷有标记 | H | todo | +| BASE-04 | workspace
捕获 DOM、CSS 和官方 demo | BASE-02 | 模板/类名/变量及全部 demo 映射 | 用户样式覆盖、移动端与自定义 controls/setting 用法已记录 | M | todo | +| BASE-05 | workspace
捕获包入口、资源和类型消费 | BASE-01 | UMD/AMD/ESM/CJS/legacy/i18n、worker/WASM/字体路径矩阵 | 隔离消费者验证入口,记录 thumbnail tool 等不一致 | H | todo | +| BASE-06 | workspace
记录性能与资源基线 | BASE-03, BASE-04 | 固定媒体/设备测量、包体积、反复装卸资源报告 | 多次采样可重跑,指标和审查阈值确定,不承诺未经测量的收益 | M | todo | +| BASE-07 | workspace
建立差异和风险台账 | BASE-03, BASE-05 | 销毁/切源/类型差异、vendored 许可和外部 SDK 清单 | 已确认与待复现分开,每项有负责任务及兼容处理路线 | H | todo | + +## 2 工程保障 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| ENG-01 | workspace
固定 Node、包管理器与依赖 | BASE-01 | 版本 pin、唯一锁文件、安装说明 | 干净环境可复现,最低 Node 与构建依赖一致,未夹带全量升级 | M | todo | +| ENG-02 | workspace
拆分只读检查并建立 PR CI | ENG-01 | lint/lint:fix、PR 与主线检查、独立部署任务 | 检查不改源码、不发布,失败阻止合并;必要 required check 有配置证据 | M | todo | +| ENG-03 | workspace
建立公共行为与单元测试入口 | ENG-02, BASE-03 | 保留现有 node:test,测试目录/夹具/统一入口 | 已有 19 项回归保留,旧版与候选可用同一夹具运行 | M | todo | +| ENG-04 | workspace
建立类型测试基础 | ENG-02, BASE-05 | 根与分包 tsconfig、显式 TS 依赖、正反例测试 | 隔离 DOM/Node/worker 类型,最低和选定当前 TS 验证声明消费 | M | todo | +| ENG-05 | workspace
建立真实浏览器测试服务 | ENG-03, BASE-04 | Playwright projects、本地 Range/失败媒体服务 | Chromium/Firefox/WebKit 的基础播放 smoke 和报告可执行 | M | todo | +| ENG-06 | workspace
支持按包非交互与 JS/TS 构建 | ENG-02, BASE-05 | build/dev 入口解析、指定包参数、原交互保留 | 三种产物、Less/SVG/worker 和本地 8082 demo 正常 | H | todo | +| ENG-07 | workspace
建立 tarball 消费与产物检查 | ENG-04, ENG-06 | 隔离 npm 消费 fixtures、API/声明/入口差分 | 不借 workspace 源码通过,能识别缺文件与默认导出变化 | H | todo | +| ENG-08 | workspace
增加覆盖率、资源与性能报告 | ENG-03, ENG-05, BASE-06 | 覆盖率基线、资源清理断言、性能报告与阈值 | 关键生命周期分支有门槛,报告不靠无意义断言堆数量 | M | todo | +| ENG-09 | workspace
建立全包依赖影响和文档检查 | ENG-07, DOC-04 | 共享核心/构建影响映射、计划文档检查接入 | 核心变化触发全生态必需检查,新增包不会漏计划 | M | todo | + +## 3-4 核心迁移 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| CORE-01 | artplayer
迁移纯工具并冻结导出 | ENG-03, ENG-04, ENG-06 | utils/time/property/format/file/error/subtitle 的分批 TS 迁移 | Artplayer.utils 导出/参数/绑定保持,纯逻辑与类型测试通过 | M | todo | +| CORE-02 | artplayer
迁移内部 Emitter | CORE-01, BASE-03 | 带类型事件映射的原 Emitter 实现 | ctx、once/off、重入/异常和链式返回保持 | H | todo | +| CORE-03 | artplayer
建立内部资源作用域 | CORE-02 | 监听/订阅/定时器/RAF/请求/URL 的资源登记 | 实例与操作作用域分离,单项清理失败不阻断其他资源 | H | todo | +| CORE-04 | artplayer
修复初始化与销毁生命周期 | CORE-03, ENG-05, BASE-07 | 构造失败回收、重复/重入 destroy、instances 修复 | 事件顺序、removeHtml、多实例和销毁中异步有真实回归 | H | todo | +| CORE-05 | artplayer
区分输入配置和内部配置 | CORE-01, ENG-04 | Option/ResolvedOption、默认值与校验整理 | 配置合并/错误时机不变,JS 输入仍运行时校验 | M | todo | +| CORE-06 | artplayer
建立内部媒体与宿主类型 | CORE-05 | 原生 video、canvas shim、UI host 类型 | 不更改公开 art.video 用法,不以 HTMLVideoElement 断言掩盖 shim | M | todo | +| CORE-07 | artplayer
逐项协调公开声明差异 | CORE-02, CORE-06, BASE-07 | plugins/toggle/cue/setting/static 的旧新类型对照 | 每项有兼容重载/扩展或待决结论,不能删除旧类型样例 | H | todo | +| CORE-08 | artplayer
整理插件管理器与扩展类型 | CORE-03, CORE-07 | 注册流程、同步/异步结果、插件/事件扩展接口 | 旧插件同步可见性、重名与命名、销毁中异步插件保持明确语义 | H | todo | +| CORE-09 | artplayer
整理 URL 与切源操作 | CORE-04, CORE-06, CORE-08 | url/switch/customType 的操作身份及取消方案 | 并发切源、错误、同 URL、销毁和 Promise 结算有契约 | H | todo | +| CORE-10 | artplayer
迁移播放与时间/状态属性 | CORE-09 | play/pause/toggle/seek/volume/rate/duration 等模块 | 旧返回值、拒绝、mutex、位置恢复、属性描述符与事件通过 | H | todo | +| CORE-11 | artplayer
整理媒体事件、ready 与重连 | CORE-10 | 媒体转发、重连、UI 响应职责分离 | readiness 次数/顺序、过期重连、原错误参数有回归 | H | todo | +| CORE-12 | artplayer
迁移模板及公开资源入口 | CORE-06, CORE-04, BASE-04 | template/icons/i18n/style、SSR 与 proxy 挂载 | DOM/CSS/global/样式注入、i18n 子路径及 SSR import 保持 | H | todo | +| CORE-13 | artplayer
迁移组件注册与控件 | CORE-12, CORE-08 | Component/control/layer/contextmenu 的资源与 TS 边界 | add/update/remove、name、selector、mounted/beforeUnmount 通过 | H | todo | +| CORE-14 | artplayer
拆分设置树、渲染和布局 | CORE-13 | setting model/selection/render/layout 的分批实现 | 不强行统一控件返回值,嵌套选择、默认高亮、更新清理通过 | H | todo | +| CORE-15 | artplayer
迁移字幕获取、解析和渲染 | CORE-11, CORE-13 | subtitle 请求/track/DOM/URL 生命周期与类型 | 过期结果、偏移、cue 数组、原生全屏及错误路径通过 | H | todo | +| CORE-16 | artplayer
迁移全屏、PiP、mini 与尺寸模式 | CORE-11, CORE-12 | 显示模式服务和原公开属性门面 | 模式互斥/恢复位置、手势权限、移动方向和退出失败通过 | H | todo | +| CORE-17 | artplayer
迁移键盘、手势、焦点和全局事件 | CORE-13, CORE-16 | events/hotkey 的明确 document 与资源归属 | 跨 document 重绑、触摸/键盘、快捷键及销毁无重复响应 | H | todo | +| CORE-18 | artplayer
迁移内置插件和提示模块 | CORE-14, CORE-16, CORE-17 | autoPlayback/autoOrientation/fastForward/lock/miniProgressBar 及 info/notice/loading/mask | 默认启用条件、storage 格式、定时器/动画清理通过 | M | todo | +| CORE-19 | artplayer
整理进度、质量、缩略图和截图 | CORE-10, CORE-13, CORE-16 | 相关 player/control 功能与纯计算分离 | 截图跨域失败、缩略图布局、quality/进度边界保持 | M | todo | +| CORE-20 | artplayer
收敛核心入口与依赖方向 | CORE-14, CORE-15, CORE-18, CORE-19 | Artplayer 门面、初始化依赖与最终目录 | 所有核心自有源码迁移,公开描述符/静态接口/事件差分通过 | H | todo | +| CORE-21 | artplayer
生成核心声明并校验包内容 | CORE-20, ENG-07 | 由 TS 生成的既有入口声明与三种发布产物 | 内部类型不泄漏,旧 JS/TS 消费者与 i18n 通过 | H | todo | +| CORE-22 | artplayer
核心阶段完整验收 | CORE-21, PKG-CHAPTER-04 | 旧插件对候选核心的完整回归与资源/性能报告 | 公开兼容差异有结论,核心测试和简单插件试点通过 | H | todo | + +## 5 包迁移:artplayer-plugin-chapter + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-CHAPTER-01 | artplayer-plugin-chapter
核对包契约与历史用法 | BASE-05 | chapters 时间区间、update、name 和进度 DOM 清单 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | M | todo | +| PKG-CHAPTER-02 | artplayer-plugin-chapter
建立特有行为与错误测试 | PKG-CHAPTER-01, ENG-03, ENG-05 | 区间重叠/空列表/边界 seek、hover 标题和 update 用例 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | M | todo | +| PKG-CHAPTER-03 | artplayer-plugin-chapter
整理内部职责与资源 | PKG-CHAPTER-02, CORE-14, CORE-08 | 拆分时间区间计算、进度 DOM、事件与布局 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | M | todo | +| PKG-CHAPTER-04 | artplayer-plugin-chapter
迁移自有源码和公开类型 | PKG-CHAPTER-03, ENG-04, ENG-06, CORE-07 | Chapters/Option/Result 与 update 推导,先做简单插件 TS 试点 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | M | todo | +| PKG-CHAPTER-05 | artplayer-plugin-chapter
验证新旧核心和组合 | PKG-CHAPTER-04, CORE-22 | chapter + quality/thumbnail、移动和全屏进度场景 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | todo | +| PKG-CHAPTER-06 | artplayer-plugin-chapter
验证分发并同步文档 | PKG-CHAPTER-05, ENG-07 | chapter.js 示例、产物和变更记录 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | M | todo | + +## 5 包迁移:artplayer-plugin-ambilight + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-AMBILIGHT-01 | artplayer-plugin-ambilight
核对包契约与历史用法 | BASE-05 | blur/opacity/frequency/duration、start/stop 与挂载样式 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | M | todo | +| PKG-AMBILIGHT-02 | artplayer-plugin-ambilight
建立特有行为与错误测试 | PKG-AMBILIGHT-01, ENG-03, ENG-05 | 跨域 canvas 失败、零尺寸、暂停、重复 start/stop 和 destroy | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | M | todo | +| PKG-AMBILIGHT-03 | artplayer-plugin-ambilight
整理内部职责与资源 | PKG-AMBILIGHT-02, CORE-03, CORE-12 | 取色计算与绘帧分离,统一 RAF 和 DOM 清理 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | M | todo | +| PKG-AMBILIGHT-04 | artplayer-plugin-ambilight
迁移自有源码和公开类型 | PKG-AMBILIGHT-03, ENG-04, ENG-06, CORE-07 | canvas 上下文、参数及 start/stop 的明确类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | M | todo | +| PKG-AMBILIGHT-05 | artplayer-plugin-ambilight
验证新旧核心和组合 | PKG-AMBILIGHT-04, CORE-22 | 原生 video、canvas proxy 的能力边界及销毁无帧循环 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | todo | +| PKG-AMBILIGHT-06 | artplayer-plugin-ambilight
验证分发并同步文档 | PKG-AMBILIGHT-05, ENG-07 | ambilight.js 示例及样式/分发验证 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | M | todo | + +## 5 包迁移:artplayer-plugin-audio-track + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-AUDIO-01 | artplayer-plugin-audio-track
核对包契约与历史用法 | BASE-05 | url/offset/sync、audio 实例暴露、update 与音量语义 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-AUDIO-02 | artplayer-plugin-audio-track
建立特有行为与错误测试 | PKG-AUDIO-01, ENG-03, ENG-05 | 偏移、倍率、seek、waiting/playing、加载错误和 autoplay 拒绝 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-AUDIO-03 | artplayer-plugin-audio-track
整理内部职责与资源 | PKG-AUDIO-02, CORE-10 | 外部 audio 的同步策略、监听与源更新生命周期 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-AUDIO-04 | artplayer-plugin-audio-track
迁移自有源码和公开类型 | PKG-AUDIO-03, ENG-04, ENG-06, CORE-07 | Option/Result/audio、update 输入和事件类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-AUDIO-05 | artplayer-plugin-audio-track
验证新旧核心和组合 | PKG-AUDIO-04, CORE-22 | 主视频切源和缓冲恢复,多实例独立音频、旧核心 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-AUDIO-06 | artplayer-plugin-audio-track
验证分发并同步文档 | PKG-AUDIO-05, ENG-07 | audio.track.js 示例与运行返回值一致的声明 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-auto-thumbnail + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-AUTO-THUMB-01 | artplayer-plugin-auto-thumbnail
核对包契约与历史用法 | BASE-05 | url/width/number/scale、异步工厂和渐进缩略图更新 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-AUTO-THUMB-02 | artplayer-plugin-auto-thumbnail
建立特有行为与错误测试 | PKG-AUTO-THUMB-01, ENG-03, ENG-05 | 抽帧边界、短视频、失败、连续来源和销毁中的抽帧 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-AUTO-THUMB-03 | artplayer-plugin-auto-thumbnail
整理内部职责与资源 | PKG-AUTO-THUMB-02, CORE-09, CORE-19 | 隐藏 video、seek 队列、canvas 编码与 Blob URL 清理 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-AUTO-THUMB-04 | artplayer-plugin-auto-thumbnail
迁移自有源码和公开类型 | PKG-AUTO-THUMB-03, ENG-04, ENG-06, CORE-07 | 抽帧结果和真实异步插件返回类型兼容 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-AUTO-THUMB-05 | artplayer-plugin-auto-thumbnail
验证新旧核心和组合 | PKG-AUTO-THUMB-04, CORE-22 | 旧核心/候选核心预览、多次加载无过期缩略图覆盖 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-AUTO-THUMB-06 | artplayer-plugin-auto-thumbnail
验证分发并同步文档 | PKG-AUTO-THUMB-05, ENG-07 | auto.thumbnail.js、三种产物和内存/URL 证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-vtt-thumbnail + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-VTT-THUMB-01 | artplayer-plugin-vtt-thumbnail
核对包契约与历史用法 | BASE-05 | vtt/style、异步返回、预览控件名与样式契约 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | M | todo | +| PKG-VTT-THUMB-02 | artplayer-plugin-vtt-thumbnail
建立特有行为与错误测试 | PKG-VTT-THUMB-01, ENG-03, ENG-05 | VTT 解析、xywh、相对 URL、时间边界、请求失败和定位 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | M | todo | +| PKG-VTT-THUMB-03 | artplayer-plugin-vtt-thumbnail
整理内部职责与资源 | PKG-VTT-THUMB-02, CORE-09, CORE-19 | 纯解析/区间查找与 DOM、请求/定时器生命周期分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | M | todo | +| PKG-VTT-THUMB-04 | artplayer-plugin-vtt-thumbnail
迁移自有源码和公开类型 | PKG-VTT-THUMB-03, ENG-04, ENG-06, CORE-07 | cue/rect/result 和参数可选性保持兼容 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | M | todo | +| PKG-VTT-THUMB-05 | artplayer-plugin-vtt-thumbnail
验证新旧核心和组合 | PKG-VTT-THUMB-04, CORE-22 | 鼠标和移动进度、全屏、切源、chapter 组合 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | todo | +| PKG-VTT-THUMB-06 | artplayer-plugin-vtt-thumbnail
验证分发并同步文档 | PKG-VTT-THUMB-05, ENG-07 | vtt.thumbnail.js、VTT/图片资源解析和产物验证 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | M | todo | + +## 5 包迁移:artplayer-plugin-hls-control + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-HLS-01 | artplayer-plugin-hls-control
核对包契约与历史用法 | BASE-05 | quality/audio 配置、getName、update、控件名及 Hls 实例绑定 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-HLS-02 | artplayer-plugin-hls-control
建立特有行为与错误测试 | PKG-HLS-01, ENG-03, ENG-05 | Auto/手动实际 level、音轨、去重/过滤和拓扑变化 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-HLS-03 | artplayer-plugin-hls-control
整理内部职责与资源 | PKG-HLS-02, CORE-11, CORE-14 | 映射计算与 selector 更新/删除、Hls 事件订阅分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-HLS-04 | artplayer-plugin-hls-control
迁移自有源码和公开类型 | PKG-HLS-03, ENG-04, ENG-06, CORE-07 | HLS 能力适配类型、回调上下文和旧 getName 参数 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-HLS-05 | artplayer-plugin-hls-control
验证新旧核心和组合 | PKG-HLS-04, CORE-22 | 本地多码率 HLS、换成无轨道来源、旧核心和最终核心 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-HLS-06 | artplayer-plugin-hls-control
验证分发并同步文档 | PKG-HLS-05, ENG-07 | hls.control.js、依赖范围与回退记录 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-dash-control + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-DASH-01 | artplayer-plugin-dash-control
核对包契约与历史用法 | BASE-05 | quality/audio、representation ID/Auto、getName 和 update | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-DASH-02 | artplayer-plugin-dash-control
建立特有行为与错误测试 | PKG-DASH-01, ENG-03, ENG-05 | 保留已有 5 项回归,补音轨/空列表/过滤/换源 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-DASH-03 | artplayer-plugin-dash-control
整理内部职责与资源 | PKG-DASH-02, CORE-11, CORE-14 | 稳定 ID 映射、ABR 状态与 UI 清理职责分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-DASH-04 | artplayer-plugin-dash-control
迁移自有源码和公开类型 | PKG-DASH-03, ENG-04, ENG-06, CORE-07 | dash.js adapter、selector 和回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-DASH-05 | artplayer-plugin-dash-control
验证新旧核心和组合 | PKG-DASH-04, CORE-22 | 本地 DASH 实际 representation、高亮、恢复 Auto 和换源 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-DASH-06 | artplayer-plugin-dash-control
验证分发并同步文档 | PKG-DASH-05, ENG-07 | dash.control.js、支持的 dash.js 版本与产物 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-multiple-subtitles + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-MULTI-SUB-01 | artplayer-plugin-multiple-subtitles
核对包契约与历史用法 | BASE-05 | subtitles/onParser、multipleSubtitles 名称及实际返回方法 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-MULTI-SUB-02 | artplayer-plugin-multiple-subtitles
建立特有行为与错误测试 | PKG-MULTI-SUB-01, ENG-03, ENG-05 | VTT/SRT/ASS、编码/重叠 cue/排序/空轨/失败与切换 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-MULTI-SUB-03 | artplayer-plugin-multiple-subtitles
整理内部职责与资源 | PKG-MULTI-SUB-02, CORE-15 | 解析与合并/获取/渲染分离,过期请求及对象 URL 清理 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-MULTI-SUB-04 | artplayer-plugin-multiple-subtitles
迁移自有源码和公开类型 | PKG-MULTI-SUB-03, ENG-04, ENG-06, CORE-07 | 准确 parser/cue/tree/result 类型与真实异步形状 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-MULTI-SUB-05 | artplayer-plugin-multiple-subtitles
验证新旧核心和组合 | PKG-MULTI-SUB-04, CORE-22 | 与核心字幕/偏移/全屏组合,旧名称调用不变 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-MULTI-SUB-06 | artplayer-plugin-multiple-subtitles
验证分发并同步文档 | PKG-MULTI-SUB-05, ENG-07 | multiple.subtitles.js、parser 来源许可及打包边界 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-jassub + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-JASSUB-01 | artplayer-plugin-jassub
核对包契约与历史用法 | BASE-05 | 选项透传、result.instance、vendor 来源、worker/WASM/font 路径 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-JASSUB-02 | artplayer-plugin-jassub
建立特有行为与错误测试 | PKG-JASSUB-01, ENG-03, ENG-05 | ASS 字体、时钟/seek/倍率/resize、加载失败和销毁 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-JASSUB-03 | artplayer-plugin-jassub
整理内部职责与资源 | PKG-JASSUB-02, CORE-15, CORE-16 | 仅整理自有 adapter/销毁;保留第三方文件及来源 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-JASSUB-04 | artplayer-plugin-jassub
迁移自有源码和公开类型 | PKG-JASSUB-03, ENG-04, ENG-06, CORE-07 | JASSUB option/instance 的兼容类型包装,vendor JS 例外记录 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-JASSUB-05 | artplayer-plugin-jassub
验证新旧核心和组合 | PKG-JASSUB-04, CORE-22 | 真实 worker/WASM 字幕渲染与全屏、旧核心测试 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-JASSUB-06 | artplayer-plugin-jassub
验证分发并同步文档 | PKG-JASSUB-05, ENG-07 | jassub.js、外部资源路径、许可和离线失败记录 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-danmuku-mask + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-MASK-01 | artplayer-plugin-danmuku-mask
核对包契约与历史用法 | BASE-05 | 模型参数、start/stop、默认下载路径及 mask 样式 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-MASK-02 | artplayer-plugin-danmuku-mask
建立特有行为与错误测试 | PKG-MASK-01, ENG-03, ENG-05 | 加载期间停止/销毁、重复启动、推理失败、WebGL/CPU 边界 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-MASK-03 | artplayer-plugin-danmuku-mask
整理内部职责与资源 | PKG-MASK-02, CORE-18, PKG-DANMUKU-07 | 模型加载/推理/画布输出分离,阻止重叠推理与过期写入 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-MASK-04 | artplayer-plugin-danmuku-mask
迁移自有源码和公开类型 | PKG-MASK-03, ENG-04, ENG-06, CORE-07 | 模型 adapter、canvas 和选项的精确类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-MASK-05 | artplayer-plugin-danmuku-mask
验证新旧核心和组合 | PKG-MASK-04, CORE-22 | 真实模型和 danmuku/seek/全屏组合,GPU 资源释放 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-MASK-06 | artplayer-plugin-danmuku-mask
验证分发并同步文档 | PKG-MASK-05, ENG-07 | danmuku.mask.js、资源版本/许可、CPU fallback 和包体积证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-asr + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-ASR-01 | artplayer-plugin-asr
核对包契约与历史用法 | BASE-05 | length/interval/sampleRate/onAudioChunk、append/hide/stop 的真实能力 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-ASR-02 | artplayer-plugin-asr
建立特有行为与错误测试 | PKG-ASR-01, ENG-03, ENG-05 | PCM/WAV、chunk 时序、回调慢/拒绝、重复初始化与停止 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-ASR-03 | artplayer-plugin-asr
整理内部职责与资源 | PKG-ASR-02, CORE-10, CORE-18 | AudioContext/Worklet/Stream 生命周期和背压分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-ASR-04 | artplayer-plugin-asr
迁移自有源码和公开类型 | PKG-ASR-03, ENG-04, ENG-06, CORE-07 | 主线程/Worklet/音频 buffer 与异步回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-ASR-05 | artplayer-plugin-asr
验证新旧核心和组合 | PKG-ASR-04, CORE-22 | 真实 WebAudio 分块、播放暂停/切源/销毁,不引入网络 ASR | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-ASR-06 | artplayer-plugin-asr
验证分发并同步文档 | PKG-ASR-05, ENG-07 | asr.js、Worklet 资源、输出格式与声明证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-ads + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-ADS-01 | artplayer-plugin-ads
核对包契约与历史用法 | BASE-05 | 核对 html/video/url 与 source/type 声明差异,结果方法和倒计时 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-ADS-02 | artplayer-plugin-ads
建立特有行为与错误测试 | PKG-ADS-01, ENG-03, ENG-05 | 视频/HTML/图片实际支持路径、跳过阈值、暂停恢复、加载失败 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-ADS-03 | artplayer-plugin-ads
整理内部职责与资源 | PKG-ADS-02, CORE-10, CORE-13 | 广告状态/计时/视图/主视频恢复分离,不改变广告产品规则 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-ADS-04 | artplayer-plugin-ads
迁移自有源码和公开类型 | PKG-ADS-03, ENG-04, ENG-06, CORE-07 | 旧参数契约和真实返回方法的兼容类型;错误声明单独处理 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-ADS-05 | artplayer-plugin-ads
验证新旧核心和组合 | PKG-ADS-04, CORE-22 | 本地广告 fixture、多实例、正常结束/跳过/销毁恢复内容 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-ADS-06 | artplayer-plugin-ads
验证分发并同步文档 | PKG-ADS-05, ENG-07 | ads.js、README/类型一致性、旧参数保留与变更日志 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-vast + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-VAST-01 | artplayer-plugin-vast
核对包契约与历史用法 | BASE-05 | 异步工厂、callback context、playUrl/playRes/init 与 SDK 版本 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-VAST-02 | artplayer-plugin-vast
建立特有行为与错误测试 | PKG-VAST-01, ENG-03, ENG-05 | SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-VAST-03 | artplayer-plugin-vast
整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-VAST-04 | artplayer-plugin-vast
迁移自有源码和公开类型 | PKG-VAST-03, ENG-04, ENG-06, CORE-07 | IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-VAST-05 | artplayer-plugin-vast
验证新旧核心和组合 | PKG-VAST-04, CORE-22 | 官方测试广告或受控 SDK 环境,错误后主视频状态恢复 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-VAST-06 | artplayer-plugin-vast
验证分发并同步文档 | PKG-VAST-05, ENG-07 | vast.js、SDK 资源、声明消费和独立版本记录 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-chromecast + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-CAST-01 | artplayer-plugin-chromecast
核对包契约与历史用法 | BASE-05 | url/sdk/icon/mimeType、loader、会话、全局 SDK 与结果 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-CAST-02 | artplayer-plugin-chromecast
建立特有行为与错误测试 | PKG-CAST-01, ENG-03, ENG-05 | SDK 脚本加载失败/重入、无设备/拒绝、重复实例与销毁 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-CAST-03 | artplayer-plugin-chromecast
整理内部职责与资源 | PKG-CAST-02, CORE-11, CORE-13 | SDK singleton/实例订阅/会话与控件职责分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-CAST-04 | artplayer-plugin-chromecast
迁移自有源码和公开类型 | PKG-CAST-03, ENG-04, ENG-06, CORE-07 | Cast 能力 adapter、全局对象和元数据类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-CAST-05 | artplayer-plugin-chromecast
验证新旧核心和组合 | PKG-CAST-04, CORE-22 | stub 测试之外记录实际 Cast 设备会话、源更新和断开 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-CAST-06 | artplayer-plugin-chromecast
验证分发并同步文档 | PKG-CAST-05, ENG-07 | chromecast.js、SDK URL/权限能力及待支持环境说明 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-document-pip + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-DPIP-01 | artplayer-plugin-document-pip
核对包契约与历史用法 | BASE-05 | width/height/placeholder/fallbackToVideoPiP、open/close/toggle 返回 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-DPIP-02 | artplayer-plugin-document-pip
建立特有行为与错误测试 | PKG-DPIP-01, ENG-03, ENG-05 | 不支持/拒绝、重复打开、pagehide、核心销毁和视频 PiP fallback | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-DPIP-03 | artplayer-plugin-document-pip
整理内部职责与资源 | PKG-DPIP-02, CORE-16, CORE-17 | 窗口生命周期、DOM 迁移、样式与事件 document 重绑分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-DPIP-04 | artplayer-plugin-document-pip
迁移自有源码和公开类型 | PKG-DPIP-03, ENG-04, ENG-06, CORE-07 | Document PiP 可选能力和真实状态/返回类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-DPIP-05 | artplayer-plugin-document-pip
验证新旧核心和组合 | PKG-DPIP-04, CORE-22 | 原生视频及两个 proxy、键盘/焦点/全屏与关闭还原 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-DPIP-06 | artplayer-plugin-document-pip
验证分发并同步文档 | PKG-DPIP-05, ENG-07 | document.pip.js、浏览器能力矩阵、旧接口与恢复证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-plugin-danmuku + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-DANMUKU-01 | artplayer-plugin-danmuku
核对弹幕全部公开契约 | BASE-05 | emit/load/config/hide/show/reset/mount、option/isHide/isStop/icons 与事件清单 | 源码、声明、发布包、Bilibili 输入和设置入口对照 | H | todo | +| PKG-DANMUKU-02 | artplayer-plugin-danmuku
建立弹幕算法与浏览器基线 | PKG-DANMUKU-01, ENG-05, ENG-08 | 密集/稀疏弹幕、过滤/异步输入、seek/倍率/重载测试 | 轨道选择、发射顺序、事件、内存和可视结果可重跑 | H | todo | +| PKG-DANMUKU-03 | artplayer-plugin-danmuku
整理加载、解析与配置 | PKG-DANMUKU-02, CORE-08 | bilibili/input/parser/config 的分层与取消 | 旧格式、回调、过滤、追加/替换语义保持 | M | todo | +| PKG-DANMUKU-04 | artplayer-plugin-danmuku
整理时钟、队列与轨道调度 | PKG-DANMUKU-03, CORE-10 | danmuku 调度器和确定性时钟测试 | seek/暂停/倍率/长时间运行无顺序和碰撞回归 | H | todo | +| PKG-DANMUKU-05 | artplayer-plugin-danmuku
整理 DOM 渲染、设置、热力图与 worker | PKG-DANMUKU-04, CORE-14, CORE-18 | renderer/setting/heatmap/worker 职责及资源归属 | mount/icons/设置和 worker 协议保持,销毁无后台工作 | H | todo | +| PKG-DANMUKU-06 | artplayer-plugin-danmuku
迁移 TS 与公开声明 | PKG-DANMUKU-05, ENG-04, ENG-06 | 自有模块、worker 消息、option/item/result 类型 | 旧参数、扩展字段和事件消费通过,vendored 边界清楚 | H | todo | +| PKG-DANMUKU-07 | artplayer-plugin-danmuku
弹幕能力稳定性验收 | PKG-DANMUKU-06 | 负载/渲染/资源对比及 mask 可依赖的稳定边界 | 在试点核心中旧插件 API 与关键帧路径通过 | H | todo | +| PKG-DANMUKU-08 | artplayer-plugin-danmuku
完成新旧核心与组合验收 | PKG-DANMUKU-07, CORE-22 | 最终核心/旧核心、mask/fullscreen/PiP 组合报告 | 性能无未解释退化,反复装卸无累计资源 | H | todo | +| PKG-DANMUKU-09 | artplayer-plugin-danmuku
完成分发、示例与文档 | PKG-DANMUKU-08, ENG-07 | danmuku.js、README、声明、worker 与产物 | tarball 和静态 icons 等旧调用通过,有独立回退版本 | H | todo | + +## 5 包迁移:artplayer-proxy-canvas + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-CANVAS-01 | artplayer-proxy-canvas
核对包契约与历史用法 | BASE-05 | callback、canvas 原方法、转发 media 属性/方法/事件 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-CANVAS-02 | artplayer-proxy-canvas
建立特有行为与错误测试 | PKG-CANVAS-01, ENG-03, ENG-05 | ready/loadeddata/canplay、play/seek、回调、resize 与销毁 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-CANVAS-03 | artplayer-proxy-canvas
整理内部职责与资源 | PKG-CANVAS-02, CORE-06, CORE-11, CORE-16 | video adapter/原 canvas 方法/RAF 绘制/事件订阅分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-CANVAS-04 | artplayer-proxy-canvas
迁移自有源码和公开类型 | PKG-CANVAS-03, ENG-04, ENG-06, CORE-07 | canvas 与媒体能力的精确组合类型,保持 Result | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-CANVAS-05 | artplayer-proxy-canvas
验证新旧核心和组合 | PKG-CANVAS-04, CORE-22 | 真实 video/canvas 绘制、字幕和 document PiP 恢复 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-CANVAS-06 | artplayer-proxy-canvas
验证分发并同步文档 | PKG-CANVAS-05, ENG-07 | canvas.js、三种产物、调用兼容与资源证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-proxy-mediabunny + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-MB-01 | artplayer-proxy-mediabunny
核对 shim 与媒体契约 | BASE-05 | 全部 option、art.mediabunny、canvas/shim 属性及事件表 | 公开暴露成员和实际发布依赖/资源范围明确 | H | todo | +| PKG-MB-02 | artplayer-proxy-mediabunny
建立真实媒体与事件基线 | PKG-MB-01, ENG-05, ENG-08 | MP4/WebM/HLS/Blob/Stream、seek/错误/轨道切换样本 | ready 事件顺序、音画同步、超时和释放可重跑 | H | todo | +| PKG-MB-03 | artplayer-proxy-mediabunny
整理 input 与加载取消 | PKG-MB-02, CORE-09 | input.js 源检测、输入资源、Range 与取消 | HLS 检测在 input 边界,旧来源类型和超时保持 | H | todo | +| PKG-MB-04 | artplayer-proxy-mediabunny
整理 VideoShim/EventTarget/Engine 协调 | PKG-MB-03, CORE-06, CORE-11 | shim 描述符、事件桥、加载状态和操作隔离 | 公开属性/同步异步返回与事件重入顺序保持 | H | todo | +| PKG-MB-05 | artplayer-proxy-mediabunny
整理视频解码、seek 和帧释放 | PKG-MB-04 | VideoEngine 调度、队列、晚帧处理和资源释放 | 暂停/seek/切源无旧帧覆盖,默认丢帧策略不变 | H | todo | +| PKG-MB-06 | artplayer-proxy-mediabunny
整理音频解码、时钟与同步 | PKG-MB-04 | AudioEngine 时钟、缓冲和 AudioContext 归属 | AV sync、倍速、无音轨、静音/音量和暂停恢复通过 | H | todo | +| PKG-MB-07 | artplayer-proxy-mediabunny
整理 HLS 配对轨道与 selector | PKG-MB-05, PKG-MB-06, CORE-14 | m3u8 配对、质量/音频选择及拓扑清理 | 实际选择高亮、切到无轨道来源清理、无重复 readiness | H | todo | +| PKG-MB-08 | artplayer-proxy-mediabunny
完成 TS 与媒体能力声明 | PKG-MB-07, ENG-04, ENG-06 | 8 个自有 JS 模块迁移与 Result/shim 类型 | 解码器/Stream/DOM 类型清楚,旧 Option 和 art.mediabunny 使用保持 | H | todo | +| PKG-MB-09 | artplayer-proxy-mediabunny
完成新旧核心和真实媒体组合 | PKG-MB-08, CORE-22 | 跨浏览器能力、长播放、DPiP、HLS 音轨/质量报告 | 资源释放、事件顺序、AV sync 与支持范围满足基线 | H | todo | +| PKG-MB-10 | artplayer-proxy-mediabunny
完成分发和文档 | PKG-MB-09, ENG-07 | mediabunny.js、README、依赖版本、三产物和许可 | tarball 可消费、无意外依赖升级、旧调用与回退可用 | H | todo | + +## 5 包迁移:artplayer-tool-iframe + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-IFRAME-01 | artplayer-tool-iframe
核对包契约与历史用法 | BASE-05 | constructor/commit/message/inject、postMessage 协议与历史公开拼写 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-IFRAME-02 | artplayer-tool-iframe
建立特有行为与错误测试 | PKG-IFRAME-01, ENG-03, ENG-05 | 跨窗口消息、ID 匹配、请求失败、重复 inject、销毁中请求 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-IFRAME-03 | artplayer-tool-iframe
整理内部职责与资源 | PKG-IFRAME-02, CORE-02, BASE-07 | 请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-IFRAME-04 | artplayer-tool-iframe
迁移自有源码和公开类型 | PKG-IFRAME-03, ENG-04, ENG-06, CORE-07 | 消息联合类型、回调/Promise 推导、旧公开字段兼容 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-IFRAME-05 | artplayer-tool-iframe
验证新旧核心和组合 | PKG-IFRAME-04, CORE-22 | 真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-IFRAME-06 | artplayer-tool-iframe
验证分发并同步文档 | PKG-IFRAME-05, ENG-07 | iframe.js、示例集成和原 script/class 导出验证 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 5 包迁移:artplayer-tool-thumbnail + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-TOOL-THUMB-01 | artplayer-tool-thumbnail
核对包契约与历史用法 | BASE-05 | 构造/defaults/事件/方法/历史拼写、.esm.js 入口和缺失 types | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-TOOL-THUMB-02 | artplayer-tool-thumbnail
建立特有行为与错误测试 | PKG-TOOL-THUMB-01, ENG-03, ENG-05 | 文件输入/拖放、抽帧网格、begin/end、进度/失败/重复任务 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-TOOL-THUMB-03 | artplayer-tool-thumbnail
整理内部职责与资源 | PKG-TOOL-THUMB-02, CORE-01 | 输入、抽帧队列、网格导出、URL/监听清理分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-TOOL-THUMB-04 | artplayer-tool-thumbnail
迁移自有源码和公开类型 | PKG-TOOL-THUMB-03, ENG-04, ENG-06, CORE-07 | 补齐真实 API 声明,自有 emitter/utils TS 化 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-TOOL-THUMB-05 | artplayer-tool-thumbnail
验证新旧核心和组合 | PKG-TOOL-THUMB-04, CORE-22 | 工具独立浏览器使用,生成缩略图在核心中显示 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-TOOL-THUMB-06 | artplayer-tool-thumbnail
验证分发并同步文档 | PKG-TOOL-THUMB-05, ENG-07 | tool.thumbnail.js、历史 ESM 兼容文件、types 路径和 tarball | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | + +## 6 文档与消费者 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| SITE-01 | artplayer-vitepress
清点文档/示例/生成链 | BASE-04, BASE-05 | 中英文文档、插件页面、demo URL、编辑器声明与生成目录清单 | 所有公开 API/插件有对应页面或明确补充任务 | M | todo | +| SITE-02 | artplayer-vitepress
整理声明与示例生成器 | SITE-01, ENG-04, ENG-06 | build-ts/build-test 生成链的可验证 TS 脚本 | 不靠字符串拼接掩盖声明错误,生成示例有真实断言或仅标 smoke | M | todo | +| SITE-03 | artplayer-vitepress
整理 i18n/文档/LLM 生成流程 | SITE-02 | build-i18n/build-docs/build-llm/trans-docs 的任务边界和错误处理 | 原命令兼容、生成可复现,翻译步骤不隐式运行远程服务 | M | todo | +| SITE-04 | artplayer-vitepress
同步核心和全部插件使用文档 | CORE-22, PKG-CHAPTER-06, PKG-AMBILIGHT-06, PKG-AUDIO-06, PKG-AUTO-THUMB-06, PKG-VTT-THUMB-06, PKG-HLS-06, PKG-DASH-06, PKG-MULTI-SUB-06, PKG-JASSUB-06, PKG-MASK-06, PKG-ASR-06, PKG-ADS-06, PKG-VAST-06, PKG-CAST-06, PKG-DPIP-06, PKG-DANMUKU-09, PKG-CANVAS-06, PKG-MB-10, PKG-IFRAME-06, PKG-TOOL-THUMB-06, SITE-03 | 中文/英文 API、插件选项、兼容说明及旧 JS 用法 | 不要求旧调用迁移,未支持能力不写成已支持 | M | todo | +| SITE-05 | artplayer-vitepress
构建文档站和验证链接/示例 | SITE-04, EX-03 | VitePress 构建、链接与嵌入 demo 检查 | 产物可访问,全部包文档与 types 注入无丢失 | M | todo | +| SITE-06 | artplayer-vitepress
文档站交付验收 | SITE-05 | 维护指南和站点变更记录 | 未手改 generated 目录,旧 URL 可用、部署与检查分离 | M | todo | +| EX-01 | example/react.js
验证 React 消费者与 TS | CORE-22, ENG-07 | React 挂载/卸载/重挂载、引用和插件样例 | 真实 tarball + TS 消费通过,保留既有 React 集成 API | M | todo | +| EX-02 | example/vue.js
验证 Vue 消费者与更新卸载 | CORE-22, ENG-07 | Vue 实例/ref、参数更新、卸载及插件样例 | 旧 JS 组件用法无需修改,重复挂载不泄漏 | M | todo | +| EX-03 | workspace
验证全部原生 demo 与外部播放集成 | EX-01, EX-02, PKG-CHAPTER-06, PKG-AMBILIGHT-06, PKG-AUDIO-06, PKG-AUTO-THUMB-06, PKG-VTT-THUMB-06, PKG-HLS-06, PKG-DASH-06, PKG-MULTI-SUB-06, PKG-JASSUB-06, PKG-MASK-06, PKG-ASR-06, PKG-ADS-06, PKG-VAST-06, PKG-CAST-06, PKG-DPIP-06, PKG-DANMUKU-09, PKG-CANVAS-06, PKG-MB-10, PKG-IFRAME-06, PKG-TOOL-THUMB-06 | 8082 全 demo、HLS/DASH/FLV/MPEGTS/WebTorrent 集成记录 | 旧 URL/参数/脚本加载保持;网络/SDK 限制明确,不静默跳过 | H | todo | + +## 7 工具链与性能 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| MOD-01 | workspace
Bun 固定版本干净安装试点 | ENG-09 | 独立目录的 Bun 锁文件、lifecycle/peer/workspace 与全部构建对比 | Node 测试仍通过;安装与资源一致才决定采用;不改 bundler | H | todo | +| MOD-02 | workspace
整理剩余开发/构建脚本与插件模板 | MOD-01, SITE-03 | dev/build/utils/create-plugin 的 TS 与可测 CLI,模板同时提供旧 API | 旧脚本入口保留、新插件类型/测试/示例齐全,Lerna 改动单独取证 | M | todo | +| MOD-03 | workspace
测量并优化核心热路径 | CORE-22, ENG-08 | DOM 读写、进度更新、持久化、初始化的测量与改进 | 相同设备媒体多次比较,契约不变,收益及无效尝试记录 | M | todo | +| MOD-04 | workspace
测量并优化重型插件/proxy | PKG-DANMUKU-09, PKG-MASK-06, PKG-MB-10, ENG-08 | 帧/队列/推理/音画同步与资源长期运行比较 | 不改默认算法/阈值,性能改善有证据;无收益则保留旧实现 | M | todo | +| MOD-05 | workspace
完成工具链与性能采用决策 | MOD-02, MOD-03, MOD-04 | 最终 runtime/packageManager/构建配置及性能台账 | 干净安装和全包检查通过;Bun 未采用有理由,不为状态强行切换 | M | todo | + +## 8 发布验收 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| REL-01 | workspace
确定分包版本与差异处置 | SITE-06, EX-03, MOD-05 | 每包变更日志/版本/依赖/类型差异及支持范围 | 所有公共差异已解释或解决;未决破坏性变化阻止兼容发布 | H | todo | +| REL-02 | workspace
生成候选 tarball 并验证新旧组合 | REL-01 | 全部候选包与原支持范围消费者安装矩阵 | 新核心旧插件、旧核心新插件、新新组合和历史路径通过 | H | todo | +| REL-03 | workspace
完成真机、外部 SDK 与压力验收 | REL-02 | Safari/移动/PiP/Cast/IMA/模型/长播放完整报告 | 无环境验证的关键能力保持阻塞,mock 不能替代设备结论 | H | todo | +| REL-04 | workspace
演练回退与主线修复同步 | REL-03 | 分包旧版本/tag/依赖回退方案与 master 差异 | 独立回退可行,紧急修复能同步,无需所有用户联动升级 | H | todo | +| REL-05 | workspace
经授权发布候选并收集反馈 | REL-04 | 候选 tag、完整产物 integrity、反馈与复现记录 | 实际发布授权/操作/版本可追溯;本计划不自动执行发布 | H | todo | +| REL-06 | workspace
经授权分批正式发布 | REL-05 | 正式分包版本/tag/站点文档及兼容公告 | 候选验收通过,安装/浏览器复核和回退入口就绪 | H | todo | +| REL-07 | workspace
关闭重构里程碑并维护后续队列 | REL-06 | 最终任务/设计/证据归档和维护指南 | 全范围任务有结论、无未解释兼容缺口;遗留项有明确后续责任 | L | todo | + +## 完成证据与阻塞 + +- DOC-01: [记录](progress.md) +- DOC-02: [记录](progress.md) +- DOC-03: [记录](progress.md) +- DOC-04: [记录](progress.md) +- DOC-05: [记录](changes/2026-09-10-DOC-05-task-commits.md) diff --git a/refactor/progress.md b/refactor/progress.md new file mode 100644 index 000000000..fbf44d7a2 --- /dev/null +++ b/refactor/progress.md @@ -0,0 +1,61 @@ +# 进度与证据 + +## 2026-09-10:建立重构工作区 + +- 分支:`codex/compatible-modernization`,由干净 master 创建。 +- 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。 +- 已清点:22 包、全部插件、proxy、工具、文档与 React/Vue 示例;逐步任务以 tasks.json 为准。 +- 本轮修改仅包含重构文档、其生成/校验工具,以及 AGENTS.md 的文档入口。未修改生产源码、声明或发布产物。 +- 初始化阶段 DOC-01 至 DOC-04 完成时尚未提交。用户随后要求每任务独立 commit;已有规划文件作为 DOC-05 初始文档基线入库,实际提交以 Git 日志中的 `[DOC-05]` 为准。未推送、未发布。 + +本轮交付共 190 个任务:4 个 DOC 规划任务完成,186 个实施/验收任务待执行。包括核心 22 步,普通生态包各 6 步,danmuku 9 步,MediaBunny 10 步,另含基线、工程、文档、消费者、工具链和发布任务。 + +本轮文档验证: + +- `node refactor/scripts/plan.mjs --write` 与 `--check`:任务 ID/状态/依赖、无环检查、22 包覆盖、完成证据和计划同步通过。 +- 本地 Markdown 文件链接共 30 个均存在;初始清单中的 manifest、源码、类型和 demo 路径均存在。manifest 自身声明的缺失目标仍如实登记,不伪造文件。 +- `node --check refactor/scripts/plan.mjs`:通过。 +- `git diff --check`:通过;工作区仅 AGENTS.md 和 refactor/ 变化。 +- 本轮没有重跑生产源码测试或浏览器播放;没有生产源码修改。 + +## 先前评估证据 + +以下来自建立计划前的同一会话评估,属于初步诊断,不代替 BASE 阶段的已发布产物基线与完整浏览器测试: + +| 检查 | 结果与限制 | +| --- | --- | +| `node --test test/playback.test.js test/dash-control.test.js` | Node 25.2.1,19 项通过;这是 mock/单元测试 | +| 核心 src/types、test、scripts/*.js 的 ESLint(不加 --fix) | 通过;没有把插件模板占位符作为普通源码 lint | +| 三个 TS 样例,TS 5.9.3、strict、types: [] | 通过;未隔离环境类型时存在第三方 DOM/WebCodecs/markdown 声明冲突 | +| 使用项目构建配置 write:false 进行 ESM/现代 UMD/legacy UMD 内存构建 | 成功;不是完整 npm pack 或全部发布构建;未写产物 | +| 销毁源码隔离探针 | 重复 destroy 可误删其他实例注册项;需要正式回归用例 | +| 连续切源源码隔离探针 | 一次 canplay 可结算两次切源;尚未真实浏览器复现影响 | +| `bun test ./test/playback.test.js ./test/dash-control.test.js` | Bun 1.3.14:1 通过、18 失败,mock.fn 不兼容;未来版本需重测 | + +## 清点中新增的待核对项 + +- artplayer-tool-thumbnail:manifest 的 types 目标当前不存在,ESM 历史路径与统一构建命名不同;在包契约任务中核对发布内容。 +- ads、VAST、auto-thumbnail、vtt-thumbnail 等包的声明与源码参数/同步异步形状需要逐项对照。 +- JASSUB、字幕 parser、screenfull 等第三方复制代码需要来源与许可台账。 +- package-inventory 是当前 checkout 的清单,npm 发布基线尚未获取。 + +## 下一步 + +2026-09-10 新增 DOC-05,记录并落实“每完成一项任务立即独立本地 commit”。总任务现为 191 项,DOC-01 至 DOC-05 的规划交付与 186 个待执行任务以 tasks.json 为准。DOC-05 的范围是文档初始化和提交纪律,不包含生产实现;具体检查与提交主题见 changes/2026-09-10-DOC-05-task-commits.md。 + +2026-09-10 用户补充要求已落实到 quality-contract.md、ADR-013、根 AGENTS.md、AI 工作流程和变更模板:自主改进不合理内部设计、TS 化同时拆清模块、增加风险对应的有效测试,并持续维护包内架构和后续 AI 接续文档。初始任务数量保持 190,可按后续发现扩展;这次更新不代表开始或完成任何生产代码重构。 + +从 BASE-01 开始取得并固定消费者版本基线;随后完成接口/事件/DOM/包分发清单及 ENG 测试基础。当前没有任何核心或插件重构任务被标为完成。 + +## 会话记录模板 + +```text +日期 / HEAD / 分支: +任务 ID 和实际修改: +兼容差异与决策: +验证命令、环境、结果、报告: +未验证项与阻塞: +变更记录链接: +下一步与依赖: +提交/推送/发布状态: +``` diff --git a/refactor/quality-contract.md b/refactor/quality-contract.md new file mode 100644 index 000000000..6fa64064c --- /dev/null +++ b/refactor/quality-contract.md @@ -0,0 +1,68 @@ +# 全项目重构质量与验收要求 + +## 用户确认的目标与授权 + +2026-09-10,用户进一步明确:使用 TypeScript 重构时必须拆清文件和模块,持续维护方便后续 AI 接续维护与迭代的文档;允许主动修改项目中不合理的设计,并增加足够的测试用例。既有前提继续有效:大量用户正在使用,暴露接口必须兼容旧版本。 + +本要求适用于全部核心、插件、proxy、工具及相关工程流程,是每项实施任务的共同验收条件。任务表不构成修改范围的上限;发现新问题时补充或拆分任务,记录证据后继续推进已授权的内部改造,无需逐项重新询问常规文件拆分、内部重命名、类型和测试设计。 + +这项授权允许修复和改进内部实现,包括消除重复逻辑、整理依赖、调整目录、明确异步状态、资源回收和工程流程;不能把改变公开接口、默认产品行为或未经验证的依赖大升级当作内部整理。遇到实际兼容冲突,优先使用兼容门面、旧入口转发或能力 fallback,无法兼容时明确记录取舍。 + +## 1. TypeScript 与文件拆分 + +- 迁移覆盖自有生产源码;同时整理职责、依赖和状态归属,不以改扩展名或补类型断言作为完成。 +- 文件按职责划分:纯计算/解析、状态与调度、媒体/SDK adapter、DOM 渲染、事件与资源管理分别审查。 +- 公共入口清楚,内部依赖方向可解释;避免循环依赖、所有模块都接收整个 art、含义不清的公共 utils 堆积。 +- 不按固定行数机械拆文件。简单功能可以保留在一个文件,复杂文件必须解释边界,避免过度抽象和大量只有转发的碎文件。 +- 将公开 API 与内部实现分开,使后续更换内部实现时无需改变用户调用。 +- 为遗留 JS、vendored 文件、必要类型断言登记原因与边界;例外不意味着可以隐藏未完成迁移。 + +## 2. 不合理设计的主动审查 + +每个模块审查:重复代码、隐式全局状态、初始化依赖、异常处理、竞态、资源泄漏、陈旧回调、类型与实现漂移、不可测试的依赖、无依据的性能开销和失效文档。 + +发现的问题分成已复现缺陷、可验证的设计改进、待取证疑点。前两类可在兼容边界内自主解决,必要时扩展 tasks.json;疑点先验证,不把猜测写成已修复缺陷。范围较大的调整分批交付,保留可回退边界。 + +## 3. 面向后续 AI 的模块文档 + +每个迁移包必须在包内 README 或 ARCHITECTURE.md 维护实现地图。复杂核心/插件需要单独的架构文档;简单包用 README 的维护章节即可,避免复制无意义模板。 + +文档必须解释: + +1. 主要文件各自负责什么、公开入口在哪里、内部依赖方向。 +2. 关键数据流、状态转换、事件/Promise 的重要顺序。 +3. DOM/监听器/定时器/请求/worker/媒体资源由谁创建、谁释放。 +4. 哪些历史接口、类型、别名、样式和行为是兼容边界,为什么保留。 +5. 修改某项能力通常应从哪个模块开始,哪些组合需要回归。 +6. 可以实际执行的测试、类型检查、构建和 demo 命令。 +7. 已知限制、未验证环境、遗留事项及对应任务/决策链接。 + +实现变更必须在同一批更新相关文档,不把维护说明留到最后集中补写。refactor 下记录迁移过程,包内文档记录最终实际架构;两者用途不同,避免维护两份相互冲突的文件地图。 + +## 4. 足够且有效的测试 + +- 以风险和公开行为决定测试范围,不以测试数量或统一覆盖率数字作为唯一完成标准。 +- 每个被修复缺陷有复现用例;每个迁移边界有正常、边界、失败和必要生命周期测试。 +- 异步能力重点覆盖连续操作、乱序完成、取消、重复调用、销毁中回调和异常传播。 +- 对 API/事件/返回值/类型/入口的兼容建立消费者用例,包含新核心旧插件和原支持范围旧核心新插件。 +- 媒体播放、DOM 交互、跨窗口及 codec/SDK 能力需要对应浏览器或真实环境证据,mock 只验证可控部分。 +- 纯目录移动、文案和低影响格式修改复用现有检查,不添加只重复实现的测试。 +- 不通过删除失败用例、无理由跳过、宽泛断言、全量更新快照或扩大超时制造通过结果。 + +## 5. 完成门槛 + +实施任务标为 done 前,在变更记录中逐项说明: + +| 项目 | 所需证据 | +| --- | --- | +| 结构 | 职责与依赖清楚,拆分理由明确,不合理设计已处理或链接后续任务 | +| 类型 | 对应严格检查和消费者样例通过,类型声明与运行时一致 | +| 兼容 | 旧 API、类型、事件/Promise、DOM/CSS 和分发路径没有未经处理的回归 | +| 测试 | 风险对应的用例、运行结果和限制;修复问题有可重跑复现 | +| 文档 | 实际模块地图、维护入口、命令和决策随实现更新 | +| 交接 | 变更、任务状态、剩余问题、下一步及回退方法可追溯 | +| 提交 | 每个完成任务已有独立本地 commit,包含任务 ID 与实现/测试/文档/状态,提交结果已核实 | + +只有文档或计划变更时,如实记录文档验证,不能声称上述生产代码和浏览器验收已经完成。 + +用户补充要求:每完成一个任务就提交一个 commit。本地提交是任务交付的一部分,不能只改状态而不提交,也不能积累多个已完成任务后合并提交;执行方式见 ai-workflow.md。 diff --git a/refactor/roadmap.md b/refactor/roadmap.md new file mode 100644 index 000000000..b5b009d1f --- /dev/null +++ b/refactor/roadmap.md @@ -0,0 +1,45 @@ +# 阶段路线 + +执行细节与状态见 [完整计划表](plan.md)。本表只描述阶段目标;依赖关系由 [tasks.json](tasks.json) 维护。 + +| 阶段 | 任务前缀 | 工作 | 阶段出口 | +| --- | --- | --- | --- | +| 0 规划 | DOC | 创建分支、包清点、契约和文档维护机制 | 22 个包全部有任务,校验脚本通过 | +| 1 基线 | BASE | 已发布版本取证、API/事件/DOM/产物/性能快照、缺陷台账 | 有可重跑的兼容基线;历史版本范围明确 | +| 2 工程保障 | ENG | 固定工具链、只读 CI、单测、浏览器测试、类型/发布包检查、非交互构建 | 从干净环境可以执行可靠检查 | +| 3 生命周期与类型基础 | CORE-01 至 CORE-08 | 纯工具、Emitter、资源回收、销毁、配置、内部类型、插件管理器 | 小插件试点能基于稳定边界进行 | +| 4 核心模块 | CORE-09 至 CORE-22 | 播放和切源、媒体适配、字幕、UI、设置、模式、输入、内置插件、入口和声明 | 核心类型与实现一致,旧行为和首批旧插件通过 | +| 5 生态迁移 | PKG | 全部插件/proxy/工具按包的步骤迁移 | 每包测试、声明、demo 和发布包检查有证据 | +| 6 文档及消费者 | SITE / EX | 文档站、示例、生成器、React/Vue/原生集成 | 文档和消费者使用真实产物通过 | +| 7 Bun 与性能 | MOD | Bun 依赖管理试点、脚本整理、热路径测量优化 | Node 回归保留,性能收益有基线比较 | +| 8 发布验收 | REL | 新旧组合、候选包、真机、灰度、维护分支和回退演练 | 分包发布结论完整、可恢复旧版本 | + +## 执行顺序 + +1. 完成 DOC 后,先做 BASE,再做 ENG。已有测试继续保留。 +2. CORE-01 至 CORE-08 形成最小稳定边界后,用 chapter 等简单插件验证 TS 和旧插件契约。简单插件的契约采集可以更早完成。 +3. 播放、设置、字幕和媒体接口分别稳定后,再推进相应插件;不要求等整个核心完成才开始所有生态任务。 +4. danmuku、MediaBunny、跨文档 PiP、ASR、外部 SDK 插件各自分批,不能与基础播放改造混在同一补丁中。 +5. 所有包的集成/发布验收依赖 CORE-22;早期试点通过不能代替最终核心上的重新验证。 +6. Bun 替换默认包管理器需要干净安装试点证据;不要求迁移所有插件后才试验,但最终采用决策在发布前完成。 +7. 生命周期缺陷修复、TS 迁移、目录移动、依赖升级、行为增强应形成不同变更记录。单个小步骤确实不可分时记录原因。 + +## 里程碑 + +- M1:固定旧契约、历史版本矩阵和已知缺陷,CI 能在 PR 上执行。 +- M2:核心生命周期和类型基础稳定,一个简单插件端到端迁移完成。 +- M3:核心和全部生态包完成 TS/边界整理,源码与产物测试通过。 +- M4:候选包完成新旧组合、真机、文档和性能验证,准备分包灰度发布。 +- M5:灰度结论通过并完成正式发布记录;旧版本继续可安装、可回退。 + +## 范围限制 + +- 不强制用户升级所有插件,不增加浏览器端 Bun 依赖,不取消旧入口或 legacy 产物。 +- 不把核心改为依赖 React/Vue,不默认增加远程 AI 请求或模型下载。AI 主要改善工程流程;已有 ASR/分割插件按原能力边界维护。 +- 不顺带重写第三方 vendored 实现;如 JASSUB、字幕 parser、screenfull,先记录来源、许可和更新方式。 +- 不用“保持旧 API”掩盖安全问题。安全修正应单独取证、评估影响并安排发布,不能顺手更改默认协议或混入结构迁移。 +- 后续新增功能、重命名公开字段、删除历史拼写、统一所有插件返回形状,不属于默认重构范围。 + +## 维护与回退 + +本分支接收独立、可审查的变更。开始每批之前记录 HEAD 和工作区状态;与 master 同步时先识别重叠更改,再重跑受影响的兼容检查。主线紧急修复可回移到本分支,禁止在共享分支上重写他人历史。每批记录可回退提交;正式提交和发布在实际执行时按用户授权范围进行。 diff --git a/refactor/scripts/plan.mjs b/refactor/scripts/plan.mjs new file mode 100644 index 000000000..09a2a244a --- /dev/null +++ b/refactor/scripts/plan.mjs @@ -0,0 +1,122 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const dir = fileURLToPath(new URL('../', import.meta.url)) +const root = path.resolve(dir, '..') +const data = JSON.parse(fs.readFileSync(path.join(dir, 'tasks.json'), 'utf8')) +const inventory = JSON.parse(fs.readFileSync(path.join(dir, 'package-inventory.json'), 'utf8')) +const states = new Set(['todo', 'doing', 'blocked', 'done', 'deferred']) +const ids = new Map() + +assert.equal(data.schemaVersion, 1) +assert.equal(data.baselineCommit, inventory.baselineCommit) +assert.equal(data.qualityContract, 'quality-contract.md') +assert(fs.existsSync(path.join(dir, data.qualityContract)), 'Missing shared quality contract') +for (const task of data.tasks) { + assert(typeof task.id === 'string' && /^[A-Z]+(?:-[A-Z]+)*-\d{2}$/.test(task.id), `Invalid ID: ${task.id}`) + assert(!ids.has(task.id), `Duplicate ID: ${task.id}`) + assert(states.has(task.status), `Invalid status: ${task.id}`) + assert(['L', 'M', 'H'].includes(task.risk), `Invalid risk: ${task.id}`) + for (const key of ['phase', 'title', 'deliverable', 'acceptance']) { + assert(typeof task[key] === 'string' && task[key].trim(), `Missing ${key}: ${task.id}`) + } + for (const key of ['scope', 'dependsOn', 'evidence']) { + assert(Array.isArray(task[key]), `Invalid ${key}: ${task.id}`) + } + assert(task.scope.length, `Missing scope: ${task.id}`) + assert(new Set(task.dependsOn).size === task.dependsOn.length, `Duplicate dependency: ${task.id}`) + if (task.status === 'done') { + assert(task.evidence.length, `Missing evidence: ${task.id}`) + } + if (task.status === 'blocked' || task.status === 'deferred') { + assert(typeof task.reason === 'string' && task.reason.trim(), `Missing reason: ${task.id}`) + } + for (const evidence of task.evidence) { + assert(typeof evidence === 'string' && evidence.trim(), `Invalid evidence: ${task.id}`) + if (/^https?:\/\//.test(evidence)) continue + const resolved = path.resolve(dir, evidence.split('#')[0]) + const relative = path.relative(dir, resolved) + assert(!relative.startsWith('..') && !path.isAbsolute(relative), `Evidence outside refactor: ${task.id}`) + assert(fs.existsSync(resolved), `Missing evidence file: ${evidence}`) + assert(!relative.replaceAll('\\', '/').endsWith('TEMPLATE.md'), `Template is not evidence: ${task.id}`) + } + ids.set(task.id, task) +} + +const visited = new Set() +const visiting = new Set() +function visit(id) { + assert(ids.has(id), `Unknown dependency: ${id}`) + assert(!visiting.has(id), `Dependency cycle at ${id}`) + if (visited.has(id)) return + visiting.add(id) + for (const dependency of ids.get(id).dependsOn) { + visit(dependency) + if (['doing', 'done'].includes(ids.get(id).status)) { + assert.equal(ids.get(dependency).status, 'done', `Unfinished dependency ${dependency} for ${id}`) + } + } + visiting.delete(id) + visited.add(id) +} +for (const id of ids.keys()) visit(id) + +const packageNames = inventory.packages.map(pkg => pkg.name).sort() +const currentNames = fs.readdirSync(path.join(root, 'packages')) + .filter(name => fs.existsSync(path.join(root, 'packages', name, 'package.json'))).sort() +assert.deepEqual(currentNames, packageNames, 'Package scope changed: record the scope decision and update the validator/baseline policy') +for (const name of packageNames) { + assert(data.tasks.some(task => task.scope.includes(name)), `Package not planned: ${name}`) +} +const scopes = new Set([...packageNames, 'workspace', 'example/react.js', 'example/vue.js']) +for (const task of data.tasks) { + for (const scope of task.scope) assert(scopes.has(scope), `Unknown scope ${scope}: ${task.id}`) +} + +let localLinks = 0 +const markdownFiles = fs.readdirSync(dir, { recursive: true }) + .filter(file => file.endsWith('.md')).map(file => path.join(dir, file)) +for (const file of [...markdownFiles, path.join(root, 'AGENTS.md')]) { + const content = fs.readFileSync(file, 'utf8') + for (const match of content.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) { + const href = match[1] + if (/^(?:https?:|#)/.test(href)) continue + localLinks += 1 + assert(fs.existsSync(path.resolve(path.dirname(file), href.split('#')[0])), `Broken local link in ${path.relative(root, file)}: ${href}`) + } +} + +const cell = value => String(value).replaceAll('|', '\\|').replaceAll('\n', '
') +const counts = Object.fromEntries([...states].map(state => [state, data.tasks.filter(task => task.status === state).length])) +const lines = [ + '# 完整重构执行计划表', '', + '> 由 tasks.json 生成。请修改数据后运行 `node refactor/scripts/plan.mjs --write`,不要手改本表。', '', + `基线:\`${data.baselineCommit}\`。总任务 ${data.tasks.length} 项,范围 ${packageNames.length} 个包及工作区/示例。`, '', + `状态:${Object.entries(counts).map(([state, count]) => `${state} ${count}`).join(' / ')}。风险 L/M/H 表示兼容风险,不表示工期。`, '', + '前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。', '', + `每项实施任务同时适用[全项目质量要求](${data.qualityContract}):清晰拆分职责和依赖,主动改善不合理设计,以有效测试证明旧接口兼容,并同步维护后续 AI 可接续的包内文档。`, '', + '## 包覆盖索引', '', + '| 包 | 基线版本 | 任务 |', '| --- | --- | --- |', + ...inventory.packages.map(pkg => `| ${pkg.name} | ${pkg.version} | ${data.tasks.filter(task => task.scope.includes(pkg.name)).map(task => task.id).join(', ')} |`), '', +] +for (const phase of new Set(data.tasks.map(task => task.phase))) { + lines.push(`## ${phase}`, '', '| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |', '| --- | --- | --- | --- | --- | --- | --- |') + for (const task of data.tasks.filter(item => item.phase === phase)) { + lines.push(`| ${[task.id, `${task.scope.join(', ')}
${task.title}`, task.dependsOn.join(', ') || '-', task.deliverable, task.acceptance, task.risk, task.status].map(cell).join(' | ')} |`) + } + lines.push('') +} +lines.push('## 完成证据与阻塞', '') +for (const task of data.tasks.filter(item => item.evidence.length || item.reason)) { + lines.push(`- ${task.id}: ${task.evidence.map(link => `[记录](${link})`).join(' ')}${task.reason ? ` ${task.reason}` : ''}`) +} +lines.push('') +const output = `${lines.join('\n').trimEnd()}\n` +const target = path.join(dir, 'plan.md') +const mode = process.argv[2] +assert(['--write', '--check'].includes(mode), 'Use --write or --check') +if (mode === '--write') fs.writeFileSync(target, output) +else assert.equal(fs.readFileSync(target, 'utf8'), output, 'plan.md is stale; run --write') +console.log(`Plan ${mode}: ${data.tasks.length} tasks, ${packageNames.length} packages, ${localLinks} local links, no dependency cycles; ${JSON.stringify(counts)}`) diff --git a/refactor/tasks.json b/refactor/tasks.json new file mode 100644 index 000000000..47ed1f007 --- /dev/null +++ b/refactor/tasks.json @@ -0,0 +1,3347 @@ +{ + "schemaVersion": 1, + "date": "2026-09-10", + "baselineCommit": "40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f", + "branch": "codex/compatible-modernization", + "qualityContract": "quality-contract.md", + "tasks": [ + { + "id": "DOC-01", + "phase": "0 规划", + "title": "创建兼容重构分支", + "scope": [ + "workspace" + ], + "dependsOn": [], + "status": "done", + "risk": "L", + "deliverable": "独立本地分支和起点 SHA", + "acceptance": "分支由干净 master 创建,起点可追溯", + "evidence": [ + "progress.md" + ] + }, + { + "id": "DOC-02", + "phase": "0 规划", + "title": "清点全部包与消费者", + "scope": [ + "workspace" + ], + "dependsOn": [ + "DOC-01" + ], + "status": "done", + "risk": "L", + "deliverable": "package-inventory.json", + "acceptance": "22 包及 React/Vue/demo 有明确清单", + "evidence": [ + "progress.md" + ] + }, + { + "id": "DOC-03", + "phase": "0 规划", + "title": "建立计划、契约、决策和协作记录", + "scope": [ + "workspace" + ], + "dependsOn": [ + "DOC-02" + ], + "status": "done", + "risk": "L", + "deliverable": "refactor 文档集与任务数据", + "acceptance": "每包有独立步骤、依赖、交付物和验收条件", + "evidence": [ + "progress.md" + ] + }, + { + "id": "DOC-04", + "phase": "0 规划", + "title": "验证文档完整性与生成表", + "scope": [ + "workspace" + ], + "dependsOn": [ + "DOC-03" + ], + "status": "done", + "risk": "L", + "deliverable": "计划生成校验工具、AGENTS 入口", + "acceptance": "依赖无环、包覆盖、生成同步、文档链接通过", + "evidence": [ + "progress.md" + ] + }, + { + "id": "DOC-05", + "phase": "0 规划", + "title": "建立每任务提交规则并提交文档基线", + "scope": [ + "workspace" + ], + "dependsOn": [ + "DOC-04" + ], + "status": "done", + "risk": "L", + "deliverable": "根指令、质量要求、AI 流程、变更记录与初始文档提交", + "acceptance": "文档与计划检查通过,独立 DOC-05 commit 保存本次交付;提交后核实 SHA 和工作区", + "evidence": [ + "changes/2026-09-10-DOC-05-task-commits.md" + ] + }, + { + "id": "BASE-01", + "phase": "1 基线", + "title": "固定消费者发布基线", + "scope": [ + "workspace" + ], + "dependsOn": [ + "DOC-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "各包 npm tarball/integrity、源码 SHA、历史支持矩阵", + "acceptance": "区分源码版本与实际已发布版本,最低核心/TS/浏览器支持有证据", + "evidence": [] + }, + { + "id": "BASE-02", + "phase": "1 基线", + "title": "捕获公共 API 和属性描述符", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-01" + ], + "status": "todo", + "risk": "H", + "deliverable": "构造参数/默认值/静态及实例 API 快照", + "acceptance": "真实发布包反射与旧用户调用可重跑,未验证项明确", + "evidence": [] + }, + { + "id": "BASE-03", + "phase": "1 基线", + "title": "捕获事件、异步和生命周期", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-02" + ], + "status": "todo", + "risk": "H", + "deliverable": "ready/restart/destroy、Promise、切源/插件事件 trace", + "acceptance": "成功、失败、重入和多实例有断言,历史缺陷有标记", + "evidence": [] + }, + { + "id": "BASE-04", + "phase": "1 基线", + "title": "捕获 DOM、CSS 和官方 demo", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-02" + ], + "status": "todo", + "risk": "M", + "deliverable": "模板/类名/变量及全部 demo 映射", + "acceptance": "用户样式覆盖、移动端与自定义 controls/setting 用法已记录", + "evidence": [] + }, + { + "id": "BASE-05", + "phase": "1 基线", + "title": "捕获包入口、资源和类型消费", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-01" + ], + "status": "todo", + "risk": "H", + "deliverable": "UMD/AMD/ESM/CJS/legacy/i18n、worker/WASM/字体路径矩阵", + "acceptance": "隔离消费者验证入口,记录 thumbnail tool 等不一致", + "evidence": [] + }, + { + "id": "BASE-06", + "phase": "1 基线", + "title": "记录性能与资源基线", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-03", + "BASE-04" + ], + "status": "todo", + "risk": "M", + "deliverable": "固定媒体/设备测量、包体积、反复装卸资源报告", + "acceptance": "多次采样可重跑,指标和审查阈值确定,不承诺未经测量的收益", + "evidence": [] + }, + { + "id": "BASE-07", + "phase": "1 基线", + "title": "建立差异和风险台账", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-03", + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "销毁/切源/类型差异、vendored 许可和外部 SDK 清单", + "acceptance": "已确认与待复现分开,每项有负责任务及兼容处理路线", + "evidence": [] + }, + { + "id": "ENG-01", + "phase": "2 工程保障", + "title": "固定 Node、包管理器与依赖", + "scope": [ + "workspace" + ], + "dependsOn": [ + "BASE-01" + ], + "status": "todo", + "risk": "M", + "deliverable": "版本 pin、唯一锁文件、安装说明", + "acceptance": "干净环境可复现,最低 Node 与构建依赖一致,未夹带全量升级", + "evidence": [] + }, + { + "id": "ENG-02", + "phase": "2 工程保障", + "title": "拆分只读检查并建立 PR CI", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-01" + ], + "status": "todo", + "risk": "M", + "deliverable": "lint/lint:fix、PR 与主线检查、独立部署任务", + "acceptance": "检查不改源码、不发布,失败阻止合并;必要 required check 有配置证据", + "evidence": [] + }, + { + "id": "ENG-03", + "phase": "2 工程保障", + "title": "建立公共行为与单元测试入口", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-02", + "BASE-03" + ], + "status": "todo", + "risk": "M", + "deliverable": "保留现有 node:test,测试目录/夹具/统一入口", + "acceptance": "已有 19 项回归保留,旧版与候选可用同一夹具运行", + "evidence": [] + }, + { + "id": "ENG-04", + "phase": "2 工程保障", + "title": "建立类型测试基础", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-02", + "BASE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "根与分包 tsconfig、显式 TS 依赖、正反例测试", + "acceptance": "隔离 DOM/Node/worker 类型,最低和选定当前 TS 验证声明消费", + "evidence": [] + }, + { + "id": "ENG-05", + "phase": "2 工程保障", + "title": "建立真实浏览器测试服务", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-03", + "BASE-04" + ], + "status": "todo", + "risk": "M", + "deliverable": "Playwright projects、本地 Range/失败媒体服务", + "acceptance": "Chromium/Firefox/WebKit 的基础播放 smoke 和报告可执行", + "evidence": [] + }, + { + "id": "ENG-06", + "phase": "2 工程保障", + "title": "支持按包非交互与 JS/TS 构建", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-02", + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "build/dev 入口解析、指定包参数、原交互保留", + "acceptance": "三种产物、Less/SVG/worker 和本地 8082 demo 正常", + "evidence": [] + }, + { + "id": "ENG-07", + "phase": "2 工程保障", + "title": "建立 tarball 消费与产物检查", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-04", + "ENG-06" + ], + "status": "todo", + "risk": "H", + "deliverable": "隔离 npm 消费 fixtures、API/声明/入口差分", + "acceptance": "不借 workspace 源码通过,能识别缺文件与默认导出变化", + "evidence": [] + }, + { + "id": "ENG-08", + "phase": "2 工程保障", + "title": "增加覆盖率、资源与性能报告", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-03", + "ENG-05", + "BASE-06" + ], + "status": "todo", + "risk": "M", + "deliverable": "覆盖率基线、资源清理断言、性能报告与阈值", + "acceptance": "关键生命周期分支有门槛,报告不靠无意义断言堆数量", + "evidence": [] + }, + { + "id": "ENG-09", + "phase": "2 工程保障", + "title": "建立全包依赖影响和文档检查", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-07", + "DOC-04" + ], + "status": "todo", + "risk": "M", + "deliverable": "共享核心/构建影响映射、计划文档检查接入", + "acceptance": "核心变化触发全生态必需检查,新增包不会漏计划", + "evidence": [] + }, + { + "id": "CORE-01", + "phase": "3-4 核心迁移", + "title": "迁移纯工具并冻结导出", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "ENG-03", + "ENG-04", + "ENG-06" + ], + "status": "todo", + "risk": "M", + "deliverable": "utils/time/property/format/file/error/subtitle 的分批 TS 迁移", + "acceptance": "Artplayer.utils 导出/参数/绑定保持,纯逻辑与类型测试通过", + "evidence": [] + }, + { + "id": "CORE-02", + "phase": "3-4 核心迁移", + "title": "迁移内部 Emitter", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-01", + "BASE-03" + ], + "status": "todo", + "risk": "H", + "deliverable": "带类型事件映射的原 Emitter 实现", + "acceptance": "ctx、once/off、重入/异常和链式返回保持", + "evidence": [] + }, + { + "id": "CORE-03", + "phase": "3-4 核心迁移", + "title": "建立内部资源作用域", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-02" + ], + "status": "todo", + "risk": "H", + "deliverable": "监听/订阅/定时器/RAF/请求/URL 的资源登记", + "acceptance": "实例与操作作用域分离,单项清理失败不阻断其他资源", + "evidence": [] + }, + { + "id": "CORE-04", + "phase": "3-4 核心迁移", + "title": "修复初始化与销毁生命周期", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-03", + "ENG-05", + "BASE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "构造失败回收、重复/重入 destroy、instances 修复", + "acceptance": "事件顺序、removeHtml、多实例和销毁中异步有真实回归", + "evidence": [] + }, + { + "id": "CORE-05", + "phase": "3-4 核心迁移", + "title": "区分输入配置和内部配置", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-01", + "ENG-04" + ], + "status": "todo", + "risk": "M", + "deliverable": "Option/ResolvedOption、默认值与校验整理", + "acceptance": "配置合并/错误时机不变,JS 输入仍运行时校验", + "evidence": [] + }, + { + "id": "CORE-06", + "phase": "3-4 核心迁移", + "title": "建立内部媒体与宿主类型", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "原生 video、canvas shim、UI host 类型", + "acceptance": "不更改公开 art.video 用法,不以 HTMLVideoElement 断言掩盖 shim", + "evidence": [] + }, + { + "id": "CORE-07", + "phase": "3-4 核心迁移", + "title": "逐项协调公开声明差异", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-02", + "CORE-06", + "BASE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "plugins/toggle/cue/setting/static 的旧新类型对照", + "acceptance": "每项有兼容重载/扩展或待决结论,不能删除旧类型样例", + "evidence": [] + }, + { + "id": "CORE-08", + "phase": "3-4 核心迁移", + "title": "整理插件管理器与扩展类型", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-03", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "注册流程、同步/异步结果、插件/事件扩展接口", + "acceptance": "旧插件同步可见性、重名与命名、销毁中异步插件保持明确语义", + "evidence": [] + }, + { + "id": "CORE-09", + "phase": "3-4 核心迁移", + "title": "整理 URL 与切源操作", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-04", + "CORE-06", + "CORE-08" + ], + "status": "todo", + "risk": "H", + "deliverable": "url/switch/customType 的操作身份及取消方案", + "acceptance": "并发切源、错误、同 URL、销毁和 Promise 结算有契约", + "evidence": [] + }, + { + "id": "CORE-10", + "phase": "3-4 核心迁移", + "title": "迁移播放与时间/状态属性", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-09" + ], + "status": "todo", + "risk": "H", + "deliverable": "play/pause/toggle/seek/volume/rate/duration 等模块", + "acceptance": "旧返回值、拒绝、mutex、位置恢复、属性描述符与事件通过", + "evidence": [] + }, + { + "id": "CORE-11", + "phase": "3-4 核心迁移", + "title": "整理媒体事件、ready 与重连", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-10" + ], + "status": "todo", + "risk": "H", + "deliverable": "媒体转发、重连、UI 响应职责分离", + "acceptance": "readiness 次数/顺序、过期重连、原错误参数有回归", + "evidence": [] + }, + { + "id": "CORE-12", + "phase": "3-4 核心迁移", + "title": "迁移模板及公开资源入口", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-06", + "CORE-04", + "BASE-04" + ], + "status": "todo", + "risk": "H", + "deliverable": "template/icons/i18n/style、SSR 与 proxy 挂载", + "acceptance": "DOM/CSS/global/样式注入、i18n 子路径及 SSR import 保持", + "evidence": [] + }, + { + "id": "CORE-13", + "phase": "3-4 核心迁移", + "title": "迁移组件注册与控件", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-12", + "CORE-08" + ], + "status": "todo", + "risk": "H", + "deliverable": "Component/control/layer/contextmenu 的资源与 TS 边界", + "acceptance": "add/update/remove、name、selector、mounted/beforeUnmount 通过", + "evidence": [] + }, + { + "id": "CORE-14", + "phase": "3-4 核心迁移", + "title": "拆分设置树、渲染和布局", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-13" + ], + "status": "todo", + "risk": "H", + "deliverable": "setting model/selection/render/layout 的分批实现", + "acceptance": "不强行统一控件返回值,嵌套选择、默认高亮、更新清理通过", + "evidence": [] + }, + { + "id": "CORE-15", + "phase": "3-4 核心迁移", + "title": "迁移字幕获取、解析和渲染", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-11", + "CORE-13" + ], + "status": "todo", + "risk": "H", + "deliverable": "subtitle 请求/track/DOM/URL 生命周期与类型", + "acceptance": "过期结果、偏移、cue 数组、原生全屏及错误路径通过", + "evidence": [] + }, + { + "id": "CORE-16", + "phase": "3-4 核心迁移", + "title": "迁移全屏、PiP、mini 与尺寸模式", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-11", + "CORE-12" + ], + "status": "todo", + "risk": "H", + "deliverable": "显示模式服务和原公开属性门面", + "acceptance": "模式互斥/恢复位置、手势权限、移动方向和退出失败通过", + "evidence": [] + }, + { + "id": "CORE-17", + "phase": "3-4 核心迁移", + "title": "迁移键盘、手势、焦点和全局事件", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-13", + "CORE-16" + ], + "status": "todo", + "risk": "H", + "deliverable": "events/hotkey 的明确 document 与资源归属", + "acceptance": "跨 document 重绑、触摸/键盘、快捷键及销毁无重复响应", + "evidence": [] + }, + { + "id": "CORE-18", + "phase": "3-4 核心迁移", + "title": "迁移内置插件和提示模块", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-14", + "CORE-16", + "CORE-17" + ], + "status": "todo", + "risk": "M", + "deliverable": "autoPlayback/autoOrientation/fastForward/lock/miniProgressBar 及 info/notice/loading/mask", + "acceptance": "默认启用条件、storage 格式、定时器/动画清理通过", + "evidence": [] + }, + { + "id": "CORE-19", + "phase": "3-4 核心迁移", + "title": "整理进度、质量、缩略图和截图", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-10", + "CORE-13", + "CORE-16" + ], + "status": "todo", + "risk": "M", + "deliverable": "相关 player/control 功能与纯计算分离", + "acceptance": "截图跨域失败、缩略图布局、quality/进度边界保持", + "evidence": [] + }, + { + "id": "CORE-20", + "phase": "3-4 核心迁移", + "title": "收敛核心入口与依赖方向", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-14", + "CORE-15", + "CORE-18", + "CORE-19" + ], + "status": "todo", + "risk": "H", + "deliverable": "Artplayer 门面、初始化依赖与最终目录", + "acceptance": "所有核心自有源码迁移,公开描述符/静态接口/事件差分通过", + "evidence": [] + }, + { + "id": "CORE-21", + "phase": "3-4 核心迁移", + "title": "生成核心声明并校验包内容", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-20", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "由 TS 生成的既有入口声明与三种发布产物", + "acceptance": "内部类型不泄漏,旧 JS/TS 消费者与 i18n 通过", + "evidence": [] + }, + { + "id": "CORE-22", + "phase": "3-4 核心迁移", + "title": "核心阶段完整验收", + "scope": [ + "artplayer" + ], + "dependsOn": [ + "CORE-21", + "PKG-CHAPTER-04" + ], + "status": "todo", + "risk": "H", + "deliverable": "旧插件对候选核心的完整回归与资源/性能报告", + "acceptance": "公开兼容差异有结论,核心测试和简单插件试点通过", + "evidence": [] + }, + { + "id": "PKG-CHAPTER-01", + "phase": "5 包迁移:artplayer-plugin-chapter", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-chapter" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "chapters 时间区间、update、name 和进度 DOM 清单", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-CHAPTER-02", + "phase": "5 包迁移:artplayer-plugin-chapter", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-chapter" + ], + "dependsOn": [ + "PKG-CHAPTER-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "区间重叠/空列表/边界 seek、hover 标题和 update 用例", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-CHAPTER-03", + "phase": "5 包迁移:artplayer-plugin-chapter", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-chapter" + ], + "dependsOn": [ + "PKG-CHAPTER-02", + "CORE-14", + "CORE-08" + ], + "status": "todo", + "risk": "M", + "deliverable": "拆分时间区间计算、进度 DOM、事件与布局", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-CHAPTER-04", + "phase": "5 包迁移:artplayer-plugin-chapter", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-chapter" + ], + "dependsOn": [ + "PKG-CHAPTER-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "Chapters/Option/Result 与 update 推导,先做简单插件 TS 试点", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-CHAPTER-05", + "phase": "5 包迁移:artplayer-plugin-chapter", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-chapter" + ], + "dependsOn": [ + "PKG-CHAPTER-04", + "CORE-22" + ], + "status": "todo", + "risk": "M", + "deliverable": "chapter + quality/thumbnail、移动和全屏进度场景", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-CHAPTER-06", + "phase": "5 包迁移:artplayer-plugin-chapter", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-chapter" + ], + "dependsOn": [ + "PKG-CHAPTER-05", + "ENG-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "chapter.js 示例、产物和变更记录", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-AMBILIGHT-01", + "phase": "5 包迁移:artplayer-plugin-ambilight", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "blur/opacity/frequency/duration、start/stop 与挂载样式", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-AMBILIGHT-02", + "phase": "5 包迁移:artplayer-plugin-ambilight", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "PKG-AMBILIGHT-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "跨域 canvas 失败、零尺寸、暂停、重复 start/stop 和 destroy", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-AMBILIGHT-03", + "phase": "5 包迁移:artplayer-plugin-ambilight", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "PKG-AMBILIGHT-02", + "CORE-03", + "CORE-12" + ], + "status": "todo", + "risk": "M", + "deliverable": "取色计算与绘帧分离,统一 RAF 和 DOM 清理", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-AMBILIGHT-04", + "phase": "5 包迁移:artplayer-plugin-ambilight", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "PKG-AMBILIGHT-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "canvas 上下文、参数及 start/stop 的明确类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-AMBILIGHT-05", + "phase": "5 包迁移:artplayer-plugin-ambilight", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "PKG-AMBILIGHT-04", + "CORE-22" + ], + "status": "todo", + "risk": "M", + "deliverable": "原生 video、canvas proxy 的能力边界及销毁无帧循环", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-AMBILIGHT-06", + "phase": "5 包迁移:artplayer-plugin-ambilight", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "PKG-AMBILIGHT-05", + "ENG-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "ambilight.js 示例及样式/分发验证", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-AUDIO-01", + "phase": "5 包迁移:artplayer-plugin-audio-track", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-audio-track" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "url/offset/sync、audio 实例暴露、update 与音量语义", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-AUDIO-02", + "phase": "5 包迁移:artplayer-plugin-audio-track", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-audio-track" + ], + "dependsOn": [ + "PKG-AUDIO-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "偏移、倍率、seek、waiting/playing、加载错误和 autoplay 拒绝", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-AUDIO-03", + "phase": "5 包迁移:artplayer-plugin-audio-track", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-audio-track" + ], + "dependsOn": [ + "PKG-AUDIO-02", + "CORE-10" + ], + "status": "todo", + "risk": "H", + "deliverable": "外部 audio 的同步策略、监听与源更新生命周期", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-AUDIO-04", + "phase": "5 包迁移:artplayer-plugin-audio-track", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-audio-track" + ], + "dependsOn": [ + "PKG-AUDIO-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "Option/Result/audio、update 输入和事件类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-AUDIO-05", + "phase": "5 包迁移:artplayer-plugin-audio-track", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-audio-track" + ], + "dependsOn": [ + "PKG-AUDIO-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "主视频切源和缓冲恢复,多实例独立音频、旧核心", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-AUDIO-06", + "phase": "5 包迁移:artplayer-plugin-audio-track", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-audio-track" + ], + "dependsOn": [ + "PKG-AUDIO-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "audio.track.js 示例与运行返回值一致的声明", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-AUTO-THUMB-01", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "url/width/number/scale、异步工厂和渐进缩略图更新", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-AUTO-THUMB-02", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "PKG-AUTO-THUMB-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "抽帧边界、短视频、失败、连续来源和销毁中的抽帧", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-AUTO-THUMB-03", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "PKG-AUTO-THUMB-02", + "CORE-09", + "CORE-19" + ], + "status": "todo", + "risk": "H", + "deliverable": "隐藏 video、seek 队列、canvas 编码与 Blob URL 清理", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-AUTO-THUMB-04", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "PKG-AUTO-THUMB-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "抽帧结果和真实异步插件返回类型兼容", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-AUTO-THUMB-05", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "PKG-AUTO-THUMB-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "旧核心/候选核心预览、多次加载无过期缩略图覆盖", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-AUTO-THUMB-06", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "PKG-AUTO-THUMB-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "auto.thumbnail.js、三种产物和内存/URL 证据", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-VTT-THUMB-01", + "phase": "5 包迁移:artplayer-plugin-vtt-thumbnail", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-vtt-thumbnail" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "vtt/style、异步返回、预览控件名与样式契约", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-VTT-THUMB-02", + "phase": "5 包迁移:artplayer-plugin-vtt-thumbnail", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-vtt-thumbnail" + ], + "dependsOn": [ + "PKG-VTT-THUMB-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "VTT 解析、xywh、相对 URL、时间边界、请求失败和定位", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-VTT-THUMB-03", + "phase": "5 包迁移:artplayer-plugin-vtt-thumbnail", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-vtt-thumbnail" + ], + "dependsOn": [ + "PKG-VTT-THUMB-02", + "CORE-09", + "CORE-19" + ], + "status": "todo", + "risk": "M", + "deliverable": "纯解析/区间查找与 DOM、请求/定时器生命周期分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-VTT-THUMB-04", + "phase": "5 包迁移:artplayer-plugin-vtt-thumbnail", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-vtt-thumbnail" + ], + "dependsOn": [ + "PKG-VTT-THUMB-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "cue/rect/result 和参数可选性保持兼容", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-VTT-THUMB-05", + "phase": "5 包迁移:artplayer-plugin-vtt-thumbnail", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-vtt-thumbnail" + ], + "dependsOn": [ + "PKG-VTT-THUMB-04", + "CORE-22" + ], + "status": "todo", + "risk": "M", + "deliverable": "鼠标和移动进度、全屏、切源、chapter 组合", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-VTT-THUMB-06", + "phase": "5 包迁移:artplayer-plugin-vtt-thumbnail", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-vtt-thumbnail" + ], + "dependsOn": [ + "PKG-VTT-THUMB-05", + "ENG-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "vtt.thumbnail.js、VTT/图片资源解析和产物验证", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-HLS-01", + "phase": "5 包迁移:artplayer-plugin-hls-control", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-hls-control" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "quality/audio 配置、getName、update、控件名及 Hls 实例绑定", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-HLS-02", + "phase": "5 包迁移:artplayer-plugin-hls-control", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-hls-control" + ], + "dependsOn": [ + "PKG-HLS-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "Auto/手动实际 level、音轨、去重/过滤和拓扑变化", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-HLS-03", + "phase": "5 包迁移:artplayer-plugin-hls-control", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-hls-control" + ], + "dependsOn": [ + "PKG-HLS-02", + "CORE-11", + "CORE-14" + ], + "status": "todo", + "risk": "H", + "deliverable": "映射计算与 selector 更新/删除、Hls 事件订阅分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-HLS-04", + "phase": "5 包迁移:artplayer-plugin-hls-control", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-hls-control" + ], + "dependsOn": [ + "PKG-HLS-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "HLS 能力适配类型、回调上下文和旧 getName 参数", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-HLS-05", + "phase": "5 包迁移:artplayer-plugin-hls-control", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-hls-control" + ], + "dependsOn": [ + "PKG-HLS-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "本地多码率 HLS、换成无轨道来源、旧核心和最终核心", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-HLS-06", + "phase": "5 包迁移:artplayer-plugin-hls-control", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-hls-control" + ], + "dependsOn": [ + "PKG-HLS-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "hls.control.js、依赖范围与回退记录", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-DASH-01", + "phase": "5 包迁移:artplayer-plugin-dash-control", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-dash-control" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "quality/audio、representation ID/Auto、getName 和 update", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-DASH-02", + "phase": "5 包迁移:artplayer-plugin-dash-control", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-dash-control" + ], + "dependsOn": [ + "PKG-DASH-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "保留已有 5 项回归,补音轨/空列表/过滤/换源", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-DASH-03", + "phase": "5 包迁移:artplayer-plugin-dash-control", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-dash-control" + ], + "dependsOn": [ + "PKG-DASH-02", + "CORE-11", + "CORE-14" + ], + "status": "todo", + "risk": "H", + "deliverable": "稳定 ID 映射、ABR 状态与 UI 清理职责分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-DASH-04", + "phase": "5 包迁移:artplayer-plugin-dash-control", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-dash-control" + ], + "dependsOn": [ + "PKG-DASH-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "dash.js adapter、selector 和回调类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-DASH-05", + "phase": "5 包迁移:artplayer-plugin-dash-control", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-dash-control" + ], + "dependsOn": [ + "PKG-DASH-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "本地 DASH 实际 representation、高亮、恢复 Auto 和换源", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-DASH-06", + "phase": "5 包迁移:artplayer-plugin-dash-control", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-dash-control" + ], + "dependsOn": [ + "PKG-DASH-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "dash.control.js、支持的 dash.js 版本与产物", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-MULTI-SUB-01", + "phase": "5 包迁移:artplayer-plugin-multiple-subtitles", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-multiple-subtitles" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "subtitles/onParser、multipleSubtitles 名称及实际返回方法", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-MULTI-SUB-02", + "phase": "5 包迁移:artplayer-plugin-multiple-subtitles", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-multiple-subtitles" + ], + "dependsOn": [ + "PKG-MULTI-SUB-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "VTT/SRT/ASS、编码/重叠 cue/排序/空轨/失败与切换", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-MULTI-SUB-03", + "phase": "5 包迁移:artplayer-plugin-multiple-subtitles", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-multiple-subtitles" + ], + "dependsOn": [ + "PKG-MULTI-SUB-02", + "CORE-15" + ], + "status": "todo", + "risk": "H", + "deliverable": "解析与合并/获取/渲染分离,过期请求及对象 URL 清理", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-MULTI-SUB-04", + "phase": "5 包迁移:artplayer-plugin-multiple-subtitles", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-multiple-subtitles" + ], + "dependsOn": [ + "PKG-MULTI-SUB-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "准确 parser/cue/tree/result 类型与真实异步形状", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-MULTI-SUB-05", + "phase": "5 包迁移:artplayer-plugin-multiple-subtitles", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-multiple-subtitles" + ], + "dependsOn": [ + "PKG-MULTI-SUB-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "与核心字幕/偏移/全屏组合,旧名称调用不变", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-MULTI-SUB-06", + "phase": "5 包迁移:artplayer-plugin-multiple-subtitles", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-multiple-subtitles" + ], + "dependsOn": [ + "PKG-MULTI-SUB-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "multiple.subtitles.js、parser 来源许可及打包边界", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-JASSUB-01", + "phase": "5 包迁移:artplayer-plugin-jassub", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-jassub" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "选项透传、result.instance、vendor 来源、worker/WASM/font 路径", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-JASSUB-02", + "phase": "5 包迁移:artplayer-plugin-jassub", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-jassub" + ], + "dependsOn": [ + "PKG-JASSUB-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "ASS 字体、时钟/seek/倍率/resize、加载失败和销毁", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-JASSUB-03", + "phase": "5 包迁移:artplayer-plugin-jassub", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-jassub" + ], + "dependsOn": [ + "PKG-JASSUB-02", + "CORE-15", + "CORE-16" + ], + "status": "todo", + "risk": "H", + "deliverable": "仅整理自有 adapter/销毁;保留第三方文件及来源", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-JASSUB-04", + "phase": "5 包迁移:artplayer-plugin-jassub", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-jassub" + ], + "dependsOn": [ + "PKG-JASSUB-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "JASSUB option/instance 的兼容类型包装,vendor JS 例外记录", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-JASSUB-05", + "phase": "5 包迁移:artplayer-plugin-jassub", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-jassub" + ], + "dependsOn": [ + "PKG-JASSUB-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "真实 worker/WASM 字幕渲染与全屏、旧核心测试", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-JASSUB-06", + "phase": "5 包迁移:artplayer-plugin-jassub", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-jassub" + ], + "dependsOn": [ + "PKG-JASSUB-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "jassub.js、外部资源路径、许可和离线失败记录", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-MASK-01", + "phase": "5 包迁移:artplayer-plugin-danmuku-mask", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-danmuku-mask" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "模型参数、start/stop、默认下载路径及 mask 样式", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-MASK-02", + "phase": "5 包迁移:artplayer-plugin-danmuku-mask", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-danmuku-mask" + ], + "dependsOn": [ + "PKG-MASK-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "加载期间停止/销毁、重复启动、推理失败、WebGL/CPU 边界", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-MASK-03", + "phase": "5 包迁移:artplayer-plugin-danmuku-mask", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-danmuku-mask" + ], + "dependsOn": [ + "PKG-MASK-02", + "CORE-18", + "PKG-DANMUKU-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "模型加载/推理/画布输出分离,阻止重叠推理与过期写入", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-MASK-04", + "phase": "5 包迁移:artplayer-plugin-danmuku-mask", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-danmuku-mask" + ], + "dependsOn": [ + "PKG-MASK-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "模型 adapter、canvas 和选项的精确类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-MASK-05", + "phase": "5 包迁移:artplayer-plugin-danmuku-mask", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-danmuku-mask" + ], + "dependsOn": [ + "PKG-MASK-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "真实模型和 danmuku/seek/全屏组合,GPU 资源释放", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-MASK-06", + "phase": "5 包迁移:artplayer-plugin-danmuku-mask", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-danmuku-mask" + ], + "dependsOn": [ + "PKG-MASK-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "danmuku.mask.js、资源版本/许可、CPU fallback 和包体积证据", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-ASR-01", + "phase": "5 包迁移:artplayer-plugin-asr", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-asr" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "length/interval/sampleRate/onAudioChunk、append/hide/stop 的真实能力", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-ASR-02", + "phase": "5 包迁移:artplayer-plugin-asr", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-asr" + ], + "dependsOn": [ + "PKG-ASR-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "PCM/WAV、chunk 时序、回调慢/拒绝、重复初始化与停止", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-ASR-03", + "phase": "5 包迁移:artplayer-plugin-asr", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-asr" + ], + "dependsOn": [ + "PKG-ASR-02", + "CORE-10", + "CORE-18" + ], + "status": "todo", + "risk": "H", + "deliverable": "AudioContext/Worklet/Stream 生命周期和背压分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-ASR-04", + "phase": "5 包迁移:artplayer-plugin-asr", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-asr" + ], + "dependsOn": [ + "PKG-ASR-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "主线程/Worklet/音频 buffer 与异步回调类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-ASR-05", + "phase": "5 包迁移:artplayer-plugin-asr", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-asr" + ], + "dependsOn": [ + "PKG-ASR-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "真实 WebAudio 分块、播放暂停/切源/销毁,不引入网络 ASR", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-ASR-06", + "phase": "5 包迁移:artplayer-plugin-asr", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-asr" + ], + "dependsOn": [ + "PKG-ASR-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "asr.js、Worklet 资源、输出格式与声明证据", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-ADS-01", + "phase": "5 包迁移:artplayer-plugin-ads", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-ads" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "核对 html/video/url 与 source/type 声明差异,结果方法和倒计时", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-ADS-02", + "phase": "5 包迁移:artplayer-plugin-ads", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-ads" + ], + "dependsOn": [ + "PKG-ADS-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "视频/HTML/图片实际支持路径、跳过阈值、暂停恢复、加载失败", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-ADS-03", + "phase": "5 包迁移:artplayer-plugin-ads", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-ads" + ], + "dependsOn": [ + "PKG-ADS-02", + "CORE-10", + "CORE-13" + ], + "status": "todo", + "risk": "H", + "deliverable": "广告状态/计时/视图/主视频恢复分离,不改变广告产品规则", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-ADS-04", + "phase": "5 包迁移:artplayer-plugin-ads", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-ads" + ], + "dependsOn": [ + "PKG-ADS-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "旧参数契约和真实返回方法的兼容类型;错误声明单独处理", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-ADS-05", + "phase": "5 包迁移:artplayer-plugin-ads", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-ads" + ], + "dependsOn": [ + "PKG-ADS-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "本地广告 fixture、多实例、正常结束/跳过/销毁恢复内容", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-ADS-06", + "phase": "5 包迁移:artplayer-plugin-ads", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-ads" + ], + "dependsOn": [ + "PKG-ADS-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "ads.js、README/类型一致性、旧参数保留与变更日志", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-VAST-01", + "phase": "5 包迁移:artplayer-plugin-vast", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-vast" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "异步工厂、callback context、playUrl/playRes/init 与 SDK 版本", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-VAST-02", + "phase": "5 包迁移:artplayer-plugin-vast", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-vast" + ], + "dependsOn": [ + "PKG-VAST-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-VAST-03", + "phase": "5 包迁移:artplayer-plugin-vast", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-vast" + ], + "dependsOn": [ + "PKG-VAST-02", + "CORE-10", + "CORE-13" + ], + "status": "todo", + "risk": "H", + "deliverable": "SDK loader、IMA adapter、广告状态和 DOM 清理分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-VAST-04", + "phase": "5 包迁移:artplayer-plugin-vast", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-vast" + ], + "dependsOn": [ + "PKG-VAST-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-VAST-05", + "phase": "5 包迁移:artplayer-plugin-vast", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-vast" + ], + "dependsOn": [ + "PKG-VAST-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "官方测试广告或受控 SDK 环境,错误后主视频状态恢复", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-VAST-06", + "phase": "5 包迁移:artplayer-plugin-vast", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-vast" + ], + "dependsOn": [ + "PKG-VAST-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "vast.js、SDK 资源、声明消费和独立版本记录", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-CAST-01", + "phase": "5 包迁移:artplayer-plugin-chromecast", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-chromecast" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "url/sdk/icon/mimeType、loader、会话、全局 SDK 与结果", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-CAST-02", + "phase": "5 包迁移:artplayer-plugin-chromecast", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-chromecast" + ], + "dependsOn": [ + "PKG-CAST-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "SDK 脚本加载失败/重入、无设备/拒绝、重复实例与销毁", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-CAST-03", + "phase": "5 包迁移:artplayer-plugin-chromecast", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-chromecast" + ], + "dependsOn": [ + "PKG-CAST-02", + "CORE-11", + "CORE-13" + ], + "status": "todo", + "risk": "H", + "deliverable": "SDK singleton/实例订阅/会话与控件职责分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-CAST-04", + "phase": "5 包迁移:artplayer-plugin-chromecast", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-chromecast" + ], + "dependsOn": [ + "PKG-CAST-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "Cast 能力 adapter、全局对象和元数据类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-CAST-05", + "phase": "5 包迁移:artplayer-plugin-chromecast", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-chromecast" + ], + "dependsOn": [ + "PKG-CAST-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "stub 测试之外记录实际 Cast 设备会话、源更新和断开", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-CAST-06", + "phase": "5 包迁移:artplayer-plugin-chromecast", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-chromecast" + ], + "dependsOn": [ + "PKG-CAST-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "chromecast.js、SDK URL/权限能力及待支持环境说明", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-DPIP-01", + "phase": "5 包迁移:artplayer-plugin-document-pip", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-plugin-document-pip" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "width/height/placeholder/fallbackToVideoPiP、open/close/toggle 返回", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-DPIP-02", + "phase": "5 包迁移:artplayer-plugin-document-pip", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-plugin-document-pip" + ], + "dependsOn": [ + "PKG-DPIP-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "不支持/拒绝、重复打开、pagehide、核心销毁和视频 PiP fallback", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-DPIP-03", + "phase": "5 包迁移:artplayer-plugin-document-pip", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-plugin-document-pip" + ], + "dependsOn": [ + "PKG-DPIP-02", + "CORE-16", + "CORE-17" + ], + "status": "todo", + "risk": "H", + "deliverable": "窗口生命周期、DOM 迁移、样式与事件 document 重绑分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-DPIP-04", + "phase": "5 包迁移:artplayer-plugin-document-pip", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-plugin-document-pip" + ], + "dependsOn": [ + "PKG-DPIP-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "Document PiP 可选能力和真实状态/返回类型", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-DPIP-05", + "phase": "5 包迁移:artplayer-plugin-document-pip", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-plugin-document-pip" + ], + "dependsOn": [ + "PKG-DPIP-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "原生视频及两个 proxy、键盘/焦点/全屏与关闭还原", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-DPIP-06", + "phase": "5 包迁移:artplayer-plugin-document-pip", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-plugin-document-pip" + ], + "dependsOn": [ + "PKG-DPIP-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "document.pip.js、浏览器能力矩阵、旧接口与恢复证据", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-01", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "核对弹幕全部公开契约", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "emit/load/config/hide/show/reset/mount、option/isHide/isStop/icons 与事件清单", + "acceptance": "源码、声明、发布包、Bilibili 输入和设置入口对照", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-02", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "建立弹幕算法与浏览器基线", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-01", + "ENG-05", + "ENG-08" + ], + "status": "todo", + "risk": "H", + "deliverable": "密集/稀疏弹幕、过滤/异步输入、seek/倍率/重载测试", + "acceptance": "轨道选择、发射顺序、事件、内存和可视结果可重跑", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-03", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "整理加载、解析与配置", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-02", + "CORE-08" + ], + "status": "todo", + "risk": "M", + "deliverable": "bilibili/input/parser/config 的分层与取消", + "acceptance": "旧格式、回调、过滤、追加/替换语义保持", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-04", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "整理时钟、队列与轨道调度", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-03", + "CORE-10" + ], + "status": "todo", + "risk": "H", + "deliverable": "danmuku 调度器和确定性时钟测试", + "acceptance": "seek/暂停/倍率/长时间运行无顺序和碰撞回归", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-05", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "整理 DOM 渲染、设置、热力图与 worker", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-04", + "CORE-14", + "CORE-18" + ], + "status": "todo", + "risk": "H", + "deliverable": "renderer/setting/heatmap/worker 职责及资源归属", + "acceptance": "mount/icons/设置和 worker 协议保持,销毁无后台工作", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-06", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "迁移 TS 与公开声明", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-05", + "ENG-04", + "ENG-06" + ], + "status": "todo", + "risk": "H", + "deliverable": "自有模块、worker 消息、option/item/result 类型", + "acceptance": "旧参数、扩展字段和事件消费通过,vendored 边界清楚", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-07", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "弹幕能力稳定性验收", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-06" + ], + "status": "todo", + "risk": "H", + "deliverable": "负载/渲染/资源对比及 mask 可依赖的稳定边界", + "acceptance": "在试点核心中旧插件 API 与关键帧路径通过", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-08", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "完成新旧核心与组合验收", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-07", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "最终核心/旧核心、mask/fullscreen/PiP 组合报告", + "acceptance": "性能无未解释退化,反复装卸无累计资源", + "evidence": [] + }, + { + "id": "PKG-DANMUKU-09", + "phase": "5 包迁移:artplayer-plugin-danmuku", + "title": "完成分发、示例与文档", + "scope": [ + "artplayer-plugin-danmuku" + ], + "dependsOn": [ + "PKG-DANMUKU-08", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "danmuku.js、README、声明、worker 与产物", + "acceptance": "tarball 和静态 icons 等旧调用通过,有独立回退版本", + "evidence": [] + }, + { + "id": "PKG-CANVAS-01", + "phase": "5 包迁移:artplayer-proxy-canvas", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-proxy-canvas" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "callback、canvas 原方法、转发 media 属性/方法/事件", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-CANVAS-02", + "phase": "5 包迁移:artplayer-proxy-canvas", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-proxy-canvas" + ], + "dependsOn": [ + "PKG-CANVAS-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "ready/loadeddata/canplay、play/seek、回调、resize 与销毁", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-CANVAS-03", + "phase": "5 包迁移:artplayer-proxy-canvas", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-proxy-canvas" + ], + "dependsOn": [ + "PKG-CANVAS-02", + "CORE-06", + "CORE-11", + "CORE-16" + ], + "status": "todo", + "risk": "H", + "deliverable": "video adapter/原 canvas 方法/RAF 绘制/事件订阅分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-CANVAS-04", + "phase": "5 包迁移:artplayer-proxy-canvas", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-proxy-canvas" + ], + "dependsOn": [ + "PKG-CANVAS-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "canvas 与媒体能力的精确组合类型,保持 Result", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-CANVAS-05", + "phase": "5 包迁移:artplayer-proxy-canvas", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-proxy-canvas" + ], + "dependsOn": [ + "PKG-CANVAS-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "真实 video/canvas 绘制、字幕和 document PiP 恢复", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-CANVAS-06", + "phase": "5 包迁移:artplayer-proxy-canvas", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-proxy-canvas" + ], + "dependsOn": [ + "PKG-CANVAS-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "canvas.js、三种产物、调用兼容与资源证据", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-MB-01", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "核对 shim 与媒体契约", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "全部 option、art.mediabunny、canvas/shim 属性及事件表", + "acceptance": "公开暴露成员和实际发布依赖/资源范围明确", + "evidence": [] + }, + { + "id": "PKG-MB-02", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "建立真实媒体与事件基线", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-01", + "ENG-05", + "ENG-08" + ], + "status": "todo", + "risk": "H", + "deliverable": "MP4/WebM/HLS/Blob/Stream、seek/错误/轨道切换样本", + "acceptance": "ready 事件顺序、音画同步、超时和释放可重跑", + "evidence": [] + }, + { + "id": "PKG-MB-03", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "整理 input 与加载取消", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-02", + "CORE-09" + ], + "status": "todo", + "risk": "H", + "deliverable": "input.js 源检测、输入资源、Range 与取消", + "acceptance": "HLS 检测在 input 边界,旧来源类型和超时保持", + "evidence": [] + }, + { + "id": "PKG-MB-04", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "整理 VideoShim/EventTarget/Engine 协调", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-03", + "CORE-06", + "CORE-11" + ], + "status": "todo", + "risk": "H", + "deliverable": "shim 描述符、事件桥、加载状态和操作隔离", + "acceptance": "公开属性/同步异步返回与事件重入顺序保持", + "evidence": [] + }, + { + "id": "PKG-MB-05", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "整理视频解码、seek 和帧释放", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-04" + ], + "status": "todo", + "risk": "H", + "deliverable": "VideoEngine 调度、队列、晚帧处理和资源释放", + "acceptance": "暂停/seek/切源无旧帧覆盖,默认丢帧策略不变", + "evidence": [] + }, + { + "id": "PKG-MB-06", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "整理音频解码、时钟与同步", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-04" + ], + "status": "todo", + "risk": "H", + "deliverable": "AudioEngine 时钟、缓冲和 AudioContext 归属", + "acceptance": "AV sync、倍速、无音轨、静音/音量和暂停恢复通过", + "evidence": [] + }, + { + "id": "PKG-MB-07", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "整理 HLS 配对轨道与 selector", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-05", + "PKG-MB-06", + "CORE-14" + ], + "status": "todo", + "risk": "H", + "deliverable": "m3u8 配对、质量/音频选择及拓扑清理", + "acceptance": "实际选择高亮、切到无轨道来源清理、无重复 readiness", + "evidence": [] + }, + { + "id": "PKG-MB-08", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "完成 TS 与媒体能力声明", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-07", + "ENG-04", + "ENG-06" + ], + "status": "todo", + "risk": "H", + "deliverable": "8 个自有 JS 模块迁移与 Result/shim 类型", + "acceptance": "解码器/Stream/DOM 类型清楚,旧 Option 和 art.mediabunny 使用保持", + "evidence": [] + }, + { + "id": "PKG-MB-09", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "完成新旧核心和真实媒体组合", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-08", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "跨浏览器能力、长播放、DPiP、HLS 音轨/质量报告", + "acceptance": "资源释放、事件顺序、AV sync 与支持范围满足基线", + "evidence": [] + }, + { + "id": "PKG-MB-10", + "phase": "5 包迁移:artplayer-proxy-mediabunny", + "title": "完成分发和文档", + "scope": [ + "artplayer-proxy-mediabunny" + ], + "dependsOn": [ + "PKG-MB-09", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "mediabunny.js、README、依赖版本、三产物和许可", + "acceptance": "tarball 可消费、无意外依赖升级、旧调用与回退可用", + "evidence": [] + }, + { + "id": "PKG-IFRAME-01", + "phase": "5 包迁移:artplayer-tool-iframe", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-tool-iframe" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "constructor/commit/message/inject、postMessage 协议与历史公开拼写", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-IFRAME-02", + "phase": "5 包迁移:artplayer-tool-iframe", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-tool-iframe" + ], + "dependsOn": [ + "PKG-IFRAME-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "跨窗口消息、ID 匹配、请求失败、重复 inject、销毁中请求", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-IFRAME-03", + "phase": "5 包迁移:artplayer-tool-iframe", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-tool-iframe" + ], + "dependsOn": [ + "PKG-IFRAME-02", + "CORE-02", + "BASE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-IFRAME-04", + "phase": "5 包迁移:artplayer-tool-iframe", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-tool-iframe" + ], + "dependsOn": [ + "PKG-IFRAME-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "消息联合类型、回调/Promise 推导、旧公开字段兼容", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-IFRAME-05", + "phase": "5 包迁移:artplayer-tool-iframe", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-tool-iframe" + ], + "dependsOn": [ + "PKG-IFRAME-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-IFRAME-06", + "phase": "5 包迁移:artplayer-tool-iframe", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-tool-iframe" + ], + "dependsOn": [ + "PKG-IFRAME-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "iframe.js、示例集成和原 script/class 导出验证", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "PKG-TOOL-THUMB-01", + "phase": "5 包迁移:artplayer-tool-thumbnail", + "title": "核对包契约与历史用法", + "scope": [ + "artplayer-tool-thumbnail" + ], + "dependsOn": [ + "BASE-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "构造/defaults/事件/方法/历史拼写、.esm.js 入口和缺失 types", + "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", + "evidence": [] + }, + { + "id": "PKG-TOOL-THUMB-02", + "phase": "5 包迁移:artplayer-tool-thumbnail", + "title": "建立特有行为与错误测试", + "scope": [ + "artplayer-tool-thumbnail" + ], + "dependsOn": [ + "PKG-TOOL-THUMB-01", + "ENG-03", + "ENG-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "文件输入/拖放、抽帧网格、begin/end、进度/失败/重复任务", + "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", + "evidence": [] + }, + { + "id": "PKG-TOOL-THUMB-03", + "phase": "5 包迁移:artplayer-tool-thumbnail", + "title": "整理内部职责与资源", + "scope": [ + "artplayer-tool-thumbnail" + ], + "dependsOn": [ + "PKG-TOOL-THUMB-02", + "CORE-01" + ], + "status": "todo", + "risk": "H", + "deliverable": "输入、抽帧队列、网格导出、URL/监听清理分离", + "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", + "evidence": [] + }, + { + "id": "PKG-TOOL-THUMB-04", + "phase": "5 包迁移:artplayer-tool-thumbnail", + "title": "迁移自有源码和公开类型", + "scope": [ + "artplayer-tool-thumbnail" + ], + "dependsOn": [ + "PKG-TOOL-THUMB-03", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "补齐真实 API 声明,自有 emitter/utils TS 化", + "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", + "evidence": [] + }, + { + "id": "PKG-TOOL-THUMB-05", + "phase": "5 包迁移:artplayer-tool-thumbnail", + "title": "验证新旧核心和组合", + "scope": [ + "artplayer-tool-thumbnail" + ], + "dependsOn": [ + "PKG-TOOL-THUMB-04", + "CORE-22" + ], + "status": "todo", + "risk": "H", + "deliverable": "工具独立浏览器使用,生成缩略图在核心中显示", + "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", + "evidence": [] + }, + { + "id": "PKG-TOOL-THUMB-06", + "phase": "5 包迁移:artplayer-tool-thumbnail", + "title": "验证分发并同步文档", + "scope": [ + "artplayer-tool-thumbnail" + ], + "dependsOn": [ + "PKG-TOOL-THUMB-05", + "ENG-07" + ], + "status": "todo", + "risk": "H", + "deliverable": "tool.thumbnail.js、历史 ESM 兼容文件、types 路径和 tarball", + "acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录", + "evidence": [] + }, + { + "id": "SITE-01", + "phase": "6 文档与消费者", + "title": "清点文档/示例/生成链", + "scope": [ + "artplayer-vitepress" + ], + "dependsOn": [ + "BASE-04", + "BASE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "中英文文档、插件页面、demo URL、编辑器声明与生成目录清单", + "acceptance": "所有公开 API/插件有对应页面或明确补充任务", + "evidence": [] + }, + { + "id": "SITE-02", + "phase": "6 文档与消费者", + "title": "整理声明与示例生成器", + "scope": [ + "artplayer-vitepress" + ], + "dependsOn": [ + "SITE-01", + "ENG-04", + "ENG-06" + ], + "status": "todo", + "risk": "M", + "deliverable": "build-ts/build-test 生成链的可验证 TS 脚本", + "acceptance": "不靠字符串拼接掩盖声明错误,生成示例有真实断言或仅标 smoke", + "evidence": [] + }, + { + "id": "SITE-03", + "phase": "6 文档与消费者", + "title": "整理 i18n/文档/LLM 生成流程", + "scope": [ + "artplayer-vitepress" + ], + "dependsOn": [ + "SITE-02" + ], + "status": "todo", + "risk": "M", + "deliverable": "build-i18n/build-docs/build-llm/trans-docs 的任务边界和错误处理", + "acceptance": "原命令兼容、生成可复现,翻译步骤不隐式运行远程服务", + "evidence": [] + }, + { + "id": "SITE-04", + "phase": "6 文档与消费者", + "title": "同步核心和全部插件使用文档", + "scope": [ + "artplayer-vitepress" + ], + "dependsOn": [ + "CORE-22", + "PKG-CHAPTER-06", + "PKG-AMBILIGHT-06", + "PKG-AUDIO-06", + "PKG-AUTO-THUMB-06", + "PKG-VTT-THUMB-06", + "PKG-HLS-06", + "PKG-DASH-06", + "PKG-MULTI-SUB-06", + "PKG-JASSUB-06", + "PKG-MASK-06", + "PKG-ASR-06", + "PKG-ADS-06", + "PKG-VAST-06", + "PKG-CAST-06", + "PKG-DPIP-06", + "PKG-DANMUKU-09", + "PKG-CANVAS-06", + "PKG-MB-10", + "PKG-IFRAME-06", + "PKG-TOOL-THUMB-06", + "SITE-03" + ], + "status": "todo", + "risk": "M", + "deliverable": "中文/英文 API、插件选项、兼容说明及旧 JS 用法", + "acceptance": "不要求旧调用迁移,未支持能力不写成已支持", + "evidence": [] + }, + { + "id": "SITE-05", + "phase": "6 文档与消费者", + "title": "构建文档站和验证链接/示例", + "scope": [ + "artplayer-vitepress" + ], + "dependsOn": [ + "SITE-04", + "EX-03" + ], + "status": "todo", + "risk": "M", + "deliverable": "VitePress 构建、链接与嵌入 demo 检查", + "acceptance": "产物可访问,全部包文档与 types 注入无丢失", + "evidence": [] + }, + { + "id": "SITE-06", + "phase": "6 文档与消费者", + "title": "文档站交付验收", + "scope": [ + "artplayer-vitepress" + ], + "dependsOn": [ + "SITE-05" + ], + "status": "todo", + "risk": "M", + "deliverable": "维护指南和站点变更记录", + "acceptance": "未手改 generated 目录,旧 URL 可用、部署与检查分离", + "evidence": [] + }, + { + "id": "EX-01", + "phase": "6 文档与消费者", + "title": "验证 React 消费者与 TS", + "scope": [ + "example/react.js" + ], + "dependsOn": [ + "CORE-22", + "ENG-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "React 挂载/卸载/重挂载、引用和插件样例", + "acceptance": "真实 tarball + TS 消费通过,保留既有 React 集成 API", + "evidence": [] + }, + { + "id": "EX-02", + "phase": "6 文档与消费者", + "title": "验证 Vue 消费者与更新卸载", + "scope": [ + "example/vue.js" + ], + "dependsOn": [ + "CORE-22", + "ENG-07" + ], + "status": "todo", + "risk": "M", + "deliverable": "Vue 实例/ref、参数更新、卸载及插件样例", + "acceptance": "旧 JS 组件用法无需修改,重复挂载不泄漏", + "evidence": [] + }, + { + "id": "EX-03", + "phase": "6 文档与消费者", + "title": "验证全部原生 demo 与外部播放集成", + "scope": [ + "workspace" + ], + "dependsOn": [ + "EX-01", + "EX-02", + "PKG-CHAPTER-06", + "PKG-AMBILIGHT-06", + "PKG-AUDIO-06", + "PKG-AUTO-THUMB-06", + "PKG-VTT-THUMB-06", + "PKG-HLS-06", + "PKG-DASH-06", + "PKG-MULTI-SUB-06", + "PKG-JASSUB-06", + "PKG-MASK-06", + "PKG-ASR-06", + "PKG-ADS-06", + "PKG-VAST-06", + "PKG-CAST-06", + "PKG-DPIP-06", + "PKG-DANMUKU-09", + "PKG-CANVAS-06", + "PKG-MB-10", + "PKG-IFRAME-06", + "PKG-TOOL-THUMB-06" + ], + "status": "todo", + "risk": "H", + "deliverable": "8082 全 demo、HLS/DASH/FLV/MPEGTS/WebTorrent 集成记录", + "acceptance": "旧 URL/参数/脚本加载保持;网络/SDK 限制明确,不静默跳过", + "evidence": [] + }, + { + "id": "MOD-01", + "phase": "7 工具链与性能", + "title": "Bun 固定版本干净安装试点", + "scope": [ + "workspace" + ], + "dependsOn": [ + "ENG-09" + ], + "status": "todo", + "risk": "H", + "deliverable": "独立目录的 Bun 锁文件、lifecycle/peer/workspace 与全部构建对比", + "acceptance": "Node 测试仍通过;安装与资源一致才决定采用;不改 bundler", + "evidence": [] + }, + { + "id": "MOD-02", + "phase": "7 工具链与性能", + "title": "整理剩余开发/构建脚本与插件模板", + "scope": [ + "workspace" + ], + "dependsOn": [ + "MOD-01", + "SITE-03" + ], + "status": "todo", + "risk": "M", + "deliverable": "dev/build/utils/create-plugin 的 TS 与可测 CLI,模板同时提供旧 API", + "acceptance": "旧脚本入口保留、新插件类型/测试/示例齐全,Lerna 改动单独取证", + "evidence": [] + }, + { + "id": "MOD-03", + "phase": "7 工具链与性能", + "title": "测量并优化核心热路径", + "scope": [ + "workspace" + ], + "dependsOn": [ + "CORE-22", + "ENG-08" + ], + "status": "todo", + "risk": "M", + "deliverable": "DOM 读写、进度更新、持久化、初始化的测量与改进", + "acceptance": "相同设备媒体多次比较,契约不变,收益及无效尝试记录", + "evidence": [] + }, + { + "id": "MOD-04", + "phase": "7 工具链与性能", + "title": "测量并优化重型插件/proxy", + "scope": [ + "workspace" + ], + "dependsOn": [ + "PKG-DANMUKU-09", + "PKG-MASK-06", + "PKG-MB-10", + "ENG-08" + ], + "status": "todo", + "risk": "M", + "deliverable": "帧/队列/推理/音画同步与资源长期运行比较", + "acceptance": "不改默认算法/阈值,性能改善有证据;无收益则保留旧实现", + "evidence": [] + }, + { + "id": "MOD-05", + "phase": "7 工具链与性能", + "title": "完成工具链与性能采用决策", + "scope": [ + "workspace" + ], + "dependsOn": [ + "MOD-02", + "MOD-03", + "MOD-04" + ], + "status": "todo", + "risk": "M", + "deliverable": "最终 runtime/packageManager/构建配置及性能台账", + "acceptance": "干净安装和全包检查通过;Bun 未采用有理由,不为状态强行切换", + "evidence": [] + }, + { + "id": "REL-01", + "phase": "8 发布验收", + "title": "确定分包版本与差异处置", + "scope": [ + "workspace" + ], + "dependsOn": [ + "SITE-06", + "EX-03", + "MOD-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "每包变更日志/版本/依赖/类型差异及支持范围", + "acceptance": "所有公共差异已解释或解决;未决破坏性变化阻止兼容发布", + "evidence": [] + }, + { + "id": "REL-02", + "phase": "8 发布验收", + "title": "生成候选 tarball 并验证新旧组合", + "scope": [ + "workspace" + ], + "dependsOn": [ + "REL-01" + ], + "status": "todo", + "risk": "H", + "deliverable": "全部候选包与原支持范围消费者安装矩阵", + "acceptance": "新核心旧插件、旧核心新插件、新新组合和历史路径通过", + "evidence": [] + }, + { + "id": "REL-03", + "phase": "8 发布验收", + "title": "完成真机、外部 SDK 与压力验收", + "scope": [ + "workspace" + ], + "dependsOn": [ + "REL-02" + ], + "status": "todo", + "risk": "H", + "deliverable": "Safari/移动/PiP/Cast/IMA/模型/长播放完整报告", + "acceptance": "无环境验证的关键能力保持阻塞,mock 不能替代设备结论", + "evidence": [] + }, + { + "id": "REL-04", + "phase": "8 发布验收", + "title": "演练回退与主线修复同步", + "scope": [ + "workspace" + ], + "dependsOn": [ + "REL-03" + ], + "status": "todo", + "risk": "H", + "deliverable": "分包旧版本/tag/依赖回退方案与 master 差异", + "acceptance": "独立回退可行,紧急修复能同步,无需所有用户联动升级", + "evidence": [] + }, + { + "id": "REL-05", + "phase": "8 发布验收", + "title": "经授权发布候选并收集反馈", + "scope": [ + "workspace" + ], + "dependsOn": [ + "REL-04" + ], + "status": "todo", + "risk": "H", + "deliverable": "候选 tag、完整产物 integrity、反馈与复现记录", + "acceptance": "实际发布授权/操作/版本可追溯;本计划不自动执行发布", + "evidence": [] + }, + { + "id": "REL-06", + "phase": "8 发布验收", + "title": "经授权分批正式发布", + "scope": [ + "workspace" + ], + "dependsOn": [ + "REL-05" + ], + "status": "todo", + "risk": "H", + "deliverable": "正式分包版本/tag/站点文档及兼容公告", + "acceptance": "候选验收通过,安装/浏览器复核和回退入口就绪", + "evidence": [] + }, + { + "id": "REL-07", + "phase": "8 发布验收", + "title": "关闭重构里程碑并维护后续队列", + "scope": [ + "workspace" + ], + "dependsOn": [ + "REL-06" + ], + "status": "todo", + "risk": "L", + "deliverable": "最终任务/设计/证据归档和维护指南", + "acceptance": "全范围任务有结论、无未解释兼容缺口;遗留项有明确后续责任", + "evidence": [] + } + ] +} diff --git a/refactor/testing.md b/refactor/testing.md new file mode 100644 index 000000000..8823748d6 --- /dev/null +++ b/refactor/testing.md @@ -0,0 +1,66 @@ +# 测试与验收 + +## 测试层次 + +| 层 | 内容 | 运行位置 | +| --- | --- | --- | +| 单元 | Emitter、配置、转换、索引、排序、选择状态、消息解析、时钟算法 | 保留 node:test;新工具需单独决策 | +| 生命周期 | 初始化失败、重复销毁、切源并发、过期响应、资源清理和 Promise 结算 | 可控时钟/媒体 adapter;关键流程再到真实浏览器 | +| 浏览器集成 | 完整播放器、插件 DOM、真实媒体、seek、字幕、鼠标/键盘/触控 | Playwright Chromium/Firefox/WebKit | +| 产物 | 由正常脚本构建的 tarball,UMD/AMD/global/require/ESM/legacy/i18n | 隔离消费者项目,不能靠 workspace 源码链接通过 | +| 类型 | 正向样例、错误断言、类型推断、插件扩展、JS 用户、声明入口 | 明确版本的 tsc,bundler 和 Node 模块解析分别检查 | +| 设备/供应商 | Safari 真机、PiP、Chromecast、IMA、模型和实际 codec | 有能力的设备/外部环境,记录真实版本和限制 | +| 性能/资源 | 初始化、交互、帧调度、反复装卸、CPU/内存/事件资源 | 固定设备、媒体和测量流程,多次运行 | + +## 基线与差分 + +1. 基线产物来自 BASE-01 固定的发布版本,保存 tarball integrity、源码 SHA、工具版本和样本信息。 +2. 同一测试对旧产物和候选产物运行,比较公开结果、事件 trace、属性描述符和 DOM 状态。 +3. 不使用整个 minified bundle 的文本相等作为 API 兼容证据。 +4. 已确认缺陷使用单独用例记录“旧版本复现,候选修复”;差分例外必须有变更记录,不能一键更新全部快照掩盖回归。 +5. 接口、类型与行为三项分别验收。只有类型检查通过不能证明运行时正确。 + +## 核心测试清单 + +- [ ] 正常初始化、useSSR、配置错误、无容器、重复容器、初始化中途失败。 +- [ ] play/pause/toggle、自动播放拒绝、内部播放触发不产生未处理拒绝。 +- [ ] currentTime/seek、switchUrl/switchQuality、同 URL、连续切换、切换中销毁、错误重试。 +- [ ] ready/restart/destroy 次数和状态,video 原生事件转发参数及顺序。 +- [ ] 一个实例销毁两次、多个实例互斥、销毁监听器重入/抛异常、removeHtml=false。 +- [ ] 控件/设置 add/update/remove、selector 高亮、重复名称、mounted/beforeUnmount。 +- [ ] 字幕载入、失败、切换顺序、cue 数组、偏移、URL 回收。 +- [ ] fullscreen/fullscreenWeb/PiP/mini 进入退出和异常,移动端方向、手势和安全区域。 +- [ ] 热键、焦点、document 重绑、全局监听器及组件清理。 +- [ ] i18n、图标、主题、样式注入及用户 CSS 覆盖。 +- [ ] 每个内置插件:autoPlayback、autoOrientation、fastForward、lock、miniProgressBar。 + +此清单是验收目录;具体任务状态仍只记入 tasks.json。 + +## 媒体样本 + +优先复用仓库中许可明确的本地 MP4/WebM/VTT/SRT/ASS;补充短 HLS/DASH、音轨/清晰度变化、无音轨、空字幕、损坏内容、慢响应和中断样本。媒体服务支持 Range 与受控错误。不要让公共直播 URL 的可用性决定 PR 是否通过。 + +浏览器不能解码特定样本时,要区分浏览器/codec 能力和播放器回归。需要实际支持的路径不能静默 skip;可选能力的 skip 必须有原因,设备验收在发布清单中保持待完成。 + +## CI 分层 + +| 触发 | 内容 | +| --- | --- | +| 每次 PR | 固定安装、只读 lint、类型、受影响单元/生命周期、核心浏览器 smoke、受影响发布包检查 | +| 核心或共享构建改变 | 全部 22 包构建/类型检查,旧插件对候选核心的回归,扩展浏览器矩阵 | +| 定期或候选发布 | 完整浏览器组合、压力/资源、性能、外部 SDK 与真机清单 | +| 发布前 | 干净环境完整 CI、tarball 消费、新旧组合、文档站、回退演练 | + +快速检查必须存在依赖映射;无法确定受影响范围时运行完整核心及生态检查,不仅按文件名选择测试。 + +## 证据要求 + +每次记录命令、HEAD、运行时与浏览器版本、样本、通过/失败/跳过数、报告路径和限制。报告持久化到可追溯的 CI artifact 或仓库中适量文本摘要,不只给开发机器临时路径。不提交大型录像/媒体/trace 到源码仓库。 + +必要门槛:没有新增未解释的失败,没有已知合法旧调用失效,关键资源在销毁后停止增长,发布路径存在且可加载。覆盖率报告先建立真实基线,再在 ENG 阶段按模块制定分支覆盖门槛;禁止用无意义测试堆数字。 + +性能门槛在 BASE-06 固定设备和统计方式后登记。若候选包 gzip 大小增长超过基线 5%,或主要测量中位数退化超过 10%,作为初始审查阈值触发调查,不能以一次波动判定回归,也不能以无测量声称优化。 + +## 本计划不代表已有测试 + +以上新增命令、测试目录和矩阵都是待实现内容。现有测试事实及评估范围见 [progress.md](progress.md)。 diff --git a/refactor/toolchain-release.md b/refactor/toolchain-release.md new file mode 100644 index 000000000..65cde9f98 --- /dev/null +++ b/refactor/toolchain-release.md @@ -0,0 +1,56 @@ +# 工具链、分发与发布 + +## 目标组合 + +TypeScript 用于自有源码、检查与声明生成;Vite/Rollup 保留现有产物能力;Node 继续运行现有测试和必要脚本;Bun 先作为包管理器及脚本入口试点。浏览器消费者不依赖 Bun。 + +这是项目方向,不是已完成的切换。工具版本必须在 ENG-01 / MOD-01 通过干净环境试点后固定,不能沿用开发机器上偶然存在的传递依赖。 + +## TypeScript + +1. 根目录管理基础配置,核心、插件、工具、构建脚本、worker/Worklet 各自配置环境。 +2. typescript 和必要测试工具显式声明为开发依赖。区分本仓库根工具依赖与每个发布包运行依赖。 +3. allowJs 过渡,逐包 strict;声明输出保持既有路径,禁止发布内部测试类型。 +4. 类型消费者矩阵包含旧支持的最低 TS 版本与选定当前版本,解析方式包含 bundler 和 Node;不能默认借重构抬高最低 TS 版本。 +5. docs/assets/ts 的编辑器声明由可验证的生成流程产出;不再依赖简单删除 import/拼字符串保证正确性。 +6. 保留直接消费 JS 的例子;TS 是维护手段,不成为用户必须使用的语言。 + +## Bun 试点 + +| 步骤 | 检查 | +| --- | --- | +| 依赖基线 | 保存当前依赖和工作区行为,明确唯一锁文件与版本 pin;初次固定锁不夹带大规模升级 | +| 安装对比 | 在独立干净目录执行 Bun 安装,检查 lifecycle scripts、workspace/peer 解析、原生依赖、缓存和许可 | +| 命令对比 | `bun run` 只是脚本入口;脚本中的 node 仍由 Node 执行,不能声称已经换运行时 | +| 构建对比 | 相同版本和源码下构建全部包、文档、worker/WASM,比较包内容与消费者行为 | +| Node 回归 | npm/Node 消费发布包仍通过;现有 node:test 不因包管理器变化被替换 | +| 采用或保留 | 证据充分才改默认文档/CI/锁文件;否则保留 Node 工具链,登记试点结论 | + +评估时本机 Bun 1.3.14 直接运行现有测试遇到 node:test mock.fn 不兼容;这是具体版本的观察,未来升级应重测。Bun bundler 不作为本轮替换目标,因为需要保留 UMD、legacy 语法降级和现有资源处理。参考:[Bun bundler](https://bun.com/docs/bundler)、[workspaces](https://bun.com/docs/pm/workspaces)、[lifecycle](https://bun.com/docs/pm/lifecycle)、[TS allowJs](https://www.typescriptlang.org/tsconfig/allowJs.html)。执行时重新核对官方文档。 + +## 构建改造 + +- 当前 scripts/build.js 和 dev.js 写死 src/index.js;迁移时支持 JS/TS 入口及非交互指定包,并保留旧交互调用。 +- 保留现代 UMD、legacy UMD、ESM、banner、全局名称、AMD 处理、Less/SVG 与 worker 行为。 +- 统一内部构建配置不代表统一公开文件名。thumbnail tool 的 .esm.js 等历史路径必须有生成兼容产物或明确核实结论。 +- 区分源码构建、类型、文档、测试和站点部署;禁止验证步骤顺带修改源码或推送 gh-pages。 +- 移动文件不要与改变运行行为同时铺满全仓库;每次检查 imports、exports、demo URL 和产物。 +- Lerna independent 版本模式保持。是否移除安装/链接脚本要先确认作用,不能因 workspaces 存在就直接删除。 + +## 发布流程 + +1. BASE-01 确定旧核心和插件的支持矩阵,登记 npm tarball integrity。起点 SHA 不能代替消费者产物基线。 +2. REL 阶段为每个发生变化的包生成候选 tarball,用隔离消费者验证,无需先公开发布。 +3. 决定独立版本号、变更日志和包依赖;纯内部兼容重构不自动提升全部包 major,也不自动把所有包改成同一版本。 +4. 预发布 tag、npm 发布、站点部署及推送属于后续实际发布步骤;当前仅创建本地分支与文档,不执行这些动作。 +5. 经授权后按风险批次发布候选版本。优先简单包,再核心兼容候选,最后高风险生态包;不要求用户同时升级整个生态。 +6. 收集有复现步骤的反馈,与旧版本 A/B 对照。达到记录好的验收条件后才能更新正式 tag;不设无依据的自动等待天数。 +7. 记录发布后的 tarball integrity、版本组合、测试、已知限制和回退版本。 + +## 回退与维护 + +- 不删除旧包版本和历史 CDN 文件。包回退通过恢复已验证版本/tag/锁定依赖;不把 unpublish 作为默认方案。 +- 核心和插件可分别回退;候选插件不得只能依赖尚未广泛发布的新核心内部方法。 +- 在发布清单中维护每包的旧版本、新版本、依赖范围和消费者回退命令。 +- 保持 master 的必要修复,并记录如何同步到重构分支;发布前重新建立准确差分基线。 +- 新漏洞、外部 SDK 不兼容和类型破坏单独记录,不能藏在“代码整理”变更日志里。