fix(video): guard sourceless player play attempts
This commit is contained in:
1 parent
51dd38163d
commit
5a61e68a8c
2 files changed
+26
-7
No files matched your search
@@ -153,7 +153,7 @@
|
|||||||
self.hls.loadSource(self.src);
|
self.hls.loadSource(self.src);
|
||||||
self.hls.attachMedia(self.video);
|
self.hls.attachMedia(self.video);
|
||||||
}
|
}
|
||||||
});
|
}).catch(function () { /* CDN unreachable: leave the player sourceless */ });
|
||||||
}
|
}
|
||||||
} else if (this.type === 'flv') {
|
} else if (this.type === 'flv') {
|
||||||
loadScript(FLV_SRC).then(function () {
|
loadScript(FLV_SRC).then(function () {
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
self.flvPlayer.attachMediaElement(self.video);
|
self.flvPlayer.attachMediaElement(self.video);
|
||||||
self.flvPlayer.load();
|
self.flvPlayer.load();
|
||||||
}
|
}
|
||||||
});
|
}).catch(function () { /* CDN unreachable: leave the player sourceless */ });
|
||||||
} else {
|
} else {
|
||||||
this.video.src = this.src;
|
this.video.src = this.src;
|
||||||
}
|
}
|
||||||
@@ -172,9 +172,14 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AksrtVideoPlayer.prototype.hasSource = function () {
|
||||||
|
return Boolean(this.video.currentSrc || this.video.src || this.hls || this.flvPlayer);
|
||||||
|
};
|
||||||
|
|
||||||
AksrtVideoPlayer.prototype.toggle = function () {
|
AksrtVideoPlayer.prototype.toggle = function () {
|
||||||
|
if (!this.hasSource()) return;
|
||||||
if (this.video.paused) {
|
if (this.video.paused) {
|
||||||
this.video.play();
|
this.video.play().catch(function () { /* source failed or autoplay blocked */ });
|
||||||
} else {
|
} else {
|
||||||
this.video.pause();
|
this.video.pause();
|
||||||
}
|
}
|
||||||
@@ -220,9 +225,9 @@
|
|||||||
this.loadSource();
|
this.loadSource();
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── 剧集切换按钮事件委托 ──
|
// ── 剧集切换按钮事件委托(iframe 剧集由 runtime main 的 .switch-iframe 链路处理)──
|
||||||
document.addEventListener('click', function (e) {
|
document.addEventListener('click', function (e) {
|
||||||
var switchBtn = e.target.closest('.switch-video, .switch-iframe');
|
var switchBtn = e.target.closest('.switch-video');
|
||||||
if (!switchBtn) return;
|
if (!switchBtn) return;
|
||||||
|
|
||||||
var container = switchBtn.closest('.aksrt-video') || switchBtn.closest('[data-aksrt-video]');
|
var container = switchBtn.closest('.aksrt-video') || switchBtn.closest('[data-aksrt-video]');
|
||||||
@@ -236,7 +241,7 @@
|
|||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
var src = switchBtn.dataset.src || switchBtn.getAttribute('video-url') || switchBtn.getAttribute('href');
|
var src = switchBtn.dataset.src || switchBtn.getAttribute('video-url') || switchBtn.getAttribute('href');
|
||||||
if (!src) return;
|
if (!src || !/^https?:/i.test(src)) return;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -251,7 +256,7 @@
|
|||||||
|
|
||||||
// 高亮当前集
|
// 高亮当前集
|
||||||
var scope = switchBtn.closest('.featured-video-episode') || (container.parentElement || document);
|
var scope = switchBtn.closest('.featured-video-episode') || (container.parentElement || document);
|
||||||
var siblings = scope.querySelectorAll('.switch-video, .switch-iframe');
|
var siblings = scope.querySelectorAll('.switch-video');
|
||||||
siblings.forEach(function (btn) {
|
siblings.forEach(function (btn) {
|
||||||
btn.classList.remove('is-active');
|
btn.classList.remove('is-active');
|
||||||
btn.classList.remove('active');
|
btn.classList.remove('active');
|
||||||
|
|||||||
@@ -101,6 +101,20 @@ test('video cover: the player video fills and center-crops like the image cover'
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('video cover: play never runs against a sourceless player', () => {
|
||||||
|
const player = read('assets/js/video-player.js');
|
||||||
|
// toggle 必须先守卫无源状态,且 play() 的 promise 必须被捕获。
|
||||||
|
assert.match(player, /hasSource\s*=\s*function\s*\(\)\s*\{[^}]*currentSrc[^}]*\}/);
|
||||||
|
assert.match(player, /toggle\s*=\s*function\s*\(\)\s*\{\s*if\s*\(!this\.hasSource\(\)\)\s*return;/);
|
||||||
|
assert.match(player, /this\.video\.play\(\)\.catch\(function/);
|
||||||
|
// hls/flv CDN 脚本加载失败必须收敛,不得产生未处理 rejection。
|
||||||
|
assert.match(player, /loadScript\(HLS_SRC\)\.then\([\s\S]*?\}\)\.catch\(function/);
|
||||||
|
assert.match(player, /loadScript\(FLV_SRC\)\.then\([\s\S]*?\}\)\.catch\(function/);
|
||||||
|
// iframe 剧集归 runtime main 的 .switch-iframe 链路,播放器不得接管其选择器。
|
||||||
|
assert.doesNotMatch(player, /closest\('\.switch-video, \.switch-iframe'\)/);
|
||||||
|
assert.doesNotMatch(player, /querySelectorAll\('\.switch-video, \.switch-iframe'\)/);
|
||||||
|
});
|
||||||
|
|
||||||
test('resource singles get the cover leaf versioned, never via the aggregate @import', () => {
|
test('resource singles get the cover leaf versioned, never via the aggregate @import', () => {
|
||||||
// 聚合文件的 @import 无版本号:浏览器会拿旧缓存(含已废弃的 .single-cover
|
// 聚合文件的 @import 无版本号:浏览器会拿旧缓存(含已废弃的 .single-cover
|
||||||
// padding 规则)把封面高度链挤成 0,资源型文章封面直接空白。
|
// padding 规则)把封面高度链挤成 0,资源型文章封面直接空白。
|
||||||
|
|||||||
Reference in new issue
Block a user