mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
test(asr): [PKG-ASR-01] freeze published interfaces and source contracts
This commit is contained in:
1 parent
3b016970f2
commit
a22586a172
16 files changed
+543
-7
No files matched your search
+3
-2
@@ -51,7 +51,7 @@
|
||||
"ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports",
|
||||
"test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js",
|
||||
"typecheck": "node scripts/typecheck.mjs",
|
||||
"test:unit": "node --test test/jassub.test.js test/multiple-subtitles-merge.test.js test/multiple-subtitles-lifecycle.test.js test/multiple-subtitles-failures.test.js test/multiple-subtitles.test.js test/multiple-subtitles-vendor.test.js test/vtt-thumbnail-parser.test.js test/vtt-thumbnail-lifecycle.test.js test/vtt-thumbnail.test.js test/auto-thumbnail-frames.test.js test/auto-thumbnail-lifecycle.test.js test/auto-thumbnail.test.js test/thumbnail-emitter.test.js test/thumbnail-runtime.test.js test/thumbnail-vendor.test.js test/thumbnail-lifecycle.test.js test/thumbnail-input.test.js test/thumbnail.test.js test/iframe-navigation.test.js test/iframe-boundaries.test.js test/iframe-lifecycle.test.js test/iframe.test.js test/mediabunny.test.js test/mediabunny-shim.test.js test/mediabunny-coordination.test.js test/mediabunny-video.test.js test/mediabunny-audio.test.js test/mediabunny-hls.test.js test/mediabunny-entry.test.js test/mediabunny-capability.test.js test/mediabunny-load.test.js test/mediabunny-input.test.js test/dpip.test.js test/dpip-lifecycle.test.js test/canvas.test.js test/canvas-lifecycle.test.js test/ambilight.test.js test/ambilight-lifecycle.test.js test/ambilight-proxy.test.js test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js",
|
||||
"test:unit": "node --test test/asr.test.js test/jassub.test.js test/multiple-subtitles-merge.test.js test/multiple-subtitles-lifecycle.test.js test/multiple-subtitles-failures.test.js test/multiple-subtitles.test.js test/multiple-subtitles-vendor.test.js test/vtt-thumbnail-parser.test.js test/vtt-thumbnail-lifecycle.test.js test/vtt-thumbnail.test.js test/auto-thumbnail-frames.test.js test/auto-thumbnail-lifecycle.test.js test/auto-thumbnail.test.js test/thumbnail-emitter.test.js test/thumbnail-runtime.test.js test/thumbnail-vendor.test.js test/thumbnail-lifecycle.test.js test/thumbnail-input.test.js test/thumbnail.test.js test/iframe-navigation.test.js test/iframe-boundaries.test.js test/iframe-lifecycle.test.js test/iframe.test.js test/mediabunny.test.js test/mediabunny-shim.test.js test/mediabunny-coordination.test.js test/mediabunny-video.test.js test/mediabunny-audio.test.js test/mediabunny-hls.test.js test/mediabunny-entry.test.js test/mediabunny-capability.test.js test/mediabunny-load.test.js test/mediabunny-input.test.js test/dpip.test.js test/dpip-lifecycle.test.js test/canvas.test.js test/canvas-lifecycle.test.js test/ambilight.test.js test/ambilight-lifecycle.test.js test/ambilight-proxy.test.js test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js",
|
||||
"test:coverage": "node --test test/coverage.test.js && node scripts/coverage.mjs",
|
||||
"test": "yarn test:node && yarn test:baseline",
|
||||
"test:browser": "playwright test",
|
||||
@@ -93,7 +93,8 @@
|
||||
"test:jassub": "node --test test/jassub.test.js refactor/scripts/jassub-contract.test.mjs",
|
||||
"check:ci": "node refactor/scripts/ci-workflow.mjs",
|
||||
"test:ci": "node --test test/ci-summary.test.js refactor/scripts/ci-workflow.test.mjs refactor/scripts/impact.test.mjs test/package-runtime.test.js",
|
||||
"test:package:runtime": "node scripts/package-runtime.mjs --canonical"
|
||||
"test:package:runtime": "node scripts/package-runtime.mjs --canonical",
|
||||
"test:asr": "node --test test/asr.test.js"
|
||||
},
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# ASR maintenance
|
||||
|
||||
The current implementation is still in `src/index.js`. TypeScript migration and
|
||||
resource ownership changes are tracked in the repository refactor plan as
|
||||
PKG-ASR-02 through PKG-ASR-06. Do not interpret the baseline tests as completion.
|
||||
|
||||
- The default factory snapshots options. Registration creates the `asr` layer
|
||||
and subscribes to player play, pause, volumechange and destroy events.
|
||||
- Play creates an AudioContext and tries a media element source, then a captured
|
||||
MediaStream source. An inline Blob contains the `recorder-processor` Worklet.
|
||||
- Worklet messages supply first-channel Float32 samples. The interval callback
|
||||
encodes little-endian mono PCM16 and a 44-byte-header WAV and invokes the
|
||||
caller's `onAudioChunk({ pcm, wav })`. A returned string replaces subtitles.
|
||||
- `append` splits punctuation and sets HTML in `div.art-asr-line`; `hide` changes
|
||||
display only. `src/style.less` owns layout and existing player CSS variables.
|
||||
- `stop()` is actually asynchronous and releases audio resources, but retains
|
||||
playback subscriptions. It is not a permanent disable API. There is no public
|
||||
`start()` method. Public declarations currently describe stop as returning void.
|
||||
|
||||
This package does not implement recognition or open an ASR network connection.
|
||||
The demo service and its WebSocket belong to the caller. Do not run that service
|
||||
to validate audio capture; use local media and a local callback.
|
||||
|
||||
The initial implementation has suspected chunk loss, partial initialization
|
||||
cleanup and stale callback issues. Preserve the frozen historical tests while
|
||||
adding candidate regression tests when fixing these. Keep callback/stop typing
|
||||
compatible with historical assignments, and preserve public entrypoints, HTML
|
||||
rendering behavior, layer names and stylesheet identity.
|
||||
|
||||
From the repository root, `yarn test:asr` verifies historical public behavior;
|
||||
`yarn test:baseline` includes archive provenance. `yarn dev artplayer-plugin-asr`
|
||||
and `yarn build artplayer-plugin-asr` use repository build tools. Real browser
|
||||
audio and lifecycle validation remains a separate required migration step.
|
||||
@@ -1,6 +1,12 @@
|
||||
# artplayer-plugin-asr
|
||||
|
||||
Ads plugin for ArtPlayer
|
||||
Audio capture and subtitle display plugin for ArtPlayer. Supplies PCM/WAV chunks
|
||||
to a caller-provided recognition service.
|
||||
|
||||
## Maintenance
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for the current audio flow, public behavior,
|
||||
known migration gaps and test commands.
|
||||
|
||||
## Demo
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
AI 用于源码分析、任务拆分、实现、测试和差异审查。现代化的验收是可验证的类型、行为和构建质量,不以生成代码量为指标。
|
||||
|
||||
2026-09-13 用户授权使用子代理加快重构。按独立包或不重叠文件划分有界任务,
|
||||
主代理负责集成、共享任务台账和每任务提交;子代理不得同时改同一生产模块或
|
||||
自行批量提交。测试可与契约核对并行,依赖未满足的实现不得提前宣布完成。
|
||||
按实际影响范围验证,完整回归保留在跨包变更和阶段验收节点;不承诺线性加速。
|
||||
|
||||
## 开始任务
|
||||
|
||||
1. 阅读根 AGENTS.md、本目录 README、progress、quality-contract.md,以及所选任务关联的契约/设计。
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# ASR 发布契约
|
||||
|
||||
PKG-ASR-01 于 2026-09-13 固定 npm 2.0.0、2.1.0 的实际归档,每包 6 个成员。
|
||||
[来源与逐文件指纹](asr-release.json)另保存工作区提交的 9 个 Git 文本输入。
|
||||
运行 `node --test test/asr.test.js refactor/scripts/asr-contract.test.mjs`:32 项通过。
|
||||
首次下载使用固定 npm URL;缓存后离线复核 SHA-512、SHA-256、成员与历史 Git 输入。
|
||||
|
||||
## 支持范围与入口
|
||||
|
||||
- registry gitHead 对应核心 manifest 为 5.3.1-beta.1 / 5.3.1;这是来源关联,
|
||||
不是已完成这些核心的播放器组合验证,更不是最低核心版本声明。
|
||||
- 两个发布包没有 engines/peerDependencies;工作区 2.1.0 不等于发布 tarball。
|
||||
- main/legacy 可在 CJS 读取并作为普通 script 暴露 artplayerPluginAsr;2.0.0 的 CJS
|
||||
是只有 default 可枚举成员的对象,2.1.0 是无可枚举成员的函数。测试同时断言这些
|
||||
原始形状,再从函数或 default 成员取得工厂;迁移必须分别保留历史调用路径。
|
||||
- 两个实际 ESM 文件均在无 DOM 环境导入,仅导出 default,调用工厂仍不创建音频资源。
|
||||
- 旧 TS 工厂替换和安装消费者验收归 PKG-ASR-04;不能以本次
|
||||
VM 运行通过替代实际 tarball 安装验证。
|
||||
|
||||
## 公开行为
|
||||
|
||||
| 项目 | 既有行为 |
|
||||
| --- | --- |
|
||||
| 工厂 | option 可省略;在调用工厂时解构,之后更改 option 不影响注册 |
|
||||
| 默认值 | length=3、interval=100ms、sampleRate=16000、autoHideTimeout=10000ms |
|
||||
| 注册 | 同步创建 name=asr 的 layer,返回 name/stop/hide/append;无公开 start |
|
||||
| 事件 | 注册 video:volumechange、play、pause、destroy;播放事件启动采集 |
|
||||
| append | 同步返回 undefined;非字符串忽略,字符串替换全部内容 |
|
||||
| 行拆分 | 按 、。!?!?. 断句,trim/filter,保留最后 length 段;length=0 保留全部 |
|
||||
| 内容 | div.art-asr-line 包裹,通过 innerHTML 接受 HTML;不能静默改为纯文本 |
|
||||
| hide | 只隐藏显示,不清内容;下一次字符串 append 恢复并重置自动隐藏定时器 |
|
||||
| stop | 实际返回 Promise<void>,调用完整音频销毁;保留播放订阅,可随后重启 |
|
||||
| 样式 | 模块加载时按 artplayer-plugin-asr ID 去重;沿用 art-layer-asr/CSS 变量 |
|
||||
|
||||
32 项测试包括两个发布版本的 main/legacy、冻结源码以及冻结工作区 main/legacy,
|
||||
分别观察 CJS/global 工厂、返回值、选项快照、字幕行为、样式去重;另有归档与 ESM 检查。
|
||||
冻结源码用 esbuild 转换,仅把 LESS import 换为测试字符串;该项不验证真实 CSS 编译。
|
||||
真实发布和冻结工作区 bundle 使用其实际内嵌样式。
|
||||
|
||||
## 已发现的差异及后续处理
|
||||
|
||||
1. 两版及工作区声明把 stop 写成 void,onAudioChunk 写成 void | Promise<void>;
|
||||
实际 stop 是异步,并等待回调结果交给 append。类型迁移需保留旧函数赋值能力,
|
||||
补充精确异步消费,不能只改返回类型就宣布兼容。由 PKG-ASR-04 处理。
|
||||
2. 源码每次 tick 取队列再截断,未满一块的样本和超过块长的尾部均没有放回;
|
||||
这是源码事实,PKG-ASR-02 用准确 PCM 样本序列复现,PKG-ASR-03 修复。
|
||||
3. 初始化最后才置 started;停止及异常清理依赖 started,addModule 失败没有 finally
|
||||
回收 URL;停止不能使在途回调失效。PKG-ASR-02 复现后再作独立生命周期修复。
|
||||
4. pause 后 sourceNode 仍存在,而 setupAudioSource 仅在不存在时直接返回节点;
|
||||
再次启动可能进入 captureStream 分支。需验证重复启动与恢复,不能只测一次播放。
|
||||
5. README 误写 Ads;本次改正包功能描述。demo 使用外部 ASR HTTP/WebSocket,服务
|
||||
不是本包依赖或已验证能力。本包只产出 PCM/WAV,不请求麦克风,也不自带识别模型。
|
||||
|
||||
## 下一步与限制
|
||||
|
||||
PKG-ASR-02 建立 PCM/WAV、Worklet 消息、失败、乱序和资源的受控回归;PKG-ASR-03
|
||||
拆分字幕、编码、队列和音频资源职责;PKG-ASR-04 完成严格 TS 与旧消费者。
|
||||
PKG-ASR-05 使用本地媒体与本地 onAudioChunk 验证真实 WebAudio/Worklet、音频持续性、
|
||||
新旧核心与三个浏览器。WebAudio mock 不代替实际音频/采样率/静音/CORS/设备验证。
|
||||
本任务没有运行真实识别服务,不增加依赖,不改生产源码/分发版本。
|
||||
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"registry": "https://registry.npmjs.org/artplayer-plugin-asr",
|
||||
"capturedAt": "2026-09-13T05:57:08.117Z",
|
||||
"sourceCommit": "3b016970f24fea603706a2f4bd50026846f5d939",
|
||||
"sourceNormalization": "Git text normalized to LF; archive members hashed as bytes.",
|
||||
"source": {
|
||||
"packages/artplayer-plugin-asr/package.json": "f0c9fc6c294376c7ed8974556672b077e31fae480bd8e3ecc8b2a060811b29cd",
|
||||
"packages/artplayer-plugin-asr/README.md": "8bc731990d7ab32837af8382a99759ee14b6872dd24065929054a69fdcea2e4e",
|
||||
"packages/artplayer-plugin-asr/src/index.js": "af24a6334298d636235d3af417bdea83444d200563ba6df054b66c53cdaef47f",
|
||||
"packages/artplayer-plugin-asr/src/style.less": "ed40939c1db527bddf98c3e08b8c2e0b1d5a3581804fe2084d1070c9d50af0d6",
|
||||
"packages/artplayer-plugin-asr/types/artplayer-plugin-asr.d.ts": "2d1ecb04f285b5835744d80dbde3c4a2a124bf1f5ffc995d0d775f5725309d0f",
|
||||
"packages/artplayer-plugin-asr/dist/artplayer-plugin-asr.js": "7f975b131a9ea207f88a157aafec778bc4906230500db9b30f5bbfbf327b251d",
|
||||
"packages/artplayer-plugin-asr/dist/artplayer-plugin-asr.legacy.js": "8b9f07ce97a8ce2e4f29e41e79257be530fd7a76558369d34c3d7497ea606c33",
|
||||
"packages/artplayer-plugin-asr/dist/artplayer-plugin-asr.mjs": "f1c4274541e86544b65936ff470413cfc7001999ebc193969f95c123be48cd61",
|
||||
"docs/assets/example/asr.js": "bb7fd5eee3df887b7e0c72a6f42f74f0253350f9bc884f73cb9c2996f0e35724"
|
||||
},
|
||||
"release": {
|
||||
"name": "artplayer-plugin-asr",
|
||||
"version": "2.1.0",
|
||||
"tarball": "https://registry.npmjs.org/artplayer-plugin-asr/-/artplayer-plugin-asr-2.1.0.tgz",
|
||||
"integrity": "sha512-15gXff458PAx9LeJxKzZEvmpFhfwKUfSLgb1Mfr7Xb/ZGsnE+6EA7ezTnO5S55W5mFExjv/e95iOIXP4ijuruQ==",
|
||||
"sha256": "8bc3cd93f78ce99e5c09cc546c770a63e8aea5729d3d584134ce04d826b7708b",
|
||||
"registryGitHead": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
|
||||
"files": {
|
||||
"package/README.md": "8bc731990d7ab32837af8382a99759ee14b6872dd24065929054a69fdcea2e4e",
|
||||
"package/dist/artplayer-plugin-asr.js": "7f975b131a9ea207f88a157aafec778bc4906230500db9b30f5bbfbf327b251d",
|
||||
"package/dist/artplayer-plugin-asr.legacy.js": "8b9f07ce97a8ce2e4f29e41e79257be530fd7a76558369d34c3d7497ea606c33",
|
||||
"package/dist/artplayer-plugin-asr.mjs": "f1c4274541e86544b65936ff470413cfc7001999ebc193969f95c123be48cd61",
|
||||
"package/package.json": "f0c9fc6c294376c7ed8974556672b077e31fae480bd8e3ecc8b2a060811b29cd",
|
||||
"package/types/artplayer-plugin-asr.d.ts": "2d1ecb04f285b5835744d80dbde3c4a2a124bf1f5ffc995d0d775f5725309d0f"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "artplayer-plugin-asr",
|
||||
"version": "2.1.0",
|
||||
"description": "Asr plugin for ArtPlayer",
|
||||
"author": "Harvey Zhao <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-asr.js",
|
||||
"module": "./dist/artplayer-plugin-asr.mjs",
|
||||
"types": "./types/artplayer-plugin-asr.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-asr.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
},
|
||||
"historicalCore": {
|
||||
"commit": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"version": "5.3.1",
|
||||
"sha256LF": "862f3697876fe915dd0ada178da766ce823aae7563ed30b3e5b11b811202929c"
|
||||
}
|
||||
},
|
||||
"previous": [
|
||||
{
|
||||
"name": "artplayer-plugin-asr",
|
||||
"version": "2.0.0",
|
||||
"tarball": "https://registry.npmjs.org/artplayer-plugin-asr/-/artplayer-plugin-asr-2.0.0.tgz",
|
||||
"integrity": "sha512-nXTf2drMSKnHRbyU9CQ+3o7Jsf1Meam2O9T8LqYakIr18ag/+i71p2x9zdFrLz16Xa6jfQgKeddmU5r3sXp4LA==",
|
||||
"sha256": "faa726b9536306664d935c95367230e0c622bd046faf636fc2dcef4bbce4cd47",
|
||||
"registryGitHead": "ca34b47180c94048ee765ab7e146face737eac1c",
|
||||
"files": {
|
||||
"package/README.md": "24446684a782c4c179516917a42862809164aac1ae9746e21a09da738e19ca42",
|
||||
"package/dist/artplayer-plugin-asr.js": "30c7b1fc92a262cda8c3aba63afea9c6c038f52c057039d1c6aa957baed155b6",
|
||||
"package/dist/artplayer-plugin-asr.legacy.js": "2c2bf48751e4d3cfa88f7313f092d395b61bc0564f6cc44f2c76f0fbcfc66412",
|
||||
"package/dist/artplayer-plugin-asr.mjs": "98ebdec2c66cecd9d19904a2e54e4b645f7c267b569e560d9bcbeee6028b2267",
|
||||
"package/package.json": "7545d9bb95b48aedec45c0345f39dd8f0728a24ffe148a04e3740e1ef50239df",
|
||||
"package/types/artplayer-plugin-asr.d.ts": "2d1ecb04f285b5835744d80dbde3c4a2a124bf1f5ffc995d0d775f5725309d0f"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "artplayer-plugin-asr",
|
||||
"version": "2.0.0",
|
||||
"description": "Asr plugin for ArtPlayer",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-asr.js",
|
||||
"module": "./dist/artplayer-plugin-asr.mjs",
|
||||
"types": "./types/artplayer-plugin-asr.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-asr.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
},
|
||||
"historicalCore": {
|
||||
"commit": "ca34b47180c94048ee765ab7e146face737eac1c",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"version": "5.3.1-beta.1",
|
||||
"sha256LF": "e1a0a390ec10cd8c1c12006ac6515414ae98a964300dd3e9c288377def948497"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# PKG-ASR-01:固定 ASR 公开契约
|
||||
|
||||
源起点为 3b016970f24fea603706a2f4bd50026846f5d939。冻结实际 npm 2.0.0/2.1.0、
|
||||
12 个归档成员、9 个工作区 Git 文本及各自历史核心 manifest;不覆盖初始 BASE 快照。
|
||||
交付物为 [契约](../baselines/asr-contract.md)、[来源](../baselines/asr-release.json)、
|
||||
可重跑的 asr-contract 校验器与 test/asr.test.js。生产行为未改动。
|
||||
|
||||
确认接口同步注册、异步 stop、工厂参数快照、字幕替换/HTML/隐藏行为及样式去重。
|
||||
公开声明与异步行为不一致、队列丢样本及初始化清理疑点分别登记到后续任务,
|
||||
未把源码观察写成已修复问题。README 的 Ads 误写修正并链接包内维护说明。
|
||||
|
||||
验证:`node --test test/asr.test.js refactor/scripts/asr-contract.test.mjs` 32 项通过;
|
||||
定向 ESLint、计划与风险台账检查通过。未运行全量 CI、真实浏览器、安装消费者或外部 ASR。
|
||||
本批只固定后续迁移依据,真实音频、旧类型消费与发行验收仍由 ASR-02 至 ASR-06 负责。
|
||||
|
||||
无新依赖。增加 test:asr 命令并把公开行为测试接入 test:unit;来源检查在既有
|
||||
test:baseline 通配入口执行。每次重跑都会校验归档,不静默重写基线。
|
||||
回退本任务提交可移除这些基线、测试、文档与任务状态,不影响当前播放器运行时。
|
||||
+3
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 225 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 86 / doing 16 / blocked 0 / done 123 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 85 / doing 16 / blocked 0 / done 124 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
|
||||
| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| PKG-ASR-01 | artplayer-plugin-asr<br>核对包契约与历史用法 | BASE-05 | length/interval/sampleRate/onAudioChunk、append/hide/stop 的真实能力 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo |
|
||||
| PKG-ASR-01 | artplayer-plugin-asr<br>核对包契约与历史用法 | BASE-05 | length/interval/sampleRate/onAudioChunk、append/hide/stop 的真实能力 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
||||
| PKG-ASR-02 | artplayer-plugin-asr<br>建立特有行为与错误测试 | PKG-ASR-01, ENG-03, ENG-05 | PCM/WAV、chunk 时序、回调慢/拒绝、重复初始化与停止 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo |
|
||||
| PKG-ASR-03 | artplayer-plugin-asr<br>整理内部职责与资源 | PKG-ASR-02, CORE-10, CORE-18 | AudioContext/Worklet/Stream 生命周期和背压分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo |
|
||||
| PKG-ASR-04 | artplayer-plugin-asr<br>迁移自有源码和公开类型 | PKG-ASR-03, ENG-04, ENG-06, CORE-07 | 主线程/Worklet/音频 buffer 与异步回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
|
||||
@@ -526,6 +526,7 @@
|
||||
- PKG-MULTI-SUB-04: [记录](baselines/multiple-subtitles-runtime-types.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-04-runtime-types.md) [记录](baselines/multiple-subtitles-public-types.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-04-public-types.md)
|
||||
- PKG-MULTI-SUB-07: [记录](baselines/multiple-subtitles-timestamps.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md)
|
||||
- PKG-JASSUB-01: [记录](baselines/jassub-release.json) [记录](baselines/jassub-vendor.json) [记录](baselines/jassub-font-metadata.json) [记录](baselines/jassub-contract.md) [记录](baselines/jassub-contract-validation.json) [记录](changes/2026-09-13-PKG-JASSUB-01-baseline.md)
|
||||
- PKG-ASR-01: [记录](changes/2026-09-13-PKG-ASR-01-contracts.md) [记录](baselines/asr-contract.md) [记录](baselines/asr-release.json)
|
||||
- PKG-ADS-01: [记录](baselines/ads-release.json) [记录](baselines/ads-contract.md) [记录](baselines/ads-contract-validation.json) [记录](changes/2026-09-12-PKG-ADS-01-contract.md) [记录](scripts/ads-contract.test.mjs)
|
||||
- PKG-ADS-02: [记录](changes/2026-09-12-PKG-ADS-02-tests.md) [记录](ads-validation.md) [记录](baselines/ads-validation.json)
|
||||
- PKG-ADS-03: [记录](changes/2026-09-12-PKG-ADS-03-lifecycle.md) [记录](ads-validation.md) [记录](baselines/ads-lifecycle-validation.json)
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# 进度与证据
|
||||
|
||||
## PKG-ASR-01 发布契约完成
|
||||
|
||||
冻结实际 npm 2.0.0/2.1.0 共 12 成员及工作区 9 个 Git 输入;32 项契约测试通过,
|
||||
包含 CJS/global、实际 ESM、字幕 HTML/行数/隐藏、异步 stop 和工厂选项快照。
|
||||
声明异步差异、音频丢样本及生命周期疑点已分别登记,未将源码疑点写成已修复。
|
||||
修正 README 的 Ads 误写并增加包内维护地图;无生产源码、依赖或版本变化。
|
||||
见[契约](baselines/asr-contract.md)和[变更](changes/2026-09-13-PKG-ASR-01-contracts.md)。
|
||||
225 项:124 done、16 doing、85 todo;205 风险。下一步 ASR 受控音频测试与源码拆分。
|
||||
用户已授权子代理;当前子代理只写独立音频测试文件,主代理负责契约、台账和提交。
|
||||
实际浏览器、旧类型消费者和全包发布仍待完成;没有运行外部识别服务。
|
||||
|
||||
|
||||
## CORE-25 无 navigator 默认选项修复完成
|
||||
|
||||
defaults.ts 使用 typeof 保护不存在的全局绑定,保留浏览器语言小写、lang 自有字段及每次
|
||||
|
||||
@@ -206,3 +206,6 @@
|
||||
| JASSUB-EXPORT-01 | open / 已复现 | JASSUB historical CommonJS object.default changes to a direct factory in 1.1.0 | PKG-JASSUB-04, PKG-JASSUB-06 |
|
||||
| CORE-DEFAULTS-SSR-01 | resolved / 已复现 | Reading static defaults throws when navigator is absent | CORE-25 |
|
||||
| ENG-DIST-PUBLIC-01 | resolved / 已复现 | Vite copied authored declarations into library distribution | ENG-12 |
|
||||
| ASR-TYPE-01 | open / 源码/产物事实 | ASR declarations omit asynchronous stop and callback text results | PKG-ASR-04 |
|
||||
| ASR-CHUNK-01 | open / 源码/产物事实 | ASR tick discards underfilled chunks and overrun samples in source | PKG-ASR-02, PKG-ASR-03 |
|
||||
| ASR-LIFE-01 | open / 源码/产物事实 | ASR partial initialization, pause resume and stale callback cleanup need controlled evidence | PKG-ASR-02, PKG-ASR-03, PKG-ASR-05 |
|
||||
@@ -4541,6 +4541,54 @@
|
||||
"refactor/changes/2026-09-13-ENG-12-library-public.md"
|
||||
],
|
||||
"resolutionRationale": "Three-format disk fixture and actual core archive prove removal; all other package members remain byte-identical. Full 21-library and docs build passed. CORE-25 runtime work was present but is not closed by this task."
|
||||
},
|
||||
{
|
||||
"id": "ASR-TYPE-01",
|
||||
"title": "ASR declarations omit asynchronous stop and callback text results",
|
||||
"confirmation": "source-observed",
|
||||
"status": "open",
|
||||
"owners": [
|
||||
"PKG-ASR-04"
|
||||
],
|
||||
"evidence": [
|
||||
"refactor/baselines/asr-contract.md",
|
||||
"refactor/baselines/asr-release.json"
|
||||
],
|
||||
"compatibleResolution": "Keep historical assignment compatibility while supplying accurate asynchronous consumption.",
|
||||
"closureCriteria": "Actual old/new installed TS consumers cover void callback, Promise<void>, returned text and factory substitution."
|
||||
},
|
||||
{
|
||||
"id": "ASR-CHUNK-01",
|
||||
"title": "ASR tick discards underfilled chunks and overrun samples in source",
|
||||
"confirmation": "source-observed",
|
||||
"status": "open",
|
||||
"owners": [
|
||||
"PKG-ASR-02",
|
||||
"PKG-ASR-03"
|
||||
],
|
||||
"evidence": [
|
||||
"refactor/baselines/asr-contract.md",
|
||||
"refactor/baselines/asr-release.json"
|
||||
],
|
||||
"compatibleResolution": "Reproduce exact sample loss and retain queue remainders with bounded, ordered callback delivery.",
|
||||
"closureCriteria": "Exact PCM/WAV byte sequence and slow/rejected callback regression tests pass without losing or reordering accepted input."
|
||||
},
|
||||
{
|
||||
"id": "ASR-LIFE-01",
|
||||
"title": "ASR partial initialization, pause resume and stale callback cleanup need controlled evidence",
|
||||
"confirmation": "source-observed",
|
||||
"status": "open",
|
||||
"owners": [
|
||||
"PKG-ASR-02",
|
||||
"PKG-ASR-03",
|
||||
"PKG-ASR-05"
|
||||
],
|
||||
"evidence": [
|
||||
"refactor/baselines/asr-contract.md",
|
||||
"refactor/baselines/asr-release.json"
|
||||
],
|
||||
"compatibleResolution": "Own pending setup, URLs, source nodes and callbacks across pause, stop, restart and terminal destruction.",
|
||||
"closureCriteria": "Failure/race regression tests plus native WebAudio playback and cleanup evidence prove resource ownership."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { archiveFiles, ensureArchive, hash, readMember, refactorDir } from './releases.mjs'
|
||||
|
||||
export async function verifyAsrContract() {
|
||||
const baseline = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/asr-release.json'), 'utf8'))
|
||||
const archives = new Map()
|
||||
for (const release of [baseline.release, ...baseline.previous]) {
|
||||
const archive = await ensureArchive(release)
|
||||
assert.deepEqual(archiveFiles(archive), Object.keys(release.files).sort())
|
||||
for (const [file, expected] of Object.entries(release.files))
|
||||
assert.equal(hash(readMember(archive, file)), expected, `${release.version}/${file}`)
|
||||
assert.deepEqual(JSON.parse(readMember(archive, 'package/package.json')), release.manifest)
|
||||
for (const field of ['main', 'module', 'types', 'legacy'])
|
||||
assert(Object.hasOwn(release.files, `package/${release.manifest[field].replace(/^\.\//, '')}`))
|
||||
const core = release.historicalCore
|
||||
const source = execFileSync('git', ['show', `${core.commit}:${core.file}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
|
||||
assert.equal(hash(source), core.sha256LF)
|
||||
assert.equal(JSON.parse(source).version, core.version)
|
||||
archives.set(release.version, archive)
|
||||
}
|
||||
const sources = new Map()
|
||||
for (const [file, expected] of Object.entries(baseline.source)) {
|
||||
const source = execFileSync('git', ['show', `${baseline.sourceCommit}:${file}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
|
||||
assert.equal(hash(source), expected, file)
|
||||
sources.set(file, source)
|
||||
}
|
||||
return { baseline, archives, sources }
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { Buffer } from 'node:buffer'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Frozen published package evidence uses the repository runner.
|
||||
import test from 'node:test'
|
||||
import { verifyAsrContract } from './asr-contract.mjs'
|
||||
import { readMember } from './releases.mjs'
|
||||
|
||||
const { baseline, archives, sources } = await verifyAsrContract()
|
||||
const releases = [baseline.release, ...baseline.previous]
|
||||
test('ASR verifies both releases, twelve archive members, nine Git inputs and historical core references', () => {
|
||||
assert.deepEqual(releases.map(r => r.version), ['2.1.0', '2.0.0'])
|
||||
assert.equal(releases.reduce((n, r) => n + Object.keys(r.files).length, 0), 12)
|
||||
assert.equal(sources.size, 9)
|
||||
assert.deepEqual(releases.map(r => r.historicalCore.version), ['5.3.1', '5.3.1-beta.1'])
|
||||
for (const release of releases) {
|
||||
assert.equal(release.manifest.peerDependencies, undefined)
|
||||
assert.equal(release.manifest.engines, undefined)
|
||||
}
|
||||
})
|
||||
test('ASR old declarations describe void callback/stop despite runtime consuming returned text and returning a Promise', () => {
|
||||
for (const release of releases) {
|
||||
const types = readMember(archives.get(release.version), 'package/types/artplayer-plugin-asr.d.ts').toString()
|
||||
assert.match(types, /onAudioChunk\?: \(chunk: AudioChunk\) => void \| Promise<void>/)
|
||||
assert.match(types, /stop: \(\) => void/)
|
||||
assert.match(types, /export default artplayerPluginAsr/)
|
||||
assert.match(types, /option\?: AsrPluginOption/)
|
||||
}
|
||||
})
|
||||
test('ASR actual published ESM exposes a lazy default factory without requiring a browser', async () => {
|
||||
for (const release of releases) {
|
||||
const source = readMember(archives.get(release.version), 'package/dist/artplayer-plugin-asr.mjs')
|
||||
const module = await import(`data:text/javascript;base64,${Buffer.from(source).toString('base64')}`)
|
||||
assert.deepEqual(Object.keys(module), ['default'])
|
||||
assert.equal(typeof module.default(), 'function')
|
||||
}
|
||||
})
|
||||
test('ASR source ships an inline Worklet; network transcription is caller-owned example behavior', () => {
|
||||
const source = sources.get('packages/artplayer-plugin-asr/src/index.js')
|
||||
assert.match(source, /registerProcessor\('recorder-processor'/)
|
||||
assert.doesNotMatch(source, /\bfetch\(|new WebSocket\(/)
|
||||
const demo = sources.get('docs/assets/example/asr.js')
|
||||
assert.match(demo, /await fetch\(api\)/)
|
||||
assert.match(demo, /new WebSocket\(url\)/)
|
||||
for (const release of releases)
|
||||
assert(!Object.keys(release.files).some(file => /worklet|worker|\.wasm/.test(file)))
|
||||
})
|
||||
+6
-2
@@ -2617,11 +2617,15 @@
|
||||
"dependsOn": [
|
||||
"BASE-05"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "H",
|
||||
"deliverable": "length/interval/sampleRate/onAudioChunk、append/hide/stop 的真实能力",
|
||||
"acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-13-PKG-ASR-01-contracts.md",
|
||||
"baselines/asr-contract.md",
|
||||
"baselines/asr-release.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PKG-ASR-02",
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import assert from 'node:assert/strict'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Historical ASR contracts use the repository runner.
|
||||
import test from 'node:test'
|
||||
import { asrEnvironment, asrHistorical } from './helpers/asr.js'
|
||||
|
||||
for (const implementation of await asrHistorical()) {
|
||||
for (const script of [false, true]) {
|
||||
test(`ASR ${implementation.name}: ${script ? 'global' : 'CJS'} lazy factory, synchronous result and async stop`, async () => {
|
||||
const env = asrEnvironment(implementation, { script })
|
||||
if (!script) {
|
||||
const namespace = implementation.name.startsWith('published-2.0.0') || implementation.name === 'frozen-source'
|
||||
assert.equal(typeof env.exported, namespace ? 'object' : 'function')
|
||||
assert.deepEqual(Object.keys(env.exported), namespace ? ['default'] : [])
|
||||
}
|
||||
const register = env.factory()
|
||||
assert.equal(env.layers.length, 0)
|
||||
const result = register(env.art)
|
||||
assert.deepEqual(Object.keys(result), ['name', 'stop', 'hide', 'append'])
|
||||
assert.equal(result.name, 'artplayerPluginAsr')
|
||||
assert.equal(result.then, undefined)
|
||||
assert.equal(result.start, undefined)
|
||||
assert.equal(env.layers[0].name, 'asr')
|
||||
assert.deepEqual([...env.listeners.keys()], ['video:volumechange', 'play', 'pause', 'destroy'])
|
||||
const stopped = result.stop()
|
||||
assert.equal(typeof stopped.then, 'function')
|
||||
assert.equal(await stopped, undefined)
|
||||
assert.equal(env.listeners.get('play').length, 1, 'stop retains historical restart subscription')
|
||||
assert.equal(env.styles.size, 1)
|
||||
env.reload()
|
||||
assert.equal(env.styles.size, 1)
|
||||
})
|
||||
}
|
||||
test(`ASR ${implementation.name}: append replaces punctuation lines, permits markup, and hide retains content`, () => {
|
||||
const env = asrEnvironment(implementation)
|
||||
const result = env.factory()(env.art)
|
||||
assert.equal(result.append('One. Two! 三。 Four?'), undefined)
|
||||
assert.equal(env.layer.innerHTML, '<div class="art-asr-line">Two!</div><div class="art-asr-line">三。</div><div class="art-asr-line">Four?</div>')
|
||||
assert.equal([...env.timeouts.values()][0].delay, 10000)
|
||||
result.append('<b>markup</b>')
|
||||
assert.equal(env.layer.innerHTML, '<div class="art-asr-line"><b>markup</b></div>')
|
||||
assert.equal(env.timeouts.size, 1)
|
||||
result.hide()
|
||||
assert.equal(env.layer.style.display, 'none')
|
||||
assert.equal(result.append(null), undefined)
|
||||
assert.equal(env.layer.style.display, 'none')
|
||||
assert.equal(env.timeouts.size, 1)
|
||||
result.append('')
|
||||
assert.equal(env.layer.innerHTML, '')
|
||||
assert.equal(env.layer.style.display, '')
|
||||
;[...env.timeouts.values()][0].callback()
|
||||
assert.equal(env.layer.style.display, 'none')
|
||||
})
|
||||
test(`ASR ${implementation.name}: options are captured at factory call and instances own subtitle timers`, () => {
|
||||
const option = { length: 1, autoHideTimeout: 25 }
|
||||
const env = asrEnvironment(implementation)
|
||||
const register = env.factory(option)
|
||||
option.length = 4
|
||||
option.autoHideTimeout = 99
|
||||
register(env.art).append('one. two.')
|
||||
assert.equal(env.layer.innerHTML, '<div class="art-asr-line">two.</div>')
|
||||
assert.equal([...env.timeouts.values()][0].delay, 25)
|
||||
const other = asrEnvironment(implementation)
|
||||
other.factory({ length: 0 })(other.art).append('one. two.')
|
||||
assert.equal(other.layer.innerHTML, '<div class="art-asr-line">one.</div><div class="art-asr-line">two.</div>', 'zero retains historical slice(-0) semantics')
|
||||
assert.equal(env.timeouts.size, 1)
|
||||
assert.equal(other.timeouts.size, 1)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import vm from 'node:vm'
|
||||
import { transform } from 'esbuild'
|
||||
import { verifyAsrContract } from '../../refactor/scripts/asr-contract.mjs'
|
||||
import { readMember } from '../../refactor/scripts/releases.mjs'
|
||||
|
||||
export async function asrHistorical() {
|
||||
const { baseline, archives, sources } = await verifyAsrContract()
|
||||
const implementations = []
|
||||
for (const release of [baseline.release, ...baseline.previous]) {
|
||||
for (const field of ['main', 'legacy'])
|
||||
implementations.push({ name: `published-${release.version}-${field}`, code: readMember(archives.get(release.version), `package/${release.manifest[field].replace(/^\.\//, '')}`).toString() })
|
||||
}
|
||||
const prefix = 'packages/artplayer-plugin-asr'
|
||||
const source = sources.get(`${prefix}/src/index.js`).replace('import style from \'./style.less?inline\'', 'const style = \'frozen-source-style\'')
|
||||
implementations.push({ name: 'frozen-source', code: (await transform(source, { format: 'cjs', target: 'es2020' })).code, scriptCode: (await transform(source, { format: 'iife', globalName: 'artplayerPluginAsr', target: 'es2020' })).code })
|
||||
for (const suffix of ['js', 'legacy.js'])
|
||||
implementations.push({ name: `frozen-workspace-${suffix}`, code: sources.get(`${prefix}/dist/artplayer-plugin-asr.${suffix}`) })
|
||||
return implementations
|
||||
}
|
||||
|
||||
export function asrEnvironment(implementation, { script = false } = {}) {
|
||||
const listeners = new Map()
|
||||
const timeouts = new Map()
|
||||
const styles = new Map()
|
||||
const layer = { style: {}, innerHTML: '' }
|
||||
let id = 0
|
||||
const context = vm.createContext({
|
||||
console,
|
||||
setTimeout(callback, delay) {
|
||||
timeouts.set(++id, { callback, delay })
|
||||
return id
|
||||
},
|
||||
clearTimeout(timer) { timeouts.delete(timer) },
|
||||
document: {
|
||||
getElementById: id => styles.get(id),
|
||||
createElement: () => ({}),
|
||||
head: { appendChild(element) { styles.set(element.id, element) } },
|
||||
},
|
||||
})
|
||||
context.window = context
|
||||
if (!script) {
|
||||
context.module = { exports: {} }
|
||||
context.exports = context.module.exports
|
||||
}
|
||||
const code = script ? implementation.scriptCode || implementation.code : `(function () {\n${implementation.code}\n}).call(globalThis)`
|
||||
vm.runInContext(code, context, { timeout: 1000 })
|
||||
const exported = script ? context.artplayerPluginAsr : context.module.exports
|
||||
const factory = typeof exported === 'function' ? exported : exported.default
|
||||
assert.equal(typeof factory, 'function', implementation.name)
|
||||
const layers = []
|
||||
const art = {
|
||||
video: {},
|
||||
volume: 0.5,
|
||||
layers: { add(option) {
|
||||
layers.push(option)
|
||||
return layer
|
||||
} },
|
||||
on(name, callback) { listeners.set(name, [...listeners.get(name) || [], callback]) },
|
||||
}
|
||||
return { context, factory, exported, styles, layer, layers, listeners, timeouts, art, reload: () => vm.runInContext(code, context), emit: name => Promise.all((listeners.get(name) || []).map(callback => callback())) }
|
||||
}
|
||||
Reference in new issue
Block a user