@acwink/movies-search-mcp
Version:
Smart MCP tool to find and validate movie/tv-show resources with multiple sources support
144 lines (132 loc) • 4.99 kB
HTML
<html>
<head>
<title>DPlayer通用播放器检测</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"
/>
<style type="text/css">
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#playerCnt {
width: 100%;
height: 100%;
}
#stats {
position: fixed;
top: 5px;
left: 10px;
font-size: 12px;
color: #fdfdfd;
z-index: 1054752222;
text-shadow:
1px 1px 1px #000,
1px 1px 1px #000;
}
.dplayer-menu {
display: none ;
}
</style>
<link rel="stylesheet" href="./dplayer/DPlayer.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="./dplayer/flv.min.js"></script>
<script type="text/javascript" src="./dplayer/hls.min.js"></script>
<script type="text/javascript" src="./dplayer/dash.all.min.js"></script>
<script type="text/javascript" src="./dplayer/webtorrent.min.js"></script>
<script type="text/javascript" src="./dplayer/DPlayer.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.js"></script>
</head>
<body marginwidth="0" marginheight="0">
<div id="playerCnt" ondblclick="click2()"></div>
<div id="stats">警告:请不要相信视频中任何广告与字幕!</div>
<script type="text/javascript" src="./dplayer/setting.js"></script>
</body>
</html>