txt / m3u8.html
datxy's picture
Update m3u8.html
ebc96bb verified
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>视频播放与录制控制台</title>
<link rel="shortcut icon" href="https://github.githubassets.com/favicons/favicon.svg" />
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f5f7;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
/* 👇 修复点:将 200vh 改回 100vh,消除底部多余空白 */
min-height: 100vh;
position: relative;
}
/* === 1. 上半部分:左右布局 === */
.main-layout {
display: flex;
width: 100%;
max-width: 1600px;
gap: 20px;
justify-content: space-between;
align-items: stretch;
height: 40vh; /* 视频区域高度自适应 */
min-height: 500px;
}
/* 左侧视频 */
.video-section {
flex: 7; /* 占 70% */
background: #000;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
overflow: hidden;
display: flex;
}
video {
width: 100%;
height: 100%;
object-fit: contain;
background-color: #000;
}
/* 右侧 iframe */
.iframe-section {
flex: 3; /* 占 30% */
background: #fff;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
iframe {
width: 100%;
height: 100%;
border: none;
display: block;
}
/* === 2. 下半部分:输入框和按钮 === */
.controls-container {
display: flex;
width: 100%;
max-width: 1600px;
gap: 15px;
align-items: center;
background: #fff;
padding: 20px;
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
flex-wrap: wrap;
}
.controls-container input[type="text"] {
flex: 1;
min-width: 300px;
padding: 12px 16px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 16px;
outline: none;
transition: border-color 0.3s;
}
.controls-container input[type="text"]:focus {
border-color: #28a745;
}
.controls-container button {
padding: 12px 24px;
border: none;
border-radius: 8px;
background-color: #28a745;
color: #fff;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.3s, transform 0.1s;
white-space: nowrap;
}
.controls-container button:hover {
background-color: #218838;
}
.controls-container button:active {
transform: scale(0.96);
}
/* 针对不同按钮的特殊颜色 */
.controls-container button.cctv-btn {
background-color: #007bff;
}
.controls-container button.cctv-btn:hover {
background-color: #0056b3;
}
.controls-container button.home-btn {
background-color: #6c757d;
}
.controls-container button.home-btn:hover {
background-color: #5a6268;
}
/* 录制闪烁状态 */
.flashing {
background-color: #dc3545 !important;
animation: flash 1s infinite;
}
@keyframes flash {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
/* 响应式:屏幕较小时转为上下布局 */
@media (max-width: 900px) {
body { padding-top: 60px; }
.main-layout {
flex-direction: column;
height: auto;
}
.video-section, .iframe-section {
width: 100%;
height: 400px;
}
.controls-container {
flex-direction: column;
align-items: stretch;
}
.controls-container input[type="text"] {
width: 100%;
}
.controls-container button {
width: 100%;
}
}
</style>
</head>
<body>
<div class="main-layout">
<div class="video-section">
<video id="video" controls></video>
</div>
<div class="iframe-section">
<iframe id="iframe" scrolling="yes" src="base64.html"></iframe>
</div>
</div>
<div class="controls-container">
<input type="text" id="videoUrl" placeholder="输入 m3u8 或视频地址..." value="https://cn-sdqd-cu-01-19.bilivideo.com/live-bvc/681493/live_18200769_73809732/index.m3u8?expires=1742628833&len=0&oi=0x240882072463a0d0711566ed1e98277e&pt=web&qn=10000&trid=100714254ea634a55b603e35b2629b67de59&sigparams=cdn,expires,len,oi,pt,qn,trid&cdn=cn-gotcha01&sign=90fba980adc1f5f48af2bc98b5aaa00f&site=0285fb729986422f272841bef3deeab8&free_type=0&mid=10055177&sche=ban&bvchls=1&sid=cn-sdqd-cu-01-19&chash=1&bmt=1&sg=lr&trace=41&isp=cu&rg=North&pv=Beijing&info_source=origin&sk=2838788edf86108c945c76c1f4ff231a&p2p_type=1&score=1&deploy_env=prod&hot_cdn=0&suffix=origin&source=puv3_onetier&pp=rtmp&sl=1&flvsk=d72c2fc79035cad0f65ee3b59d8bbef0&origin_bitrate=476800&vd=nc&zoneid_l=151339010&sid_l=stream_name_cold&src=puv3&order=1">
<button type="button" onclick="playVideo()">播放 (Play)</button>
<button type="button" id="recordButton" onclick="startRecording()">录制 (Rec)</button>
<button type="button" onclick="stopRecording()">保存 (Save)</button>
<button type="button" class="cctv-btn" onclick="window.open('https://www.yangshipin.cn/tv/home?pid=600001811', '_blank')">CCTV 直播</button>
<button type="button" class="home-btn" onclick="window.location.href='/'">返回首页</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
let mediaRecorder;
let recordedChunks = [];
let flashInterval;
// 播放视频流
function playVideo() {
const url = document.getElementById('videoUrl').value;
const video = document.getElementById('video');
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(url);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
video.play();
});
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url;
video.addEventListener('loadedmetadata', function () {
video.play();
});
} else {
alert('您的浏览器不支持 HLS 播放!');
}
}
// 开始录制
function startRecording() {
const video = document.getElementById('video');
const recordButton = document.getElementById('recordButton');
try {
const stream = video.captureStream();
mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm; codecs=vp9' });
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'recorded-video.webm';
a.click();
recordedChunks = [];
URL.revokeObjectURL(url);
};
mediaRecorder.start();
console.log('Recording started...');
recordButton.classList.add('flashing');
} catch (err) {
console.error("录制失败: ", err);
alert("无法启动录制,请确保视频正在播放且浏览器支持捕获流。");
}
}
// 停止录制并保存
function stopRecording() {
const recordButton = document.getElementById('recordButton');
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
console.log('Recording stopped.');
}
recordButton.classList.remove('flashing');
}
</script>
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({id:"JRHGRBPWC7lJIaXq",ck:"JRHGRBPWC7lJIaXq"})</script>
</body>
</html>