Loading... CF上部署视频播放 特别提醒: 1、部署时替换6个链接地址为你的链接地址 2、默认登录密码为:*admin* 3、CF上修改登录密码命名:*ADMIN_PASSWORD* 4、链接地址中的文件为:*txt格式*,txt格式中的MP4播放书写 ``` MP4文件直链地址|MP4文件名 ``` 代码 ``` export default { async fetch(request, env, ctx) { // 设置CORS头 const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', }; // 处理预检请求 if (request.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }); } const url = new URL(request.url); // 登录逻辑 if (url.pathname === '/login' && request.method === 'POST') { const formData = await request.formData(); const password = formData.get('password'); const adminPassword = env.ADMIN_PASSWORD || 'admin123'; // 从环境变量读取密码,默认为admin123 if (password === adminPassword) { // 登录成功,设置 Cookie return new Response('', { status: 302, headers: { 'Set-Cookie': `auth=1; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`, 'Location': '/' } }); } else { return new Response(this.renderLoginPage('密码错误,请重试!'), { headers: { 'Content-Type': 'text/html;charset=utf-8', ...corsHeaders } }); } } // 退出逻辑 if (url.pathname === '/logout') { return new Response('', { status: 302, headers: { 'Set-Cookie': `auth=; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=0`, 'Location': '/' } }); } // 检查是否已登录 const cookie = request.headers.get('Cookie') || ''; if (!cookie.includes('auth=1')) { return new Response(this.renderLoginPage(), { headers: { 'Content-Type': 'text/html;charset=utf-8', ...corsHeaders } }); } // 读取七个视频列表文件 let links = []; let links1 = [], links2 = [], links3 = [], links4 = [], links5 = [], links6 = [], links7 = []; let randomLink = ''; const parseList = (text) => text.split('\n').filter(line => line.trim() !== ''); const results = await Promise.allSettled([ fetch('链接地址1').then(r => r.text()).then(parseList), fetch('链接地址2').then(r => r.text()).then(parseList), fetch('链接地址3').then(r => r.text()).then(parseList), fetch('链接地址4').then(r => r.text()).then(parseList), fetch('链接地址5').then(r => r.text()).then(parseList), fetch('链接地址6').then(r => r.text()).then(parseList), fetch('链接地址7t').then(r => r.text()).then(parseList) ]); links1 = results[0].status === 'fulfilled' ? results[0].value : []; links2 = results[1].status === 'fulfilled' ? results[1].value : []; links3 = results[2].status === 'fulfilled' ? results[2].value : []; links4 = results[3].status === 'fulfilled' ? results[3].value : []; links5 = results[4].status === 'fulfilled' ? results[4].value : []; links6 = results[5].status === 'fulfilled' ? results[5].value : []; links7 = results[6].status === 'fulfilled' ? results[6].value : []; links = [...links1, ...links2, ...links3, ...links4, ...links5, ...links6, ...links7]; if (links.length === 0) { links1 = links2 = links3 = links4 = links5 = links6 = links7 = links = ['https://sample-videos.com/zip/10/mp4/SampleVideo_1280x720_1mb.mp4|测试视频']; } randomLink = links[0].split('|')[0]; // 生成 HTML 内容 const htmlContent = ` <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>自动随机播放 MP4 视频</title> <link rel="shortcut icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2280%22>💠</text></svg>"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> <style> body { margin: 0; padding: 0; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #f0f0f0; font-family: Arial, sans-serif; flex-direction: column; } /* 按钮样式 */ #playPauseBtn, #prevBtn, #nextBtn, #togglePlaylistBtn, #randomBtn, #singleLoopBtn { background-color: black; color: white; border: none; padding: 10px 20px; margin: 5px; cursor: pointer; border-radius: 5px; transition: background-color 0.3s ease; } /* 按钮悬停效果 */ #playPauseBtn:hover, #prevBtn:hover, #nextBtn:hover, #togglePlaylistBtn:hover, #randomBtn:hover, #singleLoopBtn:hover { background-color: #333; } /* 播放模式按钮激活状态 */ #randomBtn.active, #singleLoopBtn.active { background-color: #0F52BA; } #randomBtn.active:hover, #singleLoopBtn.active:hover { background-color: #00318C; } .sites { width: 640px; background: #F2F2F2; border: 1px solid rgba(0,0,0,.01); margin: 6px auto; padding: 10px; height: 320px; display: flex; flex-direction: column; box-sizing: border-box; } .list-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; flex-shrink: 0; } .list-tab { background-color: #ddd; color: #333; border: 1px solid #ccc; padding: 8px 14px; cursor: pointer; border-radius: 6px; font-size: 14px; transition: all 0.2s ease; } .list-tab:hover { background-color: #ccc; } .list-tab.active { background-color: #0F52BA; color: #fff; border-color: #0F52BA; } .list-panel { display: none; flex: 1; min-height: 0; overflow: hidden; flex-direction: column; } .list-panel.active { display: flex; } /* 居中对齐容器 */ .video-container { display: flex; justify-content: center; align-items: center; margin: -0cm 0 0 0; } /* 标题下移 */ h2 { text-align: center; margin-bottom: 1cm; } /* 播放列表:限制高度,超出部分可上下滚动选择,132px显示5个视频列表,156px显示6个视频列表 */ .playlist { list-style-type: none; padding: 0; margin: 0; flex: 1; min-height: 0; max-height: 156px; overflow-y: auto; overflow-x: hidden; text-align: left; border: 1px solid #ccc; background-color: #fff; border-radius: 4px; } .playlist li { margin: 5px 0; cursor: pointer; color: #000000; font-size: 15px; text-decoration: underline; transition: color 0.3s ease; } .playlist li:hover { color: green; } /* 定义正在播放的样式 */ .playlist li.playing { color: red !important; font-weight: bold; } </style> </head> <body> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1cm;"> <h2 style="margin: 0;">自动随机播放 MP4 视频</h2> <a href="/logout" style="color: #666; text-decoration: none; padding: 8px 12px; border-radius: 6px; transition: all 0.2s; background-color: rgba(0,0,0,0.1);" onmouseover="this.style.backgroundColor='rgba(0,0,0,0.2)'; this.style.color='#333'" onmouseout="this.style.backgroundColor='rgba(0,0,0,0.1)'; this.style.color='#666'" title="退出登录"> <i class="fas fa-sign-out-alt"></i> 退出 </a> </div> <div class="video-container"> <video id="videoPlayer" width="640" height="360" controls> <source src="${randomLink}" type="video/mp4"> 您的浏览器不支持视频播放。 </video> </div> <!-- 新增按钮区域 --> <div style="text-align: center; margin: 4px 0;"> <button id="togglePlaylistBtn">播放列表</button> <button id="playPauseBtn">▶</button> <button id="prevBtn">❚◀</button> <button id="nextBtn">▶❚</button> <button id="randomBtn" title="随机播放">🔀</button> <button id="singleLoopBtn" title="单曲循环">🔁</button> </div> <div class="sites" id="playlistContainer" style="display: none;"> <div class="list-tabs"> <button type="button" class="list-tab" data-list-id="1">列表1</button> <button type="button" class="list-tab" data-list-id="2">列表2</button> <button type="button" class="list-tab" data-list-id="3">列表3</button> <button type="button" class="list-tab" data-list-id="4">列表4</button> <button type="button" class="list-tab" data-list-id="5">列表5</button> <button type="button" class="list-tab" data-list-id="6">列表6</button> <button type="button" class="list-tab" data-list-id="7">列表7</button> <button type="button" class="list-tab active" data-list-id="all">综合列表</button> </div> <div class="list-panel active" id="panel-all"> <ul class="playlist" id="playlist-all" data-list-id="all"> ${links.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="all" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-1"> <ul class="playlist" id="playlist-1" data-list-id="1"> ${links1.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="1" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-2"> <ul class="playlist" id="playlist-2" data-list-id="2"> ${links2.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="2" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-3"> <ul class="playlist" id="playlist-3" data-list-id="3"> ${links3.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="3" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-4"> <ul class="playlist" id="playlist-4" data-list-id="4"> ${links4.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="4" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-5"> <ul class="playlist" id="playlist-5" data-list-id="5"> ${links5.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="5" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-6"> <ul class="playlist" id="playlist-6" data-list-id="6"> ${links6.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="6" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> <div class="list-panel" id="panel-7"> <ul class="playlist" id="playlist-7" data-list-id="7"> ${links7.map((link, index) => { const [url, title] = link.split('|'); return `<li data-src="${url}" data-list-id="7" data-index="${index}">${index + 1}. ${title}</li>`; }).join('')} </ul> </div> </div> <script> const videoLinks = ${JSON.stringify(links)}; const videoLinks1 = ${JSON.stringify(links1)}; const videoLinks2 = ${JSON.stringify(links2)}; const videoLinks3 = ${JSON.stringify(links3)}; const videoLinks4 = ${JSON.stringify(links4)}; const videoLinks5 = ${JSON.stringify(links5)}; const videoLinks6 = ${JSON.stringify(links6)}; const videoLinks7 = ${JSON.stringify(links7)}; const listIdToLinks = { 'all': videoLinks, '1': videoLinks1, '2': videoLinks2, '3': videoLinks3, '4': videoLinks4, '5': videoLinks5, '6': videoLinks6, '7': videoLinks7 }; const videoPlayer = document.getElementById('videoPlayer'); const playPauseBtn = document.getElementById('playPauseBtn'); const prevBtn = document.getElementById('prevBtn'); const nextBtn = document.getElementById('nextBtn'); let currentPlaylistId = 'all'; let currentVideoIndex = 0; let playMode = 'order'; let playedIndexes = []; function getCurrentLinks() { return listIdToLinks[currentPlaylistId] || videoLinks; } document.addEventListener('DOMContentLoaded', () => { playVideo(currentVideoIndex); updatePlaylistStyle(currentPlaylistId, currentVideoIndex); updateModeButtons(); }); function updateModeButtons() { document.getElementById('randomBtn').classList.toggle('active', playMode === 'random'); document.getElementById('singleLoopBtn').classList.toggle('active', playMode === 'single'); } function updatePlaylistStyle(listId, index) { document.querySelectorAll('.playlist li').forEach(li => { li.classList.remove('playing'); if (li.getAttribute('data-list-id') === listId && parseInt(li.getAttribute('data-index'), 10) === index) { li.classList.add('playing'); } }); } function playVideo(index) { const list = getCurrentLinks(); if (!list.length) return; index = (index + list.length) % list.length; currentVideoIndex = index; const [url] = list[index].split('|'); videoPlayer.src = url; videoPlayer.play(); updatePlaylistStyle(currentPlaylistId, currentVideoIndex); } playPauseBtn.addEventListener('click', () => { if (videoPlayer.paused) { videoPlayer.play(); playPauseBtn.textContent = '⏸'; } else { videoPlayer.pause(); playPauseBtn.textContent = '▶'; } }); prevBtn.addEventListener('click', () => { const list = getCurrentLinks(); currentVideoIndex = (currentVideoIndex - 1 + list.length) % list.length; playVideo(currentVideoIndex); }); nextBtn.addEventListener('click', () => { const list = getCurrentLinks(); currentVideoIndex = (currentVideoIndex + 1) % list.length; playVideo(currentVideoIndex); }); videoPlayer.addEventListener('ended', () => { if (playMode === 'single') { videoPlayer.currentTime = 0; videoPlayer.play(); return; } const list = getCurrentLinks(); if (playMode === 'random') { const unplayed = list.map((_, i) => i).filter(i => !playedIndexes.includes(i)); if (unplayed.length === 0) { playedIndexes = []; currentVideoIndex = Math.floor(Math.random() * list.length); } else { currentVideoIndex = unplayed[Math.floor(Math.random() * unplayed.length)]; } playedIndexes.push(currentVideoIndex); } else { currentVideoIndex = (currentVideoIndex + 1) % list.length; } playVideo(currentVideoIndex); }); document.getElementById('randomBtn').addEventListener('click', () => { playMode = playMode === 'random' ? 'order' : 'random'; playedIndexes = []; updateModeButtons(); }); document.getElementById('singleLoopBtn').addEventListener('click', () => { playMode = playMode === 'single' ? 'order' : 'single'; updateModeButtons(); }); const togglePlaylistBtn = document.getElementById('togglePlaylistBtn'); const playlistContainer = document.getElementById('playlistContainer'); togglePlaylistBtn.addEventListener('click', () => { if (playlistContainer.style.display === 'none') { playlistContainer.style.display = 'block'; togglePlaylistBtn.textContent = '隐藏列表'; } else { playlistContainer.style.display = 'none'; togglePlaylistBtn.textContent = '播放列表'; } }); document.querySelectorAll('.list-tab').forEach(tab => { tab.addEventListener('click', () => { const listId = tab.getAttribute('data-list-id'); document.querySelectorAll('.list-tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.list-panel').forEach(p => p.classList.remove('active')); tab.classList.add('active'); const panel = document.getElementById('panel-' + listId); if (panel) panel.classList.add('active'); }); }); playlistContainer.addEventListener('click', function(event) { if (event.target.tagName === 'LI') { const listId = event.target.getAttribute('data-list-id'); const index = parseInt(event.target.getAttribute('data-index'), 10); const selectedUrl = event.target.getAttribute('data-src'); currentPlaylistId = listId; currentVideoIndex = index; playedIndexes = []; videoPlayer.src = selectedUrl; videoPlayer.play(); updatePlaylistStyle(currentPlaylistId, currentVideoIndex); } }); </script> </body> </html> `; return new Response(htmlContent, { headers: { 'Content-Type': 'text/html', ...corsHeaders, }, }) }, // 登录页面渲染函数 renderLoginPage(msg = '') { return `<!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="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> <link rel="shortcut icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2280%22>💠</text></svg>"> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Noto Sans SC', 'Segoe UI', Arial, sans-serif; background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); background-size: 400% 400%; animation: gradient-animation 15s ease infinite; height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; } @keyframes gradient-animation { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } .login-container { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(20px); border-radius: 20px; padding: 40px 30px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); width: 100%; max-width: 400px; text-align: center; animation: fadeInUp 0.6s ease-out; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } .logo { display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 20px; color: #333; } .logo i { font-size: 32px; color: #0F52BA; } .logo span { font-size: 24px; font-weight: bold; } .login-title { font-size: 22px; color: #333; margin-bottom: 10px; font-weight: 600; } .login-subtitle { color: #666; margin-bottom: 30px; font-size: 14px; } .error-message { background: rgba(211, 47, 47, 0.1); color: #d32f2f; padding: 12px; border-radius: 8px; margin-bottom: 20px; font-size: 14px; border: 1px solid rgba(211, 47, 47, 0.2); } .form-group { margin-bottom: 20px; text-align: left; } .form-group label { display: block; color: #333; margin-bottom: 8px; font-weight: 500; font-size: 14px; } .password-wrapper { position: relative; width: 100%; } .password-wrapper input { width: 100%; padding: 15px 50px 15px 15px; border: 2px solid #e0e0e0; border-radius: 12px; font-size: 16px; outline: none; transition: all 0.3s ease; background: rgba(255, 255, 255, 0.9); } .password-wrapper input:focus { border-color: #0F52BA; box-shadow: 0 0 0 3px rgba(15, 82, 186, 0.1); background: #fff; } .password-wrapper input::placeholder { color: #999; } .toggle-password { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); background: none; border: none; color: #666; cursor: pointer; font-size: 18px; transition: color 0.3s ease; padding: 5px; } .toggle-password:hover { color: #0F52BA; } .login-btn { width: 100%; padding: 15px; background: linear-gradient(135deg, #0F52BA, #00318C); border: none; border-radius: 12px; color: #fff; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; margin-top: 10px; } .login-btn:hover { background: linear-gradient(135deg, #00318C, #001F5C); transform: translateY(-2px); box-shadow: 0 10px 25px rgba(15, 82, 186, 0.3); } .login-btn:active { transform: translateY(0); } .login-footer { margin-top: 20px; color: #666; font-size: 12px; } .login-footer a { color: #0F52BA; text-decoration: none; } .login-footer a:hover { text-decoration: underline; } /* 响应式设计 */ @media (max-width: 480px) { .login-container { margin: 20px; padding: 30px 20px; } } </style> </head> <body> <div class="login-container"> <div class="logo"> <i class="fas fa-video"></i> <span>视频播放器</span> </div> <h1 class="login-title">🔒 请输入密码</h1> <p class="login-subtitle">访问视频播放器需要身份验证</p> ${msg ? `<div class="error-message">${msg}</div>` : ''} <form method="POST" action="/login"> <div class="form-group"> <label for="password">管理员密码</label> <div class="password-wrapper"> <input type="password" id="password" name="password" placeholder="输入登录密码" required> <button type="button" class="toggle-password" onclick="togglePassword()"> <i class="fas fa-eye"></i> </button> </div> </div> <button type="submit" class="login-btn"> <i class="fas fa-sign-in-alt"></i> 登录 </button> </form> <div class="login-footer"> <p>© 2025 视频播放器</p> </div> </div> <script> function togglePassword() { const input = document.getElementById('password'); const icon = document.querySelector('.toggle-password i'); if (input.type === 'password') { input.type = 'text'; icon.className = 'fas fa-eye-slash'; } else { input.type = 'password'; icon.className = 'fas fa-eye'; } } // 回车键登录 document.getElementById('password').addEventListener('keypress', function(e) { if (e.key === 'Enter') { document.querySelector('form').submit(); } }); // 自动聚焦到密码输入框 window.addEventListener('load', function() { document.getElementById('password').focus(); }); </script> </body> </html>`; }, }; ``` 最后修改:2026 年 02 月 10 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏