fix data-aksrt-video 属性

This commit is contained in:
2026-09-05 22:28:19 +08:00
parent 5a61e68a8c
commit 5fbcfa2b49
3 changed files with 27 additions and 1 deletions
@@ -0,0 +1,16 @@
诊断结论(已核实):
`video-player.js:177` 是 `toggle()` 中的 `this.video.play()`。播放器进入“无可播放源”状态后,点击封面/遮罩触发 `toggle()`,该 Promise 没有 catch,于是抛出 `Uncaught (in promise) NotSupportedError: The element has no supported sources`。播放器进入无源状态有四条已确认路径:
1. `.m3u8` 在 Chrome:hls.js 从 `cdn.jsdelivr.net` 懒加载(video-player.js:22),CDN 不可达时 `loadScript` 静默失败(promise 也未 catch),`<video>` 始终没有源;
2. `.flv` 同理(flv.js,video-player.js:23);
3. 直链 mp4 地址 404/编码不支持,源加载失败后 `currentSrc` 为空;
4. `.switch-iframe` 剧集按钮被 video-player 的委托处理器(video-player.js:225)捕获,把 iframe 嵌入页 URL 当 mp4 塞给 `video.src`,必然无源。`.switch-iframe` 本应由 `runtime/main.js:1351` 的 iframe 链路处理。
修复方案(单一路径,不引入双路/迁移):
1. `assets/js/video-player.js`:
- `toggle()`:播放前守卫无源状态(`video.currentSrc`/`video.src`/`this.hls`/`this.flvPlayer` 均为空时直接返回),并对 `play()` 返回的 Promise 加 `.catch()`,播放失败不再产生未捕获异常;
- 两处 `loadScript()`(hls/flv)加 `.catch()`,CDN 失败被收敛为“无源”状态,不再产生未处理 rejection;
- 委托处理器限定为 `.switch-video`,移除对 `.switch-iframe` 的错误接管(iframe 剧集继续由 main.js 既有链路处理,属于删除错误重叠而非新增实现)。
2. 契约测试 `tests/widget-system/single-cover-height-contract.test.cjs` 的 video cover 用例追加断言:toggle 守卫 + play catch、loadScript catch、处理器不含 `.switch-iframe`。
3. 验证:`node --check` 播放器文件、运行 `single-cover-height-contract` 及相关契约测试、`rg` 复查、`git diff --check`;不做真实视觉效果验收。
+3 -1
View File
@@ -35,7 +35,9 @@
}
function initVideo(el) {
if (!once(el, 'Video')) return;
// 幂等标记落在 data-aksrt-widget-video;data-aksrt-video 是
// AksrtVideoPlayer 的自动初始化契约,被扫到会在容器里再挂一个无源播放器。
if (!once(el, 'WidgetVideo')) return;
var fallback = el.querySelector('video');
if (fallback) {
fallback.addEventListener('error', function () {
@@ -171,6 +171,14 @@ test('lazySizes has one auto_fun integration owner and loader boots main once',
assert.match(read('assets/js/pay-vip.js'), /document\.createElement\("img"\)/);
});
test('widget video init flag stays out of the AksrtVideoPlayer attribute namespace', () => {
const widgets = read('assets/widgets/frontend.js');
// data-aksrt-video 是 video-player.js 的自动初始化选择器:小工具容器若带上
// 该属性,会被再挂一个无源播放器(黑条 + 遮罩叠在 DPlayer 上)。
assert.doesNotMatch(widgets, /dataset\.aksrtVideo\s*=/);
assert.match(widgets, /once\(el, 'WidgetVideo'\)/);
});
test('post lists have no second lazy switch and keep legacy fallback thumbnails', () => {
const config = read('inc/helpers/posts-renderer/config.php');
const postData = read('inc/helpers/posts-renderer/post-data.php');