[十八岁太奶奶驾到,重整家族荣耀][第四季全集]
<!DOCTYPE html><html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Discuz M3U8 分集播放器</title>
<!-- 引入 TailwindCSS -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
corePlugins: {
preflight: false, // 关闭Tailwind的全局重置样式,避免覆盖Discuz原有页面样式
}
}
</script>
<!-- 引入 Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- 引入 Hls.js -->
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest/dist/hls.min.js"></script>
<style>
/* 自定义滚动条样式 */
.episode-scroll::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.episode-scroll::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.episode-scroll::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 3px;
}
.episode-scroll::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
/* 选中状态动画 */
.episode-btn.active {
background-color: #3b82f6;
color: white;
border-color: #3b82f6;
}
/* 加载动画 */
.loader {
border: 3px solid #f3f3f3;
border-radius: 50%;
border-top: 3px solid #3b82f6;
width: 24px;
height: 24px;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body class="bg-gray-100 p-4 font-sans">
<!-- 播放器容器 -->
<div id="dz-video-player-container" class="max-w-4xl mx-auto bg-white rounded-xl shadow-lg overflow-hidden border border-gray-200" style="isolation: isolate;">
<!-- 视频区域 -->
<div class="relative w-full aspect-video bg-black group">
<video id="dz-video-element" class="w-full h-full object-contain" controls playsinline poster="/data/attachment/album/202608/31/200711vfnhzq7opn8dqp00.jpg"></video>
<!-- 加载指示器 -->
<div id="dz-loading-indicator" class="absolute inset-0 flex items-center justify-center bg-black/50 hidden z-10">
<div class="loader"></div>
</div>
<!-- 错误提示层 -->
<div id="dz-error-overlay" class="absolute inset-0 flex flex-col items-center justify-center bg-black/80 text-white hidden z-20">
<i class="fas fa-exclamation-triangle text-4xl mb-2 text-red-500"></i>
<p class="text-sm">视频加载失败,请检查网络或链接有效性</p>
<button onclick="retryLoad()" class="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded text-sm transition">重试</button>
</div>
</div>
<!-- 控制面板:标题与分集 -->
<div class="p-4 bg-white">
<div class="flex justify-between items-center mb-4 border-b pb-2">
<h2 id="dz-video-title" class="text-lg font-bold text-gray-800 truncate pr-4">正在播放:第 1 集</h2>
<!-- div class="text-xs text-gray-500 flex items-center gap-2">
<span id="dz-quality-badge" class="px-2 py-1 bg-gray-100 rounded text-gray-600">HD</span>
<span id="dz-duration">00:00</span>
</div -->
</div>
<!-- 分集列表 -->
<div class="mb-2 flex justify-between items-center">
<span class="text-sm font-semibold text-gray-700"><i class="fas fa-list-ul mr-1"></i> 选集</span>
<div class="flex gap-2">
<button onclick="toggleOrder()" class="text-xs text-blue-600 hover:text-blue-800 flex items-center gap-1">
<i class="fas fa-sort-amount-down" id="sort-icon"></i> <span id="sort-text">倒序</span>
</button>
</div>
</div>
<div id="dz-episode-list" class="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-2 max-h-40 overflow-y-auto episode-scroll p-1">
<!-- 分集按钮将通过 JS 动态生成 -->
</div>
</div>
</div>
<script>
/**
* Discuz M3U8 Player Configuration
* 在 Discuz 发帖时,只需修改此处的 videoData 数组即可
*/
const videoData = [
{ title: "第01集", url: "https://v.cdnlz29.com/20260223/221846_dc481af2/2000k/hls/mixed.m3u8"},
{ title: "第02集", url: "https://v.cdnlz29.com/20260223/221848_2330ec1e/2000k/hls/mixed.m3u8"},
{ title: "第03集", url: "https://v.cdnlz29.com/20260223/221847_14d1153b/2000k/hls/mixed.m3u8"},
{ title: "第04集", url: "https://v.cdnlz29.com/20260223/221850_4e3a44eb/2000k/hls/mixed.m3u8"},
{ title: "第05集", url: "https://v.cdnlz29.com/20260223/221849_c3741bff/2000k/hls/mixed.m3u8"},
{ title: "第06集", url: "https://v.cdnlz29.com/20260223/221851_132511dd/2000k/hls/mixed.m3u8"},
{ title: "第07集", url: "https://v.cdnlz29.com/20260223/221853_60718af0/2000k/hls/mixed.m3u8"},
{ title: "第08集", url: "https://v.cdnlz29.com/20260223/221852_b3b37791/2000k/hls/mixed.m3u8"},
{ title: "第09集", url: "https://v.cdnlz29.com/20260223/221854_e57706dc/2000k/hls/mixed.m3u8"},
{ title: "第10集", url: "https://v.cdnlz29.com/20260223/221856_3edb846c/2000k/hls/mixed.m3u8"},
{ title: "第11集", url: "https://v.cdnlz29.com/20260223/221855_95b6985e/2000k/hls/mixed.m3u8"},
{ title: "第12集", url: "https://v.cdnlz29.com/20260223/221857_c550d523/2000k/hls/mixed.m3u8"},
{ title: "第13集", url: "https://v.cdnlz29.com/20260223/221860_eab4bea8/2000k/hls/mixed.m3u8"},
{ title: "第14集", url: "https://v.cdnlz29.com/20260223/221859_7bd70404/2000k/hls/mixed.m3u8"},
{ title: "第15集", url: "https://v.cdnlz29.com/20260223/221858_5ee5d4e8/2000k/hls/mixed.m3u8"},
{ title: "第16集", url: "https://v.cdnlz29.com/20260223/221861_9e88e97f/2000k/hls/mixed.m3u8"},
{ title: "第17集", url: "https://v.cdnlz29.com/20260223/221862_3499900c/2000k/hls/mixed.m3u8"},
{ title: "第18集", url: "https://v.cdnlz29.com/20260223/221863_b60d7985/2000k/hls/mixed.m3u8"},
{ title: "第19集", url: "https://v.cdnlz29.com/20260223/221864_14e1276e/2000k/hls/mixed.m3u8"},
{ title: "第20集", url: "https://v.cdnlz29.com/20260223/221865_884ec8c4/2000k/hls/mixed.m3u8"},
{ title: "第21集", url: "https://v.cdnlz29.com/20260223/221868_6ded2c16/2000k/hls/mixed.m3u8"},
{ title: "第22集", url: "https://v.cdnlz29.com/20260223/221869_2cb190c8/2000k/hls/mixed.m3u8"},
{ title: "第23集", url: "https://v.cdnlz29.com/20260223/221866_89579ba9/2000k/hls/mixed.m3u8"},
{ title: "第24集", url: "https://v.cdnlz29.com/20260223/221870_9f0985cc/2000k/hls/mixed.m3u8"},
{ title: "第25集", url: "https://v.cdnlz29.com/20260223/221867_2112276c/2000k/hls/mixed.m3u8"},
{ title: "第26集", url: "https://v.cdnlz29.com/20260223/221871_01b3bbdc/2000k/hls/mixed.m3u8"},
{ title: "第27集", url: "https://v.cdnlz29.com/20260223/221872_32c421ef/2000k/hls/mixed.m3u8"},
{ title: "第28集", url: "https://v.cdnlz29.com/20260223/221873_19e44e4d/2000k/hls/mixed.m3u8"},
{ title: "第29集", url: "https://v.cdnlz29.com/20260223/221874_a725bc12/2000k/hls/mixed.m3u8"},
{ title: "第30集", url: "https://v.cdnlz29.com/20260223/221875_9bc20cee/2000k/hls/mixed.m3u8"},
{ title: "第31集", url: "https://v.cdnlz29.com/20260223/221876_eede2736/2000k/hls/mixed.m3u8"},
{ title: "第32集", url: "https://v.cdnlz29.com/20260223/221877_66354462/2000k/hls/mixed.m3u8"},
{ title: "第33集", url: "https://v.cdnlz29.com/20260223/221878_4114fde5/2000k/hls/mixed.m3u8"},
{ title: "第34集", url: "https://v.cdnlz29.com/20260223/221880_e57e83bf/2000k/hls/mixed.m3u8"},
{ title: "第35集", url: "https://v.cdnlz29.com/20260223/221879_d628eea1/2000k/hls/mixed.m3u8"},
{ title: "第36集", url: "https://v.cdnlz29.com/20260223/221881_96503537/2000k/hls/mixed.m3u8"},
{ title: "第37集", url: "https://v.cdnlz29.com/20260223/221882_276ef609/2000k/hls/mixed.m3u8"},
{ title: "第38集", url: "https://v.cdnlz29.com/20260223/221883_705ee5e7/2000k/hls/mixed.m3u8"},
{ title: "第39集", url: "https://v.cdnlz29.com/20260223/221885_50e0f28f/2000k/hls/mixed.m3u8"},
{ title: "第40集", url: "https://v.cdnlz29.com/20260223/221888_3715738e/2000k/hls/mixed.m3u8"},
{ title: "第41集", url: "https://v.cdnlz29.com/20260223/221884_5194274b/2000k/hls/mixed.m3u8"},
{ title: "第42集", url: "https://v.cdnlz29.com/20260223/221886_a0d06dc5/2000k/hls/mixed.m3u8"},
{ title: "第43集", url: "https://v.cdnlz29.com/20260223/221887_3d350afb/2000k/hls/mixed.m3u8"},
{ title: "第44集", url: "https://v.cdnlz29.com/20260223/221889_8396bd2f/2000k/hls/mixed.m3u8"},
{ title: "第45集", url: "https://v.cdnlz29.com/20260223/221891_a52c7392/2000k/hls/mixed.m3u8"},
{ title: "第46集", url: "https://v.cdnlz29.com/20260223/221893_00f33239/2000k/hls/mixed.m3u8"},
{ title: "第47集", url: "https://v.cdnlz29.com/20260223/221890_0c6f3dae/2000k/hls/mixed.m3u8"},
{ title: "第48集", url: "https://v.cdnlz29.com/20260223/221892_ceb3da29/2000k/hls/mixed.m3u8"},
{ title: "第49集", url: "https://v.cdnlz29.com/20260223/221894_88db5c65/2000k/hls/mixed.m3u8"},
{ title: "第50集", url: "https://v.cdnlz29.com/20260223/221895_c697ecd4/2000k/hls/mixed.m3u8"},
{ title: "第51集", url: "https://v.cdnlz29.com/20260223/221898_249c460d/2000k/hls/mixed.m3u8"},
{ title: "第52集", url: "https://v.cdnlz29.com/20260223/221896_a7f232cb/2000k/hls/mixed.m3u8"},
{ title: "第53集", url: "https://v.cdnlz29.com/20260223/221900_d5d794a2/2000k/hls/mixed.m3u8"},
{ title: "第54集", url: "https://v.cdnlz29.com/20260223/221897_aeb5483e/2000k/hls/mixed.m3u8"},
{ title: "第55集", url: "https://v.cdnlz29.com/20260223/221899_ea7dcfa7/2000k/hls/mixed.m3u8"},
{ title: "第56集", url: "https://v.cdnlz29.com/20260223/221902_86d15afc/2000k/hls/mixed.m3u8"},
{ title: "第57集", url: "https://v.cdnlz29.com/20260223/221904_8783eb47/2000k/hls/mixed.m3u8"},
{ title: "第58集", url: "https://v.cdnlz29.com/20260223/221903_3e95cdcf/2000k/hls/mixed.m3u8"},
{ title: "第59集", url: "https://v.cdnlz29.com/20260223/221905_aaa4e2f3/2000k/hls/mixed.m3u8"},
{ title: "第60集", url: "https://v.cdnlz29.com/20260223/221901_d0d774de/2000k/hls/mixed.m3u8"},
{ title: "第61集", url: "https://v.cdnlz29.com/20260223/221906_09f1f122/2000k/hls/mixed.m3u8"},
{ title: "第62集", url: "https://v.cdnlz29.com/20260223/221910_abd20d12/2000k/hls/mixed.m3u8"},
{ title: "第63集", url: "https://v.cdnlz29.com/20260223/221907_8d1ec74a/2000k/hls/mixed.m3u8"},
{ title: "第64集", url: "https://v.cdnlz29.com/20260223/221908_3e876464/2000k/hls/mixed.m3u8"},
{ title: "第65集", url: "https://v.cdnlz29.com/20260223/221909_dff42ffa/2000k/hls/mixed.m3u8"},
{ title: "第66集", url: "https://v.cdnlz29.com/20260223/221911_fc7dc799/2000k/hls/mixed.m3u8"},
{ title: "第67集", url: "https://v.cdnlz29.com/20260223/221912_55bcee5e/2000k/hls/mixed.m3u8"},
{ title: "第68集", url: "https://v.cdnlz29.com/20260223/221913_f08b2151/2000k/hls/mixed.m3u8"},
{ title: "第69集", url: "https://v.cdnlz29.com/20260223/221916_29dab7bd/2000k/hls/mixed.m3u8"},
{ title: "第70集", url: "https://v.cdnlz29.com/20260223/221914_55060540/2000k/hls/mixed.m3u8"},
{ title: "第71集", url: "https://v.cdnlz29.com/20260223/221915_16d8b037/2000k/hls/mixed.m3u8"},
{ title: "第72集", url: "https://v.cdnlz29.com/20260223/221918_d2b2ae96/2000k/hls/mixed.m3u8"},
{ title: "第73集", url: "https://v.cdnlz29.com/20260223/221917_f8318fbf/2000k/hls/mixed.m3u8"},
{ title: "第74集", url: "https://v.cdnlz29.com/20260223/221919_e1a8cef7/2000k/hls/mixed.m3u8"},
{ title: "第75集", url: "https://v.cdnlz29.com/20260223/221923_17ab68d0/2000k/hls/mixed.m3u8"},
{ title: "第76集", url: "https://v.cdnlz29.com/20260223/221924_17ac6f13/2000k/hls/mixed.m3u8"},
{ title: "第77集", url: "https://v.cdnlz29.com/20260223/221922_7dac61f5/2000k/hls/mixed.m3u8"},
{ title: "第78集", url: "https://v.cdnlz29.com/20260223/221921_9cfcc9d8/2000k/hls/mixed.m3u8"},
{ title: "第79集", url: "https://v.cdnlz29.com/20260223/221920_3738e1e9/2000k/hls/mixed.m3u8"},
{ title: "第80集", url: "https://v.cdnlz29.com/20260223/221925_34e24fb1/2000k/hls/mixed.m3u8"},
{ title: "第81集", url: "https://v.cdnlz29.com/20260223/221926_adcb746f/2000k/hls/mixed.m3u8"},
{ title: "第82集", url: "https://v.cdnlz29.com/20260223/221927_2937ae5b/2000k/hls/mixed.m3u8"},
{ title: "第83集", url: "https://v.cdnlz29.com/20260223/221929_73eeffbf/2000k/hls/mixed.m3u8"},
{ title: "第84集", url: "https://v.cdnlz29.com/20260223/221930_dfe9e89a/2000k/hls/mixed.m3u8"},
{ title: "第85集", url: "https://v.cdnlz29.com/20260223/221928_a02d5fb2/2000k/hls/mixed.m3u8"},
{ title: "第86集", url: "https://v.cdnlz29.com/20260223/221931_5ab5631d/2000k/hls/mixed.m3u8"},
{ title: "第87集", url: "https://v.cdnlz29.com/20260223/221932_dc78cb79/2000k/hls/mixed.m3u8"},
{ title: "第88集", url: "https://v.cdnlz29.com/20260223/221933_4b9966f9/2000k/hls/mixed.m3u8"},
{ title: "第89集", url: "https://v.cdnlz29.com/20260223/221935_79632adc/2000k/hls/mixed.m3u8"},
{ title: "第90集", url: "https://v.cdnlz29.com/20260223/221936_54603335/2000k/hls/mixed.m3u8"},
{ title: "第91集", url: "https://v.cdnlz29.com/20260223/221934_b57a50fb/2000k/hls/mixed.m3u8"},
{ title: "第92集", url: "https://v.cdnlz29.com/20260223/221938_d7a5802d/2000k/hls/mixed.m3u8"},
{ title: "第93集", url: "https://v.cdnlz29.com/20260223/221937_c89394a6/2000k/hls/mixed.m3u8"},
{ title: "第94集", url: "https://v.cdnlz29.com/20260223/221939_b3f6b0ca/2000k/hls/mixed.m3u8"}
];
// 全局变量
let hls = null;
let currentEpisodeIndex = 0;
let isReversed = false;
let displayedData = [...videoData];
const videoElement = document.getElementById('dz-video-element');
const episodeListContainer = document.getElementById('dz-episode-list');
const loadingIndicator = document.getElementById('dz-loading-indicator');
const errorOverlay = document.getElementById('dz-error-overlay');
const titleElement = document.getElementById('dz-video-title');
const durationElement = document.getElementById('dz-duration');
/**
* 初始化播放器
*/
function initPlayer() {
renderEpisodes();
loadEpisode(0); // 默认加载第一集
// 监听视频元数据加载完成,更新时长显示
videoElement.addEventListener('loadedmetadata', () => {
durationElement.innerText = formatTime(videoElement.duration);
});
// 监听播放结束,自动下一集
videoElement.addEventListener('ended', () => {
playNext();
});
}
/**
* 渲染分集列表
*/
function renderEpisodes() {
episodeListContainer.innerHTML = '';
displayedData.forEach((item, index) => {
// 找到原始数据中的真实索引,用于点击事件
const originalIndex = videoData.indexOf(item);
const btn = document.createElement('button');
btn.className = `episode-btn px-3 py-2 text-xs font-medium rounded border border-gray-200 text-gray-700 hover:bg-blue-50 hover:border-blue-200 transition-all truncate ${originalIndex === currentEpisodeIndex ? 'active' : ''}`;
btn.innerText = item.title;
btn.onclick = () => loadEpisode(originalIndex);
episodeListContainer.appendChild(btn);
});
}
/**
* 加载指定集数
* @param {number} index - 原始数据数组中的索引
*/
function loadEpisode(index) {
if (index < 0 || index >= videoData.length) return;
currentEpisodeIndex = index;
const data = videoData;
// 更新UI状态
updateActiveButton();
titleElement.innerText = `正在播放:${data.title}`;
showLoading(true);
hideError();
// 销毁旧的 HLS 实例
if (hls) {
hls.destroy();
}
// 创建新的 HLS 实例
if (Hls.isSupported()) {
hls = new Hls({
debug: false,
enableWorker: true,
lowLatencyMode: true,
backBufferLength: 90
});
hls.loadSource(data.url);
hls.attachMedia(videoElement);
hls.on(Hls.Events.MANIFEST_PARSED, function() {
videoElement.play().catch(e => console.log("Auto-play prevented:", e));
showLoading(false);
});
hls.on(Hls.Events.ERROR, function(event, data) {
if (data.fatal) {
switch(data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log("fatal network error encountered, try to recover");
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log("fatal media error encountered, try to recover");
hls.recoverMediaError();
break;
default:
showError();
hls.destroy();
break;
}
}
});
} else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
// Safari 原生支持
videoElement.src = data.url;
videoElement.addEventListener('loadedmetadata', function() {
videoElement.play();
showLoading(false);
});
} else {
showError();
}
}
/**
* 更新按钮激活状态
*/
function updateActiveButton() {
const buttons = episodeListContainer.querySelectorAll('.episode-btn');
buttons.forEach((btn, idx) => {
// 注意:displayedData 可能是反转的,所以需要比对内容或重新映射
// 这里简单起见,我们重新渲染或者通过文本匹配,但更优解是重新渲染
// 为了性能,我们直接重新渲染整个列表是最安全的,因为列表通常不长
renderEpisodes();
});
}
/**
* 播放下一集
*/
function playNext() {
if (currentEpisodeIndex < videoData.length - 1) {
loadEpisode(currentEpisodeIndex + 1);
// 滚动到当前选中的按钮
setTimeout(() => {
const activeBtn = document.querySelector('.episode-btn.active');
if(activeBtn) activeBtn.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}, 100);
}
}
/**
* 切换排序(正序/倒序)
*/
function toggleOrder() {
isReversed = !isReversed;
const sortIcon = document.getElementById('sort-icon');
const sortText = document.getElementById('sort-text');
if (isReversed) {
displayedData = [...videoData].reverse();
sortIcon.className = "fas fa-sort-amount-up";
sortText.innerText = "正序";
} else {
displayedData = [...videoData];
sortIcon.className = "fas fa-sort-amount-down";
sortText.innerText = "倒序";
}
renderEpisodes();
}
/**
* 重试加载
*/
function retryLoad() {
loadEpisode(currentEpisodeIndex);
}
/**
* UI 辅助函数
*/
function showLoading(show) {
loadingIndicator.classList.toggle('hidden', !show);
}
function showError() {
errorOverlay.classList.remove('hidden');
showLoading(false);
}
function hideError() {
errorOverlay.classList.add('hidden');
}
function formatTime(seconds) {
if (isNaN(seconds)) return "00:00";
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
}
// 启动
document.addEventListener('DOMContentLoaded', initPlayer);
</script>
</body>
</html>
页:
[1]