From b382ec08f7ac876b096a64e4ea886564e4f6620d Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Thu, 10 Sep 2026 19:35:55 +0800 Subject: [PATCH] test(refactor): [BASE-02] freeze real-browser public API contracts --- refactor/baselines/README.md | 4 + refactor/baselines/api-coverage.md | 47 + refactor/baselines/public-api.json | 3785 +++++++++++++++++ .../changes/2026-09-10-BASE-02-public-api.md | 26 + refactor/fixtures/README.md | 4 +- refactor/fixtures/api.js | 60 +- refactor/plan.md | 5 +- refactor/progress.md | 6 + refactor/scripts/api.mjs | 65 + refactor/scripts/api.test.mjs | 34 + refactor/scripts/browser-server.mjs | 12 +- refactor/tasks.json | 8 +- 12 files changed, 4034 insertions(+), 22 deletions(-) create mode 100644 refactor/baselines/api-coverage.md create mode 100644 refactor/baselines/public-api.json create mode 100644 refactor/changes/2026-09-10-BASE-02-public-api.md create mode 100644 refactor/scripts/api.mjs create mode 100644 refactor/scripts/api.test.mjs diff --git a/refactor/baselines/README.md b/refactor/baselines/README.md index 30d5fa1f6..fde0ffcd5 100644 --- a/refactor/baselines/README.md +++ b/refactor/baselines/README.md @@ -28,3 +28,7 @@ BASE-01 于 2026-09-10 固定核心与 chapter 的 npm 发布内容,数据在 脚本不安装或执行发布包,不修改生成产物,不把整个 tarball 解压到工作区。归档成员通过 tar 读到内存;后续浏览器服务可复用 ensureArchive/readMember。仅缓存写入,JSON 与说明为持久来源记录;没有新增生产依赖。 修改冻结基线必须通过独立任务和变更记录;不能直接覆盖哈希来消除回归。真实样本或报告一旦生成,绑定包版本/完整性和测试 ID。 + +## 公共 API 报告 + +BASE-02 已在内置浏览器取得核心/chapter 的同步 API 和描述符快照,见 [覆盖与重跑](api-coverage.md) 和 [冻结报告](public-api.json)。事件/生命周期、DOM、类型、分发和其他包仍由各自任务补齐。 diff --git a/refactor/baselines/api-coverage.md b/refactor/baselines/api-coverage.md new file mode 100644 index 000000000..624f71215 --- /dev/null +++ b/refactor/baselines/api-coverage.md @@ -0,0 +1,47 @@ +# 公共 API 基线与契约覆盖 + +BASE-02 使用固定 npm artplayer 5.4.0 + artplayer-plugin-chapter 1.1.0 的 UMD 文件,在 Codex 内置浏览器执行。UA 报告 Windows / Chrome 152.0.0.0,语言 zh-CN;这不是外部 Chrome 扩展或其他浏览器已验证的声明。 + +## 已保存的事实 + +[public-api.json](public-api.json) 包含原始报告、已加载脚本路径、发布包版本/integrity/成员哈希、夹具源码指纹、真实采集时间和重复采集校验结果。最终两次独立 reload 的 14 项检查全部通过,快照相同,浏览器 error/warn 日志为空。 + +| 快照 | 已观察范围 | +| --- | --- | +| static/constants | 47 个静态属性描述符,33 个公开大写配置默认值 | +| defaults/config | 50 个默认选项、config 配置形状;函数用标记保存,不比较函数源码 | +| prototype/emitterPrototype | 核心原型 6 项、Emitter 原型 5 项 | +| instance/instanceResolved | 实例自身 74 项、沿原型查找可访问的 84 项属性描述符 | +| utilityDescriptors | 48 个工具属性的类型和描述符,不代表已测试全部工具行为 | +| integrations | template/events/controls/setting/contextmenu/layers/plugins/storage/subtitle/i18n 共 10 个子系统的 own、直接 prototype 和完整属性查找结果 | +| chapterFactory/chapterResult | 工厂和插件返回对象形状,保持同步注册及结果访问 | + +沿原型查找排除 Object.prototype,保留最近定义;这样能发现 controls.show/toggle 等继承 API 的缺失。快照也会包含实现细节,发现差异时需要区分公开契约和可调整内部状态,记录依据及消费者测试;不能自动覆盖旧快照消除失败,也不能把每个内部反射差异一律当作禁止重构。 + +语言默认值先实测等于 navigator.language.toLowerCase(),再用环境引用标记比较,实际语言保留在报告中。其他环境差异不自动忽略,例如 Safari preload 默认值需在其独立基线中核对。STYLE 大字符串不作默认值精确比较;CSS/DOM 契约由 BASE-04 负责。夹具指纹使用 SHA-256 和 LF 规范化,避免 Git 换行转换影响跨系统复跑;发布 JS 使用原始字节哈希。 + +## 固定测试 ID 和后续责任 + +所有已执行条目都绑定上述两个发布版本及 public-api.json;入口为 ../fixtures/api.html,原断言在 ../fixtures/api.js,比较命令见下节。 + +| 契约 | 已执行的固定 ID / 快照路径 | 未覆盖部分与责任 | +| --- | --- | --- | +| API-01 | API-01.version、defaults-independent、default-language、instance-registration、container-selector;snapshot.defaults/constants/config | ready 回调、useSSR、失败构造、合并边界由 BASE-03/CORE-01/CORE-07 接续 | +| API-02 | API-02.video、bound-query;snapshot.instanceResolved | 播放/切源 Promise、参数边界及其他可抽取方法由 BASE-03 和对应 CORE 任务接续 | +| API-03 | api.test.mjs 的 API comparison 用例;static/prototype/emitterPrototype/instance/integrations 描述符 | 比较器负例验证 writable/接口删除/默认值/继承访问变化;其他构造模式由相关场景补充 | +| API-04 | API-04.on-return、off | once/ctx、重入、异常、事件顺序由 BASE-03 接续 | +| API-05 | API-05.destroy-return、instance-cleanup | 本轮是单实例首次 destroy(true);重复销毁、多实例、removeHtml=false 和资源/媒体顺序由 BASE-03 接续 | +| API-06 | API-06.sync-chapter、add-return、result-call;chapterFactory/chapterResult | 异步注册、重名及 chapter 参数和 UI 由 BASE-03、PKG-CHAPTER-01/02 接续 | +| API-07 | snapshot.integrations 及 utilityDescriptors | 描述符覆盖不等于 UI/轨道/资源行为通过;BASE-04、插件试点和对应 CORE 任务接续 | +| API-08/09/10/11/12 | 此任务不声明完整覆盖 | BASE-04/05/06/08 与对应包任务负责 DOM/CSS、分发、浏览器、类型、持久协议 | + +表中的同前缀短名均指相同契约前缀的完整 ID,例如 defaults-independent 即 API-01.defaults-independent。执行断言列表以 api.mjs 的 checkIds 和报告为准。ENG-09 后续将覆盖索引纳入机器检查;这里没有将整条 API-01 等宽泛契约标成全部通过。 + +## 重跑和比较 + +1. 运行 `node refactor/scripts/browser-server.mjs`,按需要设置 ARTPLAYER_TEST_PORT,默认 8083。 +2. 使用 @Chrome;不可用时直接使用内置浏览器,打开 http://127.0.0.1:8083/fixtures/api.html。每次明确 reload,看到 PASS 且 errors 为空;此次页面只验证同步 API,不等待或验证视频播放。 +3. 运行 `node refactor/scripts/api.mjs --compare refactor/.cache/reports/api.json`。检查全部固定 ID、发布来源、实际脚本、夹具指纹,再比较快照。命令不改冻结文件。 +4. `node refactor/scripts/api.mjs --check` 只核对持久报告和来源/快照摘要;`node --test refactor/scripts/api.test.mjs` 运行报告/比较器负例。两者不启动浏览器,CI 不能把它们当作新一轮真实浏览器执行。 + +yarn test:baseline / ci:check 已通过通配入口包含新增 api.test.mjs。负例涵盖缺检查、错误来源、采集失败、描述符变化、删除方法、选项/静态默认值变化和继承 API 删除。正式候选对照和浏览器自动回归由 ENG-05/07 逐步接入,当前夹具仍固定旧发布文件,不自动加载工作区候选。 diff --git a/refactor/baselines/public-api.json b/refactor/baselines/public-api.json new file mode 100644 index 000000000..7a8be435f --- /dev/null +++ b/refactor/baselines/public-api.json @@ -0,0 +1,3785 @@ +{ + "schemaVersion": 1, + "task": "BASE-02", + "sourceCommit": "833cc116", + "browserSurface": "Codex in-app browser", + "report": { + "kind": "public-api", + "environment": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36", + "language": "zh-CN" + }, + "scripts": [ + "/releases/artplayer/dist/artplayer.js", + "/releases/artplayer-plugin-chapter/dist/artplayer-plugin-chapter.js", + "/fixtures/api.js" + ], + "checks": [ + { + "id": "API-01.version", + "passed": true + }, + { + "id": "API-01.defaults-independent", + "passed": true + }, + { + "id": "API-01.default-language", + "passed": true + }, + { + "id": "API-01.instance-registration", + "passed": true + }, + { + "id": "API-01.container-selector", + "passed": true + }, + { + "id": "API-02.video", + "passed": true + }, + { + "id": "API-02.bound-query", + "passed": true + }, + { + "id": "API-06.sync-chapter", + "passed": true + }, + { + "id": "API-06.add-return", + "passed": true + }, + { + "id": "API-06.result-call", + "passed": true + }, + { + "id": "API-04.on-return", + "passed": true + }, + { + "id": "API-04.off", + "passed": true + }, + { + "id": "API-05.destroy-return", + "passed": true + }, + { + "id": "API-05.instance-cleanup", + "passed": true + } + ], + "errors": [], + "snapshot": { + "static": { + "ASPECT_RATIO": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "AUTO_ORIENTATION_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "AUTO_PLAYBACK_MAX": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "AUTO_PLAYBACK_MIN": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "AUTO_PLAYBACK_TIMEOUT": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "CONTEXTMENU": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "CONTROL_HIDE_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "DBCLICK_FULLSCREEN": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "DBCLICK_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "DEBUG": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "Emitter": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "FAST_FORWARD_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "FAST_FORWARD_VALUE": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "FLIP": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "FULLSCREEN_WEB_IN_BODY": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "INFO_LOOP_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "LOG_VERSION": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "MOBILE_CLICK_PLAY": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "MOBILE_DBCLICK_PLAY": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "NOTICE_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "PLAYBACK_RATE": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "RECONNECT_SLEEP_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "RECONNECT_TIME_MAX": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "REMOVE_SRC_WHEN_DESTROY": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "RESIZE_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "SCROLL_GAP": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "SCROLL_TIME": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "SEEK_STEP": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "SETTING_ITEM_HEIGHT": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "SETTING_ITEM_WIDTH": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "SETTING_WIDTH": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "STYLE": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "TOUCH_MOVE_RATIO": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "USE_RAF": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "VOLUME_STEP": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "config": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "html": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "instances": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "kindOf": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "length": { + "enumerable": false, + "configurable": true, + "writable": false, + "type": "number" + }, + "name": { + "enumerable": false, + "configurable": true, + "writable": false, + "type": "string" + }, + "option": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "prototype": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "object" + }, + "scheme": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "utils": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "validator": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "version": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + } + }, + "prototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "proxy": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "query": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "reset": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "video": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + } + }, + "emitterPrototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "emit": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "off": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "on": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "once": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "defaults": { + "airplay": false, + "aspectRatio": false, + "autoMini": false, + "autoOrientation": false, + "autoPlayback": false, + "autoSize": false, + "autoplay": false, + "backdrop": true, + "container": "#artplayer", + "contextmenu": [], + "controls": [], + "cssVar": {}, + "customType": {}, + "fastForward": false, + "flip": false, + "fullscreen": false, + "fullscreenWeb": false, + "gesture": true, + "highlight": [], + "hotkey": true, + "i18n": {}, + "icons": {}, + "id": "", + "isLive": false, + "lang": { + "$environment": "navigator.language.toLowerCase()" + }, + "layers": [], + "lock": false, + "loop": false, + "miniProgressBar": false, + "moreVideoAttr": { + "controls": false, + "preload": "metadata" + }, + "muted": false, + "mutex": true, + "pip": false, + "playbackRate": false, + "playsInline": true, + "plugins": [], + "poster": "", + "proxy": { + "$undefined": true + }, + "quality": [], + "screenshot": false, + "setting": false, + "settings": [], + "subtitle": { + "encoding": "utf-8", + "escape": true, + "name": "", + "onVttLoad": { + "$function": true + }, + "style": {}, + "type": "", + "url": "" + }, + "subtitleOffset": false, + "theme": "#f00", + "thumbnails": { + "column": 10, + "height": 0, + "number": 60, + "scale": 1, + "url": "", + "width": 0 + }, + "type": "", + "url": "", + "useSSR": false, + "volume": 0.7 + }, + "constants": { + "ASPECT_RATIO": [ + "default", + "4:3", + "16:9" + ], + "AUTO_ORIENTATION_TIME": 200, + "AUTO_PLAYBACK_MAX": 10, + "AUTO_PLAYBACK_MIN": 5, + "AUTO_PLAYBACK_TIMEOUT": 3000, + "CONTEXTMENU": true, + "CONTROL_HIDE_TIME": 3000, + "DBCLICK_FULLSCREEN": true, + "DBCLICK_TIME": 300, + "DEBUG": false, + "FAST_FORWARD_TIME": 1000, + "FAST_FORWARD_VALUE": 3, + "FLIP": [ + "normal", + "horizontal", + "vertical" + ], + "FULLSCREEN_WEB_IN_BODY": true, + "INFO_LOOP_TIME": 1000, + "LOG_VERSION": true, + "MOBILE_CLICK_PLAY": false, + "MOBILE_DBCLICK_PLAY": true, + "NOTICE_TIME": 2000, + "PLAYBACK_RATE": [ + 0.5, + 0.75, + 1, + 1.25, + 1.5, + 2 + ], + "RECONNECT_SLEEP_TIME": 1000, + "RECONNECT_TIME_MAX": 5, + "REMOVE_SRC_WHEN_DESTROY": true, + "RESIZE_TIME": 200, + "SCROLL_GAP": 50, + "SCROLL_TIME": 200, + "SEEK_STEP": 5, + "SETTING_ITEM_HEIGHT": 35, + "SETTING_ITEM_WIDTH": 200, + "SETTING_WIDTH": 250, + "TOUCH_MOVE_RATIO": 0.5, + "USE_RAF": false, + "VOLUME_STEP": 0.1 + }, + "config": { + "events": [ + "abort", + "canplay", + "canplaythrough", + "durationchange", + "emptied", + "ended", + "error", + "loadeddata", + "loadedmetadata", + "loadstart", + "pause", + "play", + "playing", + "progress", + "ratechange", + "seeked", + "seeking", + "stalled", + "suspend", + "timeupdate", + "volumechange", + "waiting" + ], + "methods": [ + "addTextTrack", + "canPlayType", + "load", + "play", + "pause" + ], + "properties": [ + "audioTracks", + "autoplay", + "buffered", + "controller", + "controls", + "crossOrigin", + "currentSrc", + "currentTime", + "defaultMuted", + "defaultPlaybackRate", + "duration", + "ended", + "error", + "loop", + "mediaGroup", + "muted", + "networkState", + "paused", + "playbackRate", + "played", + "preload", + "readyState", + "seekable", + "seeking", + "src", + "startDate", + "textTracks", + "videoTracks", + "volume" + ], + "prototypes": [ + "width", + "height", + "videoWidth", + "videoHeight", + "poster", + "webkitDecodedFrameCount", + "webkitDroppedFrameCount", + "playsInline", + "webkitSupportsFullscreen", + "webkitDisplayingFullscreen", + "onenterpictureinpicture", + "onleavepictureinpicture", + "disablePictureInPicture", + "cancelVideoFrameCallback", + "requestVideoFrameCallback", + "getVideoPlaybackQuality", + "requestPictureInPicture", + "webkitEnterFullScreen", + "webkitEnterFullscreen", + "webkitExitFullScreen", + "webkitExitFullscreen" + ] + }, + "utilityDescriptors": { + "ArtPlayerError": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "addClass": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "append": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "assToVtt": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "capitalize": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "clamp": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "createElement": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "debounce": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "def": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "download": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "errorHandle": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "escape": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "get": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "getComposedPath": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "getExt": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "getIcon": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "getRect": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "getStyle": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "has": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "hasClass": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "includeFromEvent": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "inverseClass": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "isBrowser": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "boolean" + }, + "isIOS": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "boolean" + }, + "isIOS13": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "boolean" + }, + "isInViewport": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "isMobile": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "boolean" + }, + "isSafari": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "boolean" + }, + "loadImg": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "mergeDeep": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "query": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "queryAll": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "remove": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "removeClass": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "replaceElement": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "secondToTime": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "setStyle": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "setStyleText": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "setStyles": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "siblings": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "sleep": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "srtToVtt": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "supportsFlex": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "throttle": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "tooltip": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "unescape": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + }, + "userAgent": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "string" + }, + "vttToBlob": { + "enumerable": true, + "configurable": false, + "writable": false, + "type": "function" + } + }, + "instance": { + "airplay": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "aspectRatio": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "attr": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "autoHeight": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "autoSize": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "backward": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "bottom": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "contextmenu": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "controls": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cssVar": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "currentTime": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "duration": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "e": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "events": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "flip": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "forward": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "fullscreenWeb": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "getBlobUrl": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "getDataURL": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "height": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "hotkey": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "i18n": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "icons": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "info": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "isDestroy": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isFocus": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isInput": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isLock": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isReady": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isRotate": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "layers": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "left": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "loaded": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "loadedTime": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "loading": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "mask": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "mini": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "muted": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "notice": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "option": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "pause": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "pip": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "play": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "playbackRate": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "played": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "player": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "playing": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "plugins": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "poster": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "quality": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "rect": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "right": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "screenshot": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "seek": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "setting": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "state": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "storage": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "subtitle": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "subtitleOffset": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "switch": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "switchQuality": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "switchUrl": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "template": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "theme": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "thumbnails": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "toggle": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "top": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "type": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "url": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "volume": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "width": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "x": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "y": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + } + }, + "instanceResolved": { + "airplay": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "aspectRatio": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "attr": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "autoHeight": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "autoSize": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "backward": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "bottom": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "contextmenu": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "controls": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cssVar": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "currentTime": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "destroy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "duration": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "e": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "emit": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "events": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "flip": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "forward": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "fullscreenWeb": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "getBlobUrl": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "getDataURL": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "height": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "hotkey": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "i18n": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "icons": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "info": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "isDestroy": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isFocus": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isInput": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isLock": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isReady": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "isRotate": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "layers": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "left": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "loaded": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "loadedTime": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "loading": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "mask": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "mini": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "muted": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "notice": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "off": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "on": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "once": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "option": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "pause": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "pip": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "play": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "playbackRate": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "played": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "player": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "playing": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "plugins": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "poster": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "proxy": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "quality": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "query": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "rect": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "reset": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "right": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "screenshot": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "seek": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "setting": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "state": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "storage": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "subtitle": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "subtitleOffset": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "switch": { + "enumerable": false, + "configurable": false, + "get": "undefined", + "set": "function" + }, + "switchQuality": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "switchUrl": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "template": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "theme": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "thumbnails": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "toggle": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "function" + }, + "top": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "type": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "url": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "video": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "volume": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "function" + }, + "width": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "x": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + }, + "y": { + "enumerable": false, + "configurable": false, + "get": "function", + "set": "undefined" + } + }, + "chapterFactory": { + "length": { + "enumerable": false, + "configurable": true, + "writable": false, + "type": "number" + }, + "name": { + "enumerable": false, + "configurable": true, + "writable": false, + "type": "string" + }, + "prototype": { + "enumerable": false, + "configurable": false, + "writable": true, + "type": "object" + } + }, + "chapterResult": { + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "integrations": { + "template": { + "own": { + "$bottom": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$container": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$contextmenu": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controls": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controlsCenter": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controlsLeft": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controlsRight": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$danmuku": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$info": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$infoClose": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$infoPanel": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$layer": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$loading": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$mask": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$notice": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$noticeInner": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$player": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$poster": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$progress": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$setting": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$state": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$subtitle": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$track": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$video": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "query": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "prototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "query": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "$bottom": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$container": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$contextmenu": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controls": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controlsCenter": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controlsLeft": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$controlsRight": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$danmuku": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$info": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$infoClose": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$infoPanel": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$layer": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$loading": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$mask": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$notice": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$noticeInner": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$player": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$poster": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$progress": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$setting": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$state": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$subtitle": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$track": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "$video": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "query": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + } + }, + "events": { + "own": { + "bindGlobalEvents": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroyEvents": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "hover": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "proxy": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "prototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "hover": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "proxy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "remove": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "bindGlobalEvents": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroy": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "destroyEvents": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "hover": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "proxy": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "remove": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + } + }, + "controls": { + "own": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "isHover": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "playAndPause": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "progress": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "thumbnails": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "time": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "timer": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "volume": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + }, + "prototype": { + "add": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "check": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "selector": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "check": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "isHover": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "boolean" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "playAndPause": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "progress": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "selector": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "show": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + }, + "thumbnails": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "time": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "timer": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "toggle": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "volume": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + } + }, + "setting": { + "own": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "active": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "option": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "prototype": { + "add": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "builtin": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "check": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "createHeader": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "createItem": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "find": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "format": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "inactivate": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "remove": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "render": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "resize": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "traverse": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "active": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "builtin": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "check": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "createHeader": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "createItem": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "find": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "format": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "inactivate": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "option": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "render": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "resize": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "show": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + }, + "toggle": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "traverse": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + } + }, + "contextmenu": { + "own": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "close": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "info": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "version": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + }, + "prototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "close": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "info": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "show": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + }, + "toggle": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "version": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + } + }, + "layers": { + "own": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "prototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "$parent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "show": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + }, + "toggle": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + } + }, + "plugins": { + "own": { + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "artplayerPluginChapter": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "object" + }, + "baselineProbe": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "object" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + } + }, + "prototype": { + "add": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "next": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "add": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "artplayerPluginChapter": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "object" + }, + "baselineProbe": { + "enumerable": false, + "configurable": false, + "writable": false, + "type": "object" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "next": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + } + }, + "storage": { + "own": { + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "settings": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + }, + "prototype": { + "clear": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "del": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "get": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "set": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "clear": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "del": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "get": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "set": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "settings": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + } + }, + "subtitle": { + "own": { + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "destroyEvent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "option": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "prototype": { + "activeCues": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "createTrack": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "cues": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "style": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "switch": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "textTrack": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "update": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "url": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + } + }, + "resolved": { + "activeCues": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "add": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "cache": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "createTrack": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "cues": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "destroyEvent": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "id": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "number" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "name": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "string" + }, + "option": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "remove": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "show": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + }, + "style": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "switch": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "textTrack": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "undefined" + }, + "toggle": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "function" + }, + "url": { + "enumerable": false, + "configurable": true, + "get": "function", + "set": "function" + } + } + }, + "i18n": { + "own": { + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "language": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "languages": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + } + }, + "prototype": { + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "get": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "update": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + }, + "resolved": { + "art": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "constructor": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "get": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "init": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + }, + "language": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "languages": { + "enumerable": true, + "configurable": true, + "writable": true, + "type": "object" + }, + "update": { + "enumerable": false, + "configurable": true, + "writable": true, + "type": "function" + } + } + } + } + }, + "capture": { + "capturedAt": "2026-09-10T11:31:33.847Z", + "releases": [ + { + "name": "artplayer", + "version": "5.4.0", + "integrity": "sha512-2B+plbx8N2yNsjK4nJU3+EOG8TULm1LRZk/QPkWRAMEX2Ee/MSnZG/WJYz8kcoZxZuLKcQ3uXifqLuPxZOH29A==", + "member": "package/dist/artplayer.js", + "sha256": "f1db1fa3406aa6d41baa7c554749429a8e79f99d56a794bde23345eb9c07573f" + }, + { + "name": "artplayer-plugin-chapter", + "version": "1.1.0", + "integrity": "sha512-ji66Lr2K2S+OjFMuMby3yq+pefWlOC51Sbpop/DIr2N6w3F0smrF+YZbshN1Dy8/Tx1TYpT7N6WkkZWy5Jix1w==", + "member": "package/dist/artplayer-plugin-chapter.js", + "sha256": "c2aaee11bf1db765433b01d9f8dd3978e41fa4d39655db00ebd03fc0be3e35e0" + } + ], + "fixtureHashAlgorithm": "sha256-lf", + "fixtures": { + "api.html": "b19a20488892bfbbc7b8cc3d325a0472ce2c09259642443e193a00399b27b069", + "api.js": "296785fce39dda7f87b603ee16983f5dd305aada511b6f7fe7ae45ad07669dbf" + } + } + }, + "verification": { + "repeatedCaptureAt": "2026-09-10T11:31:50.198Z", + "snapshotSha256": "fa95270e4f8fe0d5b8af2517b7be2e04d60d2d4ebbcbb2063a9ffbb1268ebdfe", + "repeatComparison": "equal" + } +} diff --git a/refactor/changes/2026-09-10-BASE-02-public-api.md b/refactor/changes/2026-09-10-BASE-02-public-api.md new file mode 100644 index 000000000..7276e607b --- /dev/null +++ b/refactor/changes/2026-09-10-BASE-02-public-api.md @@ -0,0 +1,26 @@ +# BASE-02:冻结公共 API 与默认值 + +日期:2026-09-10;分支 codex/compatible-modernization;起点 833cc116。 + +## 交付 + +扩充 BASE-HARNESS-01 的真实发布包夹具,保存核心 5.4.0 / chapter 1.1.0 的公共 API 描述符和默认值。加入静态配置、继承属性查找、绑定 query、构造选项身份、插件同步返回和销毁返回断言。服务器给报告附加其提供的发布成员和夹具来源指纹。 + +内置浏览器最终两次 reload 的 14 项检查全部通过,快照完全相同,error/warn 日志为空;UA 为 Windows / Chrome 152.0.0.0,语言 zh-CN。报告见 [public-api.json](../baselines/public-api.json),细分的契约、固定测试 ID、重跑命令、限制和后续责任见 [api-coverage.md](../baselines/api-coverage.md)。 + +新增 api.mjs 检查持久报告或比较新采集报告,明确区分“校验已保存的报告”和“重新执行浏览器”。新增两项 Node 测试验证报告必须完整且来源匹配,以及描述符/方法/默认值/继承接口回归会被拒绝。不提供自动覆盖冻结快照的命令。 + +## 兼容与验证 + +没有修改生产源码、公开声明、依赖或发布产物。固定包依旧由归档完整性与成员哈希校验后提供。语言默认值按真实环境关系验证后规范化;其他差异不自动忽略。API 比较记录可观察形状,反射中的内部字段变化仍需要兼容评估,不是把原内部架构永久锁死。 + +- 14 个浏览器断言、两次最终快照一致性通过。 +- 新增 2 个报告/比较器测试及原归档/HTTP 基线测试通过,已由 test:baseline 纳入 CI。 +- 夹具/比较器语法、计划/链接、Git 差异与完整 ci:check 验证通过。 +- 不宣称真实播放、完整生命周期、全部插件、类型或候选新旧组合通过;对应任务继续待办。 + +## 接续与回退 + +每项契约缺口与下一任务记录在 api-coverage.md。下一步 BASE-03 验证事件和生命周期;Chrome 不可用时继续使用内置浏览器。工作区/发布基线差异、第三方 SDK、真实设备和发布门槛保持。 + +本任务独立本地提交,主题包含 BASE-02。可撤销该提交恢复旧夹具;冻结数据保留于 Git 历史,不能直接更新快照隐藏后续回归。没有推送或发布。 diff --git a/refactor/fixtures/README.md b/refactor/fixtures/README.md index c9dfb2ae3..40d3b5745 100644 --- a/refactor/fixtures/README.md +++ b/refactor/fixtures/README.md @@ -2,13 +2,13 @@ `node refactor/scripts/browser-server.mjs` 在 127.0.0.1:8083 启动独立测试服务;ARTPLAYER_TEST_PORT 可更换端口。它不启动或修改用户的 Chrome,也不占用 docs 的 8082 开发服务。 -- `/fixtures/api.html` 加载固定核心/chapter tarball 的真实 JS,准备捕获描述符、默认配置、utils/子系统/插件形状及基础调用。 +- `/fixtures/api.html` 加载固定核心/chapter tarball 的真实 JS,捕获描述符、默认配置、utils/子系统/插件形状及基础调用。 - `/releases//` 只读取 releases.json 明确登记的成员;启动时核对 archive 完整性,不使用未编译源码或 CDN latest。 - `/assets/sample/` 读取本仓库样本,支持普通 bytes 范围请求。当前服务用于最小基线;不是完整 ENG-05 故障注入或 HTTP Range 兼容实现,不支持后缀/多段 Range。 - 页面将 `public-api` 报告发送给同源 `/reports/api`,服务器保存 refactor/.cache/reports/api.json。最多 1 MiB;其他 Origin 和未知写入路径失败。临时报告不能自动覆盖冻结快照。 运行 `node --test refactor/scripts/browser-server.test.mjs` 验证真实 HTTP 服务返回原始 JS 字节、样本范围和路由隔离;`node --check refactor/fixtures/api.js` 只检查脚本语法。两者不能证明页面能在浏览器运行。 -2026-09-10:Chrome 连接服务失败后,用户明确授权使用 Codex 内置浏览器。内置浏览器已打开 api.html,9 项基础 API 检查全部通过,页面 errors 为空,报告已保存至缓存。BASE-02 连接阻塞解除,接续核对报告和来源、生成持久基线;此时尚未完成整个 API 基线任务,也未验证真实播放。 +2026-09-10:按用户授权使用内置浏览器后,BASE-02 最终两次采集的 14 项检查均通过,快照相同,errors 为空。持久报告、比较命令、契约覆盖及剩余范围见 [API 基线](../baselines/api-coverage.md)。本页面没有验证真实播放。 夹具与报告路径由基线任务维护;ENG-05 可复用并扩充受控等待、媒体错误和正式自动化。api.js 依据已核对源码设计断言,真实发布行为如有不同应调查并记录,不能修改断言来盲目通过。 diff --git a/refactor/fixtures/api.js b/refactor/fixtures/api.js index 70e1cadc0..6965a3988 100644 --- a/refactor/fixtures/api.js +++ b/refactor/fixtures/api.js @@ -1,9 +1,14 @@ /* global Artplayer, artplayerPluginChapter */ (async () => { - const report = { kind: 'public-api', environment: { userAgent: navigator.userAgent }, checks: [], errors: [] } - const check = (name, result) => { - report.checks.push({ name, passed: Boolean(result) }) - if (!result) throw new Error(name) + const report = { + kind: 'public-api', + environment: { userAgent: navigator.userAgent, language: navigator.language }, + scripts: [...document.scripts].map(script => new URL(script.src).pathname), + checks: [], errors: [], + } + const check = (id, result) => { + report.checks.push({ id, passed: Boolean(result) }) + if (!result) throw new Error(id) } function descriptors(object) { return Object.fromEntries(Object.getOwnPropertyNames(object).sort().map((name) => { @@ -23,37 +28,57 @@ if (input && typeof input === 'object') return Object.fromEntries(Object.keys(input).sort().map(key => [key, valueOf(input[key])])) return input } + function resolvedDescriptors(object) { + const result = new Map() + for (let current = object; current && current !== Object.prototype; current = Object.getPrototypeOf(current)) { + for (const [name, descriptor] of Object.entries(descriptors(current))) { + if (!result.has(name)) result.set(name, descriptor) + } + } + return Object.fromEntries([...result].sort(([a], [b]) => a.localeCompare(b))) + } let art try { - check('published core version', Artplayer.version === '5.4.0') + check('API-01.version', Artplayer.version === '5.4.0') const defaults = valueOf(Artplayer.option) + check('API-01.defaults-independent', Artplayer.option !== Artplayer.option && Artplayer.option.subtitle !== Artplayer.option.subtitle) + check('API-01.default-language', defaults.lang === navigator.language.toLowerCase()) + defaults.lang = { $environment: 'navigator.language.toLowerCase()' } + const constants = Object.fromEntries(Object.getOwnPropertyNames(Artplayer).sort() + .filter(name => /^[A-Z_]+$/.test(name) && name !== 'STYLE') + .map(name => [name, valueOf(Artplayer[name])])) art = new Artplayer({ container: '.player', url: '/assets/sample/video.mp4', muted: true, plugins: [artplayerPluginChapter()] }) - check('constructor registers exact instance', Artplayer.instances.includes(art)) - check('native media element exposed', art.video instanceof HTMLVideoElement) - check('chapter registered synchronously', art.plugins.artplayerPluginChapter?.name === 'artplayerPluginChapter') + check('API-01.instance-registration', Artplayer.instances.includes(art)) + check('API-01.container-selector', art.template.$container === document.querySelector('.player')) + check('API-02.video', art.video instanceof HTMLVideoElement && art.video === art.template.$video) + const query = art.query + check('API-02.bound-query', query('.art-video') === art.video) + check('API-06.sync-chapter', art.plugins.artplayerPluginChapter?.name === 'artplayerPluginChapter') const plugin = { name: 'baselineProbe', ping: () => 'pong' } const added = art.plugins.add(() => plugin) - check('plugins.add returns synchronous registry', added === art.plugins) - check('plugin result methods callable', art.plugins.baselineProbe.ping() === 'pong') + check('API-06.add-return', added === art.plugins) + check('API-06.result-call', art.plugins.baselineProbe.ping() === 'pong') let received = 0 const handler = amount => { received += amount } - check('on is chainable', art.on('baseline:event', handler) === art) + check('API-04.on-return', art.on('baseline:event', handler) === art) art.emit('baseline:event', 3) art.off('baseline:event', handler) art.emit('baseline:event', 7) - check('custom event on/emit/off', received === 3) + check('API-04.off', received === 3) const integrations = {} for (const name of ['template', 'events', 'controls', 'setting', 'contextmenu', 'layers', 'plugins', 'storage', 'subtitle', 'i18n']) { - integrations[name] = { own: descriptors(art[name]), prototype: descriptors(Object.getPrototypeOf(art[name])) } + integrations[name] = { own: descriptors(art[name]), prototype: descriptors(Object.getPrototypeOf(art[name])), resolved: resolvedDescriptors(art[name]) } } report.snapshot = { static: descriptors(Artplayer), prototype: descriptors(Artplayer.prototype), emitterPrototype: descriptors(Object.getPrototypeOf(Artplayer.prototype)), defaults, + constants, config: valueOf(Artplayer.config), utilityDescriptors: descriptors(Artplayer.utils), instance: descriptors(art), + instanceResolved: resolvedDescriptors(art), chapterFactory: descriptors(artplayerPluginChapter), chapterResult: descriptors(art.plugins.artplayerPluginChapter), integrations, @@ -64,8 +89,13 @@ } finally { if (art) { - art.destroy(true) - report.checks.push({ name: 'instance cleanup', passed: !Artplayer.instances.includes(art) }) + try { + check('API-05.destroy-return', art.destroy(true) === undefined) + check('API-05.instance-cleanup', !Artplayer.instances.includes(art)) + } + catch (error) { + report.errors.push(error.message) + } } } const response = await fetch('/reports/api', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(report) }) diff --git a/refactor/plan.md b/refactor/plan.md index 5ee8ea4d2..919a97010 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 214 项,范围 22 个包及工作区/示例。 -状态:todo 196 / doing 0 / blocked 0 / done 18 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 195 / doing 0 / blocked 0 / done 19 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -61,7 +61,7 @@ | --- | --- | --- | --- | --- | --- | --- | | BASE-01 | workspace
固定核心与试点的最小发布基线 | DOC-07 | 核心及 chapter 的 npm tarball/integrity、源码 SHA、已知支持窗口;其他包标待核对 | 核心/试点来源可重跑;不虚构全生态已验证,各包 01 步负责补齐自身历史发布基线 | H | done | | BASE-HARNESS-01 | workspace
建立最小发布包浏览器采集夹具与服务 | BASE-01 | 固定 tarball 静态服务、本地媒体 Range、公开 API 采集页面及受控报告路径 | HTTP 精确内容/范围和路由隔离测试、夹具语法通过;浏览器采集仍由 BASE-02 负责 | M | done | -| BASE-02 | workspace
捕获公共 API 和属性描述符 | BASE-01, BASE-HARNESS-01 | 核心与试点的构造/默认值/静态和实例 API 快照,其余包由 01/02 步补齐;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 真实发布包反射与旧用户调用可重跑,未验证项明确 | H | todo | +| BASE-02 | workspace
捕获公共 API 和属性描述符 | BASE-01, BASE-HARNESS-01 | 核心与试点的构造/默认值/静态和实例 API 快照,其余包由 01/02 步补齐;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 真实发布包反射与旧用户调用可重跑,未验证项明确 | H | done | | BASE-03 | workspace
捕获事件、异步和生命周期 | BASE-02 | ready/restart/destroy、Promise、切源/插件事件 trace;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 成功、失败、重入和多实例有断言,历史缺陷有标记;使用已发布包和最小可重跑探针启动,不等待后续 ENG 服务 | H | todo | | BASE-04 | workspace
捕获 DOM、CSS 和官方 demo | BASE-02 | 核心模板/类名/变量、键盘/焦点/可访问名称基线及全 demo 路径映射;docs-browser-testing.md 中 HTML/编辑器的脚本来源与存储状态;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 核心/试点用户样式和输入用法已记录,其他 demo 运行状态与未知项明确;使用已发布包和最小可重跑探针启动,不等待后续 ENG 服务 | M | todo | | BASE-05 | workspace
捕获包入口、资源和类型消费 | BASE-01 | 全包 manifest/资源路径清单;核心/试点的 UMD/AMD/ESM/CJS/legacy/i18n 和类型消费者基线;登记契约/版本/固定测试 ID/命令/报告与负责任务;区分库/npm 与站点实际分发类别,SSR import/模板/非浏览器构造错误分别捕获 | 核心/试点隔离消费可运行,其他包由各自契约任务验证,thumbnail tool 差异已登记 | H | todo | @@ -418,6 +418,7 @@ - DOC-13: [记录](changes/2026-09-10-DOC-13-browser-fallback.md) - BASE-01: [记录](changes/2026-09-10-BASE-01-published-baseline.md) [记录](baselines/releases.json) - BASE-HARNESS-01: [记录](changes/2026-09-10-BASE-HARNESS-01-browser-fixture.md) +- BASE-02: [记录](changes/2026-09-10-BASE-02-public-api.md) [记录](baselines/public-api.json) [记录](baselines/api-coverage.md) - ENG-01: [记录](changes/2026-09-10-ENG-01-reproducible-toolchain.md) [记录](baselines/toolchain-validation.json) - ENG-PM-01: [记录](changes/2026-09-10-ENG-PM-01-yarn-toolchain.md) [记录](baselines/yarn-validation.json) - ENG-02: [记录](changes/2026-09-10-ENG-02-readonly-ci.md) [记录](baselines/ci-validation.json) diff --git a/refactor/progress.md b/refactor/progress.md index cc69cc9b9..f72c07929 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,11 @@ # 进度与证据 +## 当前实施:BASE-02 公共 API 基线完成 + +内置浏览器最终两次执行固定 core 5.4.0/chapter 1.1.0 的 14 项同步 API 断言,快照相同,error/warn 日志为空。已保存静态配置、默认选项、实例及继承 API、10 个子系统的描述符和来源指纹;比较器能拒绝描述符/方法/默认值等回归。见 [BASE-02](changes/2026-09-10-BASE-02-public-api.md) 与 [契约覆盖](baselines/api-coverage.md)。 + +当前 214 项任务,19 完成、195 待办。ENG-02 已提交 833cc116;本轮独立提交 BASE-02。没有生产 TS 迁移或发布结论。下一任务 BASE-03,捕获事件、异步和生命周期,并验证真实媒体场景;同步 API 快照不能替代该工作。 + ## 当前实施:ENG-02 只读检查与 CI 基础已完成 新增 PR/主线/复用检查与独立手动 Pages 流程;lint 与自动修复拆分,修复文档构建退出码和生成声明格式。23 项 Node/基线测试、3 个构建后导入 smoke、21 库包 63 产物与文档构建通过;426 个源/类型/测试文件只读检查前后不变,actionlint 静态和负例通过。详见 [ENG-02](changes/2026-09-10-ENG-02-readonly-ci.md) 与 [操作说明](ci-setup.md)。 diff --git a/refactor/scripts/api.mjs b/refactor/scripts/api.mjs new file mode 100644 index 000000000..9d0f388f2 --- /dev/null +++ b/refactor/scripts/api.mjs @@ -0,0 +1,65 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { hash, refactorDir } from './releases.mjs' + +export const checkIds = [ + 'API-01.version', 'API-01.defaults-independent', 'API-01.default-language', + 'API-01.instance-registration', 'API-01.container-selector', 'API-02.video', + 'API-02.bound-query', 'API-06.sync-chapter', 'API-06.add-return', + 'API-06.result-call', 'API-04.on-return', 'API-04.off', + 'API-05.destroy-return', 'API-05.instance-cleanup', +] + +export function validateApiReport(report) { + assert.equal(report.kind, 'public-api') + assert.deepEqual(report.errors, [], 'Browser capture failed') + assert.deepEqual(report.checks, checkIds.map(id => ({ id, passed: true })), 'Missing or failed API checks') + assert(report.environment.userAgent && report.environment.language, 'Missing browser environment') + assert(Number.isFinite(Date.parse(report.capture.capturedAt)), 'Missing capture timestamp') + const releases = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/releases.json'), 'utf8')).releases + const expectedSources = releases.map(release => { + const member = `package/${release.manifest.main.replace(/^\.\//, '')}` + return { name: release.name, version: release.version, integrity: release.integrity, member, sha256: release.files[member] } + }) + assert.deepEqual(report.capture.releases, expectedSources, 'Published sources differ') + assert.deepEqual(report.scripts, [...expectedSources.map(release => `/releases/${release.name}/${release.member.slice('package/'.length)}`), '/fixtures/api.js'], 'Unexpected loaded scripts') + assert.equal(report.capture.fixtureHashAlgorithm, 'sha256-lf') + for (const name of ['api.html', 'api.js']) { + const source = fs.readFileSync(path.join(refactorDir, 'fixtures', name), 'utf8').replaceAll('\r\n', '\n') + assert.equal(report.capture.fixtures[name], hash(source), `Fixture changed: ${name}; review the baseline explicitly`) + } + for (const section of ['static', 'prototype', 'emitterPrototype', 'defaults', 'constants', 'config', 'utilityDescriptors', 'instance', 'instanceResolved', 'chapterFactory', 'chapterResult', 'integrations']) { + assert(report.snapshot?.[section] && Object.keys(report.snapshot[section]).length, `Missing API section: ${section}`) + } + assert.deepEqual(report.snapshot.defaults.lang, { $environment: 'navigator.language.toLowerCase()' }) +} + +export function compareApiSnapshots(expected, actual) { + assert.deepEqual(actual, expected, 'Public API snapshot differs; investigate instead of overwriting the baseline') +} + +export function verifyFrozenApi() { + const frozen = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/public-api.json'), 'utf8')) + assert.equal(frozen.schemaVersion, 1) + validateApiReport(frozen.report) + assert.equal(hash(JSON.stringify(frozen.report.snapshot)), frozen.verification.snapshotSha256, 'Frozen API snapshot digest differs') + return frozen +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + const frozen = verifyFrozenApi() + const index = process.argv.indexOf('--compare') + if (index !== -1) { + assert(process.argv[index + 1], '--compare requires a captured report path') + const captured = JSON.parse(fs.readFileSync(process.argv[index + 1], 'utf8')) + validateApiReport(captured) + compareApiSnapshots(frozen.report.snapshot, captured.snapshot) + console.log('Published API capture matches the frozen snapshot') + } + else { + assert(process.argv.slice(2).every(arg => arg === '--check'), 'Use --check or --compare ') + console.log(`Frozen API verified: ${checkIds.length} browser checks; browser is not rerun by this command`) + } +} diff --git a/refactor/scripts/api.test.mjs b/refactor/scripts/api.test.mjs new file mode 100644 index 000000000..6ac88e412 --- /dev/null +++ b/refactor/scripts/api.test.mjs @@ -0,0 +1,34 @@ +import assert from 'node:assert/strict' +import { test } from 'node:test' +import { compareApiSnapshots, validateApiReport, verifyFrozenApi } from './api.mjs' + +test('frozen API reports require passing checks and the exact published source', () => { + const { report } = verifyFrozenApi() + const missing = structuredClone(report) + missing.checks.pop() + assert.throws(() => validateApiReport(missing), /Missing or failed API checks/) + const wrong = structuredClone(report) + wrong.capture.releases[0].version = '999.0.0' + assert.throws(() => validateApiReport(wrong), /Published sources differ/) + const failed = structuredClone(report) + failed.errors.push('constructor failed') + assert.throws(() => validateApiReport(failed), /Browser capture failed/) +}) + +test('API comparison detects descriptor, method and default-value regressions', () => { + const { snapshot } = verifyFrozenApi().report + compareApiSnapshots(snapshot, structuredClone(snapshot)) + for (const change of [ + copy => { copy.instance.play.enumerable = !copy.instance.play.enumerable }, + copy => { copy.static.NOTICE_TIME.writable = !copy.static.NOTICE_TIME.writable }, + copy => { delete copy.prototype.destroy }, + copy => { copy.defaults.volume = 0.25 }, + copy => { copy.constants.SEEK_STEP += 1 }, + copy => { delete copy.integrations.controls.resolved.show }, + copy => { copy.integrations.controls.resolved.show.set = 'undefined' }, + ]) { + const changed = structuredClone(snapshot) + change(changed) + assert.throws(() => compareApiSnapshots(snapshot, changed), /Public API snapshot differs/) + } +}) diff --git a/refactor/scripts/browser-server.mjs b/refactor/scripts/browser-server.mjs index 9b4543f36..8deed93ae 100644 --- a/refactor/scripts/browser-server.mjs +++ b/refactor/scripts/browser-server.mjs @@ -2,7 +2,7 @@ import assert from 'node:assert/strict' import fs from 'node:fs' import http from 'node:http' import path from 'node:path' -import { ensureArchive, readMember, refactorDir } from './releases.mjs' +import { ensureArchive, hash, readMember, refactorDir } from './releases.mjs' const root = path.resolve(refactorDir, '..') const baseline = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/releases.json'), 'utf8')) @@ -48,6 +48,16 @@ const server = http.createServer(async (req, res) => { } const report = JSON.parse(Buffer.concat(chunks).toString('utf8')) assert.equal(report.kind, 'public-api') + report.capture = { + capturedAt: new Date().toISOString(), + releases: baseline.releases.map(release => ({ + name: release.name, version: release.version, integrity: release.integrity, + member: `package/${release.manifest.main.replace(/^\.\//, '')}`, + sha256: release.files[`package/${release.manifest.main.replace(/^\.\//, '')}`], + })), + fixtureHashAlgorithm: 'sha256-lf', + fixtures: Object.fromEntries(['api.html', 'api.js'].map(name => [name, hash(fs.readFileSync(path.join(refactorDir, 'fixtures', name), 'utf8').replaceAll('\r\n', '\n'))])), + } const output = path.join(refactorDir, '.cache/reports') fs.mkdirSync(output, { recursive: true }) fs.writeFileSync(path.join(output, 'api.json'), `${JSON.stringify(report, null, 2)}\n`) diff --git a/refactor/tasks.json b/refactor/tasks.json index 47b5cf50c..dfa804276 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -285,11 +285,15 @@ "BASE-01", "BASE-HARNESS-01" ], - "status": "todo", + "status": "done", "risk": "H", "deliverable": "核心与试点的构造/默认值/静态和实例 API 快照,其余包由 01/02 步补齐;登记契约/版本/固定测试 ID/命令/报告与负责任务", "acceptance": "真实发布包反射与旧用户调用可重跑,未验证项明确", - "evidence": [] + "evidence": [ + "changes/2026-09-10-BASE-02-public-api.md", + "baselines/public-api.json", + "baselines/api-coverage.md" + ] }, { "id": "BASE-03",