@acwink/movies-search-mcp
Version:
Smart MCP tool to find and validate movie/tv-show resources with multiple sources support
238 lines (224 loc) • 7.26 kB
HTML
<html>
<head>
<title>Video.js通用播放器检测</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=11" />
<meta
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
id="viewport"
name="viewport"
/>
<link rel="stylesheet" href="./videojs/video-js.min.css" />
<script type="text/javascript">
(() => {
// 使用一个唯一的名称以避免冲突
if (window.unifiedVideoValidationPromise) {
return;
}
// 在 window 对象上暴露一个 Promise,以便 Playwright 可以等待结果
window.unifiedVideoValidationPromise = new Promise(
(resolve, reject) => {
// 设置一个全局超时,以防万一
const globalTimeoutTimer = setTimeout(() => {
reject(new Error("Global validation timeout after 15s"));
}, 15000);
const validateVideo = (video) => {
// --- 标准化 video 元素属性 ---
video.autoplay = true;
video.muted = true;
video.preload = "auto";
video.setAttribute("playsinline", "");
// -----------------------------------------
new Promise((videoResolve, videoReject) => {
if (video.error) {
return videoReject();
}
if (video.readyState >= 3) {
// HAVE_FUTURE_DATA
return videoResolve(video);
}
let timeoutId = null;
const cleanup = () => {
clearTimeout(timeoutId);
video.removeEventListener("canplay", onCanPlay);
video.removeEventListener("error", onError);
};
const onCanPlay = () => {
cleanup();
videoResolve(video);
};
const onError = () => {
cleanup();
videoReject();
};
timeoutId = setTimeout(() => {
cleanup();
videoReject();
}, 10000);
video.addEventListener("canplay", onCanPlay);
video.addEventListener("error", onError);
video.load();
})
.then((validVideo) => {
console.log("[validateVideoPlayability] success");
clearTimeout(globalTimeoutTimer);
resolve(true); // 解析主 Promise,表示成功
})
.catch((err) => {
console.log("[validateVideoPlayability] failed");
});
};
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === "childList") {
mutation.addedNodes.forEach((node) => {
if (node.nodeName === "VIDEO") {
validateVideo(node);
} else if (typeof node.querySelectorAll === "function") {
node.querySelectorAll("video").forEach(validateVideo);
}
});
}
}
});
observer.observe(document, {
childList: true,
subtree: true,
});
}
);
})();
</script>
<script type="text/javascript" src="./videojs/video.min.js"></script>
<script
type="text/javascript"
src="./videojs/videojs-http-streaming.min.js"
></script>
<script
type="text/javascript"
src="./videojs/videojs.hotkeys.min.js"
></script>
<script type="text/javascript" src="../js/jquery.js"></script>
<style type="text/css">
html,
body {
background-color: #000;
padding: 0;
margin: 0;
height: 100%;
width: 100%;
color: #999;
overflow: hidden;
}
#video,
.video {
height: 100% ;
width: 100% ;
}
#stats {
position: fixed;
top: 5px;
left: 10px;
font-size: 12px;
color: #fdfdfd;
z-index: 2147483647;
text-shadow:
1px 1px 1px #000,
1px 1px 1px #000;
}
.vjs-poster {
background-color: #161616;
}
/* 中间大的播放按钮 */
.video-js .vjs-big-play-button {
font-size: 2.5em;
line-height: 2.3em;
height: 2.5em;
width: 2.5em;
-webkit-border-radius: 2.5em;
-moz-border-radius: 2.5em;
border-radius: 2.5em;
background-color: rgba(115, 133, 159, 0.5);
border-width: 0.12em;
margin-top: -1.25em;
margin-left: -1.75em;
border-color: #ffb845 ; /*暂停按钮颜色*/
}
/*暂停按钮颜色
.vjs-icon-play:before, .video-js .vjs-play-control .vjs-icon-placeholder:before, .video-js .vjs-big-play-button .vjs-icon-placeholder:before{
color: #ffb845 !important;
}*/
/* 视频暂停时显示播放按钮 */
.video-js.vjs-paused .vjs-big-play-button {
display: block;
}
/* 视频加载出错时隐藏播放按钮 */
.video-js.vjs-error .vjs-big-play-button {
display: none;
}
/* 加载圆圈 */
.vjs-loading-spinner {
font-size: 2.5em;
width: 2em;
height: 2em;
border-radius: 1em;
margin-top: -1em;
margin-left: -1.5em;
}
.video-js .vjs-control-bar {
height: 5em;
}
.video-js .vjs-button > .vjs-icon-placeholder::before {
font-size: 3em;
}
.video-js .vjs-progress-holder {
height: 0.6em;
}
.video-js .vjs-play-progress::before {
font-size: 1.2em;
top: -0.1em;
}
.video-js .vjs-volume-bar {
margin: 2.3em 0.45em;
}
.video-js .vjs-volume-bar.vjs-slider-horizontal {
height: 0.4em;
}
.video-js .vjs-slider-horizontal .vjs-volume-level::before {
top: -0.2em;
}
.video-js .vjs-time-control {
font-size: 1.4em;
line-height: 3.3em;
}
.video-js .vjs-playback-rate {
font-size: 1.4em;
}
.video-js .vjs-playback-rate .vjs-playback-rate-value {
line-height: 2.2em;
}
/* 进度条背景色 */
.video-js .vjs-play-progress {
color: #ffb845;
background-color: #ffb845;
}
</style>
</head>
<body>
<div class="video" id="player">
<video
id="video"
class="video-js vjs-big-play-centered"
controls="controls"
playsinline="true"
webkit-playsinline="true"
x-webkit-airplay="allow"
x5-video-player-fullscreen="true"
preload="auto"
></video>
</div>
<div id="stats">警告:请不要相信视频中任何广告与字幕!</div>
<script type="text/javascript" src="./videojs/setting.js"></script>
</body>
</html>